Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[master] Porting #52458 to master #54623

Merged
merged 5 commits into from
Dec 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions doc/topics/jinja/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1346,6 +1346,49 @@ Returns:
.. _`builtin filters`: http://jinja.pocoo.org/docs/templates/#builtin-filters
.. _`timelib`: https://github.com/pediapress/timelib/


.. jinja_ref:: to_snake_case

``to_snake_case``
-----------------

.. versionadded:: Neon

Converts a string from camelCase (or CamelCase) to snake_case.

.. code-block:: jinja

Example: {{ camelsWillLoveThis | to_snake_case }}

Returns:

.. code-block:: text

Example: camels_will_love_this


.. jinja_ref:: to_camelcase

``to_camelcase``
----------------

.. versionadded:: Neon

Converts a string from snake_case to camelCase (or UpperCamelCase if so indicated).

.. code-block:: jinja

Example 1: {{ snake_case_for_the_win | to_camelcase }}

Example 2: {{ snake_case_for_the_win | to_camelcase(uppercamel=True) }}

Returns:

.. code-block:: text

Example 1: snakeCaseForTheWin
Example 2: SnakeCaseForTheWin

Networking Filters
------------------

Expand Down
37 changes: 4 additions & 33 deletions salt/modules/testinframod.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import re
import types

from salt.utils.stringutils import camel_to_snake_case, snake_to_camel_case

log = logging.getLogger(__name__)

try:
Expand Down Expand Up @@ -51,38 +53,7 @@ def _get_module(module_name, backend=default_backend):

"""
backend_instance = testinfra.get_backend(backend)
return backend_instance.get_module(_to_pascal_case(module_name))


def _to_pascal_case(snake_case):
"""Convert a snake_case string to its PascalCase equivalent.

:param snake_case: snake_cased string to be converted
:returns: PascalCase string
:rtype: str

"""
space_case = re.sub('_', ' ', snake_case)
wordlist = []
for word in space_case.split():
wordlist.append(word[0].upper())
wordlist.append(word[1:])
return ''.join(wordlist)


def _to_snake_case(pascal_case):
"""Convert a PascalCase string to its snake_case equivalent.

:param pascal_case: PascalCased string to be converted
:returns: snake_case string
:rtype: str

"""
snake_case = re.sub('(^|[a-z])([A-Z])',
lambda match: '{0}_{1}'.format(match.group(1).lower(),
match.group(2).lower()),
pascal_case)
return snake_case.lower().strip('_')
return backend_instance.get_module(snake_to_camel_case(module_name, uppercamel=True))


def _get_method_result(module_, module_instance, method_name, method_arg=None):
Expand Down Expand Up @@ -297,7 +268,7 @@ def _register_functions():
can be called via salt.
"""
try:
modules_ = [_to_snake_case(module_) for module_ in modules.__all__]
modules_ = [camel_to_snake_case(module_) for module_ in modules.__all__]
except AttributeError:
modules_ = [module_ for module_ in modules.modules]

Expand Down
20 changes: 3 additions & 17 deletions salt/states/testinframod.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals, print_function

import re
import logging

from salt.utils.stringutils import camel_to_snake_case

log = logging.getLogger(__name__)

try:
Expand Down Expand Up @@ -36,24 +37,9 @@ def _module_function_wrapper(name, **methods):
return _module_function_wrapper


def _to_snake_case(pascal_case):
"""Convert a PascalCase string to its snake_case equivalent.

:param pascal_case: PascalCased string to be converted
:returns: snake_case string
:rtype: str

"""
snake_case = re.sub('(^|[a-z])([A-Z])',
lambda match: '{0}_{1}'.format(match.group(1).lower(),
match.group(2).lower()),
pascal_case)
return snake_case.lower().strip('_')


def _generate_functions():
try:
modules_ = [_to_snake_case(module_) for module_ in modules.__all__]
modules_ = [camel_to_snake_case(module_) for module_ in modules.__all__]
except AttributeError:
modules_ = [module_ for module_ in modules.modules]

Expand Down
36 changes: 36 additions & 0 deletions salt/utils/stringutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,3 +569,39 @@ def get_diff(a, b, *args, **kwargs):
*args, **kwargs
)
)


@jinja_filter('to_snake_case')
def camel_to_snake_case(camel_input):
'''
Converts camelCase (or CamelCase) to snake_case.
From https://codereview.stackexchange.com/questions/185966/functions-to-convert-camelcase-strings-to-snake-case

:param str camel_input: The camelcase or CamelCase string to convert to snake_case

:return str
'''
res = camel_input[0].lower()
for i, letter in enumerate(camel_input[1:], 1):
if letter.isupper():
if camel_input[i-1].islower() or (i != len(camel_input)-1 and camel_input[i+1].islower()):
res += '_'
res += letter.lower()
return res


@jinja_filter('to_camelcase')
def snake_to_camel_case(snake_input, uppercamel=False):
'''
Converts snake_case to camelCase (or CamelCase if uppercamel is ``True``).
Inspired by https://codereview.stackexchange.com/questions/85311/transform-snake-case-to-camelcase

:param str snake_input: The input snake_case string to convert to camelCase
:param bool uppercamel: Whether or not to convert to CamelCase instead

:return str
'''
words = snake_input.split('_')
if uppercamel:
words[0] = words[0].capitalize()
return words[0] + ''.join(word.capitalize() for word in words[1:])
20 changes: 20 additions & 0 deletions tests/unit/utils/test_jinja.py
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,26 @@ def test_sequence(self):
.render(data={'foo': 'bar'})
self.assertEqual(rendered, '1')

def test_camel_to_snake_case(self):
'''
Test the `to_snake_case` Jinja filter.
'''
rendered = render_jinja_tmpl('{{ \'abcdEfghhIjkLmnoP\' | to_snake_case }}',
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
self.assertEqual(rendered, 'abcd_efghh_ijk_lmno_p')

def test_snake_to_camel_case(self):
'''
Test the `to_camelcase` Jinja filter.
'''
rendered = render_jinja_tmpl('{{ \'the_fox_jumped_over_the_lazy_dog\' | to_camelcase }}',
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
self.assertEqual(rendered, 'theFoxJumpedOverTheLazyDog')

rendered = render_jinja_tmpl('{{ \'the_fox_jumped_over_the_lazy_dog\' | to_camelcase(uppercamel=True) }}',
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt))
self.assertEqual(rendered, 'TheFoxJumpedOverTheLazyDog')

def test_is_ip(self):
'''
Test the `is_ip` Jinja filter.
Expand Down