From a260063ffdd9c2fc03548c572917a3796d33b97c Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Thu, 20 Jul 2017 09:57:05 +1000 Subject: [PATCH] Added function to convert camelCase to snake_case for powershell (#26203) * Added camel case to snake case converters * removed uneeded shebang * renamed util to remove PowerShell from the name --- .../Ansible.ModuleUtils.CamelConversion.psm1 | 69 +++++++++++++++++++ .../library/camel_conversion_test.ps1 | 64 +++++++++++++++++ .../targets/win_module_utils/tasks/main.yml | 8 +++ 3 files changed, 141 insertions(+) create mode 100644 lib/ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 create mode 100644 test/integration/targets/win_module_utils/library/camel_conversion_test.ps1 diff --git a/lib/ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 b/lib/ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 new file mode 100644 index 0000000000..dda7185f69 --- /dev/null +++ b/lib/ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 @@ -0,0 +1,69 @@ +# Copyright (c) 2017 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# used by Convert-DictToSnakeCase to convert a string in camelCase +# format to snake_case +Function Convert-StringToSnakeCase($string) { + # cope with pluralized abbreaviations such as TargetGroupARNs + if ($string -cmatch "[A-Z]{3,}s") { + $replacement_string = $string -creplace $matches[0], "_$($matches[0].ToLower())" + + # handle when there was nothing before the plural pattern + if ($replacement_string.StartsWith("_") -and -not $string.StartsWith("_")) { + $replacement_string = $replacement_string.Substring(1) + } + $string = $replacement_string + } + $string = $string -creplace "(.)([A-Z][a-z]+)", '$1_$2' + $string = $string -creplace "([a-z0-9])([A-Z])", '$1_$2' + $string = $string.ToLower() + + return $string +} + +# used by Convert-DictToSnakeCase to covert list entries from camelCase +# to snake_case +Function Convert-ListToSnakeCase($list) { + $snake_list = [System.Collections.ArrayList]@() + foreach ($value in $list) { + if ($value -is [Hashtable]) { + $new_value = Convert-DictToSnakeCase -dict $value + } elseif ($value -is [Array]) { + $new_value = Convert-ListToSnakeCase -list $value + } elseif ($value -is [String]) { + $new_value = Convert-StringToSnakeCase -string $value + } else { + $new_value = $value + } + $snake_list.Add($new_value) | Out-Null + } + + return $snake_list +} + +# converts a dict/hashtable keys from camelCase to snake_case +# this is to keep the return values consistent with the Ansible +# way of working. +Function Convert-DictToSnakeCase($dict) { + $snake_dict = @{} + foreach ($dict_entry in $dict.GetEnumerator()) { + $key = $dict_entry.Key + $snake_key = Convert-StringToSnakeCase -string $key + + $value = $dict_entry.Value + if ($value -is [Hashtable]) { + $snake_dict.$snake_key = Convert-DictToSnakeCase -dict $value + } elseif ($value -is [Array]) { + $snake_dict.$snake_key = Convert-ListToSnakeCase -list $value + } elseif ($value -is [String]) { + $snake_dict.$snake_key = Convert-StringToSnakeCase -string $value + } else { + $snake_dict.$snake_key = $value + } + } + + return $snake_dict +} + +# this line must stay at the bottom to ensure all defined module parts are exported +Export-ModuleMember -Alias * -Function * -Cmdlet * diff --git a/test/integration/targets/win_module_utils/library/camel_conversion_test.ps1 b/test/integration/targets/win_module_utils/library/camel_conversion_test.ps1 new file mode 100644 index 0000000000..bfefe7fd01 --- /dev/null +++ b/test/integration/targets/win_module_utils/library/camel_conversion_test.ps1 @@ -0,0 +1,64 @@ +#!powershell + +#Requires -Module Ansible.ModuleUtils.PowerShellLegacy +#Requires -Module Ansible.ModuleUtils.CamelConversion + +$ErrorActionPreference = 'Continue' + +Function Assert-Equals($actual, $expected) { + if ($actual -cne $expected) { + Fail-Json @{} "actual != expected`nActual: $actual`nExpected: $expected" + } +} + +$input_dict = @{ + alllower = 'alllower' + ALLUPPER = 'allupper' + camelCase = 'camel_case' + mixedCase_withCamel = 'mixed_case_with_camel' + TwoWords = 'two_words' + AllUpperAtEND = 'all_upper_at_end' + AllUpperButPLURALs = 'all_upper_but_plurals' + TargetGroupARNs = 'target_group_arns' + HTTPEndpoints = 'http_endpoints' + PLURALs = 'plurals' + listDict = @( + @{ entry1 = 'entry1'; entryTwo = 'entry_two' }, + 'stringTwo', + 0 + ) + INNERHashTable = @{ + ID = 'id' + IEnumerable = 'i_enumerable' + } +} + +$output_dict = Convert-DictToSnakeCase -dict $input_dict +foreach ($entry in $output_dict.GetEnumerator()) { + $key = $entry.Name + $value = $entry.Value + + if ($value -is [Hashtable]) { + Assert-Equals -actual $key -expected "inner_hash_table" + foreach ($inner_hash in $value.GetEnumerator()) { + Assert-Equals -actual $inner_hash.Name -expected $inner_hash.Value + } + } elseif ($value -is [Array]) { + # there is one array in our original dict, we know the structure + foreach ($inner_list in $value) { + if ($inner_list -is [Hashtable]) { + foreach ($inner_list_hash in $inner_list.GetEnumerator()) { + Assert-Equals -actual $inner_list_hash.Name -expected $inner_list_hash.Value + } + } elseif ($inner_list -is [String]) { + Assert-Equals -actual $inner_list -expected "string_two" + } else { + Assert-Equals -actual $inner_list -expected 0 + } + } + } else { + Assert-Equals -actual $key -expected $value + } +} + +Exit-Json @{ data = 'success' } diff --git a/test/integration/targets/win_module_utils/tasks/main.yml b/test/integration/targets/win_module_utils/tasks/main.yml index 2c9744e9d2..c3cfbc79cb 100644 --- a/test/integration/targets/win_module_utils/tasks/main.yml +++ b/test/integration/targets/win_module_utils/tasks/main.yml @@ -31,3 +31,11 @@ that: - bogus_utils | failed - bogus_utils.msg | search("Could not find") + +- name: call module with camel conversion tests + camel_conversion_test: + register: camel_conversion + +- assert: + that: + - camel_conversion.data == 'success'