Skip to content

Commit

Permalink
Merge pull request #52458 from ogd-software/camels_and_snakes
Browse files Browse the repository at this point in the history
Camels and snakes
  • Loading branch information
twangboy committed Apr 25, 2019
2 parents f11b41f + a0961bf commit e6dcc52
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 50 deletions.
43 changes: 43 additions & 0 deletions doc/topics/jinja/index.rst
Expand Up @@ -1309,6 +1309,49 @@ Returns:
.. _`JMESPath language`: http://jmespath.org/
.. _`jmespath`: https://github.com/jmespath/jmespath.py


.. 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
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
@@ -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
Expand Up @@ -588,3 +588,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
Expand Up @@ -943,6 +943,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

0 comments on commit e6dcc52

Please sign in to comment.