darthjee-core_ext 1.7.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +7 -1
- data/.gitignore +2 -0
- data/.reek.yml +3 -0
- data/ARRAY_README.md +72 -15
- data/CLASS_README.md +154 -0
- data/DATE_README.md +19 -9
- data/Dockerfile +2 -5
- data/ENUMERABLE_README.md +154 -4
- data/HASH_README.md +276 -135
- data/MATH_README.md +14 -10
- data/OBJECT_README.md +18 -35
- data/README.md +8 -4
- data/Rakefile +1 -0
- data/SYMBOL_README.md +13 -18
- data/config/rubycritc.rb +12 -0
- data/config/yardstick.yml +45 -3
- data/core_ext.gemspec +10 -8
- data/docker-compose.yml +15 -7
- data/lib/darthjee/core_ext/array.rb +17 -12
- data/lib/darthjee/core_ext/array/hash_builder.rb +20 -4
- data/lib/darthjee/core_ext/class.rb +28 -10
- data/lib/darthjee/core_ext/date.rb +1 -0
- data/lib/darthjee/core_ext/enumerable.rb +67 -30
- data/lib/darthjee/core_ext/hash.rb +4 -2
- data/lib/darthjee/core_ext/hash/cameliazable.rb +39 -8
- data/lib/darthjee/core_ext/hash/chain_fetcher.rb +17 -1
- data/lib/darthjee/core_ext/hash/changeable.rb +88 -0
- data/lib/darthjee/core_ext/hash/deep_hash_constructor.rb +127 -63
- data/lib/darthjee/core_ext/hash/deep_hash_constructor/setter.rb +112 -0
- data/lib/darthjee/core_ext/hash/key_changeable.rb +126 -54
- data/lib/darthjee/core_ext/hash/key_changer.rb +140 -40
- data/lib/darthjee/core_ext/hash/keys_sorter.rb +42 -6
- data/lib/darthjee/core_ext/hash/squasher.rb +131 -18
- data/lib/darthjee/core_ext/hash/transformable.rb +133 -41
- data/lib/darthjee/core_ext/hash/transposeable.rb +37 -8
- data/lib/darthjee/core_ext/hash/value_changer.rb +76 -36
- data/lib/darthjee/core_ext/math.rb +37 -6
- data/lib/darthjee/core_ext/numeric.rb +10 -0
- data/lib/darthjee/core_ext/object.rb +29 -0
- data/lib/darthjee/core_ext/symbol.rb +22 -2
- data/lib/darthjee/core_ext/version.rb +1 -1
- data/scripts/check_readme.sh +6 -0
- data/scripts/rubycritic.sh +10 -0
- data/spec/integration/readme/array_spec.rb +96 -0
- data/spec/integration/readme/class_spec.rb +123 -0
- data/spec/integration/readme/date_spec.rb +20 -0
- data/spec/integration/readme/enumerable_spec.rb +87 -0
- data/spec/integration/readme/hash_spec.rb +391 -0
- data/spec/integration/readme/math_spec.rb +31 -0
- data/spec/integration/readme/object_spec.rb +49 -0
- data/spec/integration/readme/symbol_spec.rb +29 -0
- data/spec/integration/yard/darthjee/core_ext/enumerable_spec.rb +24 -4
- data/spec/integration/yard/darthjee/core_ext/hash/cameliazable_spec.rb +11 -0
- data/spec/integration/yard/darthjee/core_ext/hash/changeable_spec.rb +68 -0
- data/spec/integration/yard/darthjee/core_ext/hash/deep_hash_constructor/setter_spec.rb +34 -0
- data/spec/integration/yard/darthjee/core_ext/hash/deep_hash_constructor_spec.rb +65 -0
- data/spec/integration/yard/darthjee/core_ext/hash/key_changeable_spec.rb +8 -0
- data/spec/integration/yard/darthjee/core_ext/hash/key_changer_spec.rb +59 -0
- data/spec/integration/yard/darthjee/core_ext/hash/keys_sorter_spec.rb +25 -0
- data/spec/integration/yard/darthjee/core_ext/hash/squasher_spec.rb +60 -0
- data/spec/integration/yard/darthjee/core_ext/hash/transformable_spec.rb +66 -36
- data/spec/integration/yard/darthjee/core_ext/hash/transposeable_spec.rb +35 -0
- data/spec/integration/yard/darthjee/core_ext/hash_spec.rb +13 -2
- data/spec/integration/yard/darthjee/core_ext/math_spec.rb +28 -0
- data/spec/integration/yard/darthjee/core_ext/numeric_spec.rb +11 -0
- data/spec/integration/yard/darthjee/core_ext/object_spec.rb +47 -0
- data/spec/integration/yard/darthjee/core_ext/symbol_spec.rb +17 -0
- data/spec/lib/darthjee/core_ext/hash/deep_hash_constructor/setter_spec.rb +64 -0
- data/spec/lib/darthjee/core_ext/hash/deep_hash_constructor_spec.rb +16 -156
- data/spec/lib/darthjee/core_ext/hash/keys_sorter_spec.rb +5 -4
- data/spec/lib/darthjee/core_ext/hash/squasher_spec.rb +8 -2
- data/spec/lib/darthjee/core_ext/hash/value_changer_spec.rb +4 -12
- data/spec/lib/hash_spec.rb +92 -146
- data/spec/lib/object_spec.rb +32 -0
- data/spec/support/models/client.rb +22 -0
- data/spec/support/shared_examples/hash/deep_hash.rb +166 -0
- data/spec/support/shared_examples/hash/hash_squasher.rb +54 -9
- data/spec/support/shared_examples/hash/keys_sorter.rb +266 -6
- metadata +70 -8
- data/lib/darthjee/core_ext/hash/to_hash_mapper.rb +0 -25
- data/spec/lib/darthjee/core_ext/hash/to_hash_mapper_spec.rb +0 -11
@@ -4,11 +4,34 @@ module Darthjee
|
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
6
|
# @api private
|
7
|
+
#
|
8
|
+
# @author Darthjee
|
7
9
|
class KeyChanger
|
8
10
|
def initialize(hash)
|
9
11
|
@hash = hash
|
10
12
|
end
|
11
13
|
|
14
|
+
# Changes keys based on map
|
15
|
+
#
|
16
|
+
# @param keys_map [::Hash] map of
|
17
|
+
# original => final key
|
18
|
+
#
|
19
|
+
# @return [::Hash] the given hash modified
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# hash = { a: 1, 'b' => 2 }
|
23
|
+
# changer = Darthjee::CoreExt::Hash::KeyChanger.new(hash)
|
24
|
+
# remap_map = { a: 1, 'b' => 2 }
|
25
|
+
#
|
26
|
+
# changer.remap(remap_map)
|
27
|
+
#
|
28
|
+
# hash # changed to {
|
29
|
+
# # za: 1,
|
30
|
+
# # 'yb' => 2,
|
31
|
+
# # zb: nil
|
32
|
+
# # }
|
33
|
+
#
|
34
|
+
# @example (see Hash::KeyChangeable#remap_keys)
|
12
35
|
def remap(keys_map)
|
13
36
|
new_hash = {}
|
14
37
|
keys_map.each do |o, n|
|
@@ -19,20 +42,27 @@ module Darthjee
|
|
19
42
|
|
20
43
|
# Change the keys of the given hash returning the new hash
|
21
44
|
#
|
22
|
-
# @
|
45
|
+
# @param [::TrueClass,::FalseClass]
|
46
|
+
# recursive flag defining
|
47
|
+
# the change to happen also on inner hashes
|
23
48
|
#
|
24
|
-
# @
|
25
|
-
# @option options [Boolean] recursive: flag defining
|
26
|
-
# the change to happen also
|
27
|
-
# on inner hashes (defaults to: true)
|
49
|
+
# @return [::Hash] Given hash after keys tranformation
|
28
50
|
#
|
29
|
-
# @example (see Hash#change_keys)
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
51
|
+
# @example (see Hash::KeyChangeable#change_keys)
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# hash = { a: 1, 'b' => { c: 3 } }
|
55
|
+
# changer = Darthjee::CoreExt::Hash::KeyChanger.new(hash)
|
56
|
+
# changer.change_keys { |k| "key_#{k}" }
|
57
|
+
#
|
58
|
+
# hash # changed to {
|
59
|
+
# # 'key_a' => 1,
|
60
|
+
# # 'key_b' => {
|
61
|
+
# # 'key_c' => 3
|
62
|
+
# # }
|
63
|
+
# # }
|
64
|
+
def change_keys(recursive: true, &block)
|
65
|
+
if recursive
|
36
66
|
hash.deep_transform_keys!(&block)
|
37
67
|
else
|
38
68
|
hash.transform_keys!(&block)
|
@@ -41,35 +71,81 @@ module Darthjee
|
|
41
71
|
|
42
72
|
# Performs camelization of the keys of the hash
|
43
73
|
#
|
44
|
-
# @
|
45
|
-
# @param [::
|
46
|
-
#
|
74
|
+
# @param [::Hash] options
|
75
|
+
# @param [::TrueClass,::FalseClass]
|
76
|
+
# uppercase_first_letter flag
|
47
77
|
# defining the type of CamelCase
|
78
|
+
# @option options [::TrueClass,::FalseClass]
|
79
|
+
# recursive (true) flag defining
|
80
|
+
# the change to happen also on inner hashes
|
48
81
|
#
|
49
|
-
# @
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
82
|
+
# @return [::Hash] the given hash with it's keys
|
83
|
+
# changed
|
84
|
+
#
|
85
|
+
# @see #change_keys
|
86
|
+
# @see Cameliazable#camelize_keys
|
87
|
+
#
|
88
|
+
# @example (see Cameliazable#camelize_keys)
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# hash = { my_key: { inner_key: 10 } }
|
92
|
+
# changer = Darthjee::CoreExt::Hash::KeyChanger.new(hash)
|
93
|
+
# changer.camelize_keys
|
94
|
+
# hash # changed to { MyKey: { InnerKey: 10 } }
|
95
|
+
def camelize_keys(uppercase_first_letter: true, **options)
|
96
|
+
type = uppercase_first_letter ? :upper : :lower
|
56
97
|
|
57
|
-
change_keys(options) do |
|
58
|
-
|
98
|
+
change_keys(options) do |key|
|
99
|
+
key.camelize(type)
|
59
100
|
end
|
60
101
|
end
|
61
102
|
|
103
|
+
# Changes keys by performing underscore transformation
|
104
|
+
#
|
105
|
+
# @param [::hash] options
|
106
|
+
# @option options [::TrueClass,::FalseClass]
|
107
|
+
# recursive (true) flag defining
|
108
|
+
# the change to happen also on inner hashes
|
109
|
+
#
|
110
|
+
# @return [::Hash]
|
111
|
+
#
|
112
|
+
# @example (see Cameliazable#underscore_keys)
|
113
|
+
#
|
114
|
+
# @example
|
115
|
+
# hash = { myKey: { InnerKey: 10 } }
|
116
|
+
# changer = Darthjee::CoreExt::Hash::KeyChanger.new(hash)
|
117
|
+
# changer.underscore_keys
|
118
|
+
#
|
119
|
+
# hash # changed to { my_key: { inner_key: 10 } }
|
62
120
|
def underscore_keys(options = {})
|
63
121
|
change_keys(options, &:underscore)
|
64
122
|
end
|
65
123
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
124
|
+
# Change keys considering them to be strings
|
125
|
+
#
|
126
|
+
# @param options [::Hash]
|
127
|
+
# @param type [::Symbol] type that key will be case
|
128
|
+
# - keep: Cast the key back to the same type it was
|
129
|
+
# - string cast the key to {String}
|
130
|
+
# - symbol cast the key to {Symbol}
|
131
|
+
#
|
132
|
+
# @option options [::TrueClass,::FalseClass]
|
133
|
+
# recursive (true) flag defining
|
134
|
+
# the change to happen also on inner hashes
|
135
|
+
#
|
136
|
+
# @yield (key) key transformation block
|
137
|
+
#
|
138
|
+
# @return [::Hash] the given hash with changed keys
|
139
|
+
#
|
140
|
+
# @example
|
141
|
+
# hash = { key: { inner_key: 10 } }
|
142
|
+
# changer = Darthjee::CoreExt::Hash::KeyChanger.new(hash)
|
143
|
+
# changer.change_text { |key| key.to_s.upcase }
|
144
|
+
#
|
145
|
+
# hash # changed to { KEY: { INNER_KEY: 10 } }
|
146
|
+
def change_text(type: :keep, **options)
|
147
|
+
change_keys(**options) do |key|
|
148
|
+
cast_new_key yield(key), key.class, type
|
73
149
|
end
|
74
150
|
end
|
75
151
|
|
@@ -77,8 +153,22 @@ module Darthjee
|
|
77
153
|
|
78
154
|
attr_reader :hash
|
79
155
|
|
80
|
-
|
81
|
-
|
156
|
+
# @api private
|
157
|
+
# @private
|
158
|
+
#
|
159
|
+
# Cast key to correct type (String or Symbol)
|
160
|
+
#
|
161
|
+
# @param key [::String] key to be cast
|
162
|
+
# (after transformation)
|
163
|
+
# @param old_clazz [::Class] original class of the key
|
164
|
+
# @param type [::Symbol] option of type
|
165
|
+
# - keep: Cast the key back to the same type it was
|
166
|
+
# - string cast the key to {String}
|
167
|
+
# - symbol cast the key to {Symbol}
|
168
|
+
#
|
169
|
+
# @return [::String,::Symbol]
|
170
|
+
def cast_new_key(key, old_clazz, type)
|
171
|
+
case class_cast(old_clazz, type)
|
82
172
|
when :symbol then
|
83
173
|
key.to_sym
|
84
174
|
when :string then
|
@@ -86,13 +176,23 @@ module Darthjee
|
|
86
176
|
end
|
87
177
|
end
|
88
178
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
179
|
+
# @api private
|
180
|
+
# @private
|
181
|
+
#
|
182
|
+
# Returns the type of the cast to be applied
|
183
|
+
#
|
184
|
+
# @param old_clazz [::Class] original class of a key
|
185
|
+
# @param type [:symbol] option of castying
|
186
|
+
# - keep: Cast the key back to the same type it was
|
187
|
+
# - string cast the key to {String}
|
188
|
+
# - symbol cast the key to {Symbol}
|
189
|
+
#
|
190
|
+
# @see #cast_new_key
|
191
|
+
#
|
192
|
+
# @return [::Symbol]
|
193
|
+
def class_cast(old_clazz, type)
|
194
|
+
return type unless type == :keep
|
195
|
+
old_clazz.to_s.downcase.to_sym
|
96
196
|
end
|
97
197
|
end
|
98
198
|
end
|
@@ -3,32 +3,68 @@
|
|
3
3
|
module Darthjee
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
|
+
# @api private
|
7
|
+
#
|
8
|
+
# @author Darthjee
|
9
|
+
#
|
10
|
+
# Class responsible for sorting keys of a Hash
|
6
11
|
class KeysSorter
|
12
|
+
# @param hash [::hash] hash to be sorted
|
13
|
+
# @param recursive [::TrueClass,::FalseClass]
|
14
|
+
# flag indicating to perform transformation
|
15
|
+
# recursively
|
7
16
|
def initialize(hash, recursive: true)
|
8
17
|
@hash = hash
|
9
18
|
@recursive = recursive
|
10
19
|
end
|
11
20
|
|
21
|
+
# Creates a new Hash sorting it's keys
|
22
|
+
#
|
23
|
+
# @return [::Hash] new hash
|
24
|
+
#
|
25
|
+
# @example (see KeyChangeable#sort_keys)
|
26
|
+
#
|
27
|
+
# @example Simple Usage
|
28
|
+
# hash = { key: 10, a_key: { z: 5, a: 10 } }
|
29
|
+
# sorter = Darthjee::CoreExt::Hash::KeysSorter.new(hash)
|
30
|
+
#
|
31
|
+
# sorter.sort # changes hash to {
|
32
|
+
# # a_key: { a: 10, z: 5 },
|
33
|
+
# # key: 10
|
34
|
+
# # }
|
12
35
|
def sort
|
13
|
-
|
36
|
+
hash.tap do
|
14
37
|
sorted_keys.each do |key|
|
15
|
-
|
38
|
+
hash[key] = change_value(hash.delete(key))
|
16
39
|
end
|
17
40
|
end
|
18
41
|
end
|
19
42
|
|
20
43
|
private
|
21
44
|
|
45
|
+
attr_reader :hash, :recursive
|
46
|
+
|
47
|
+
# @api private
|
48
|
+
# @private
|
49
|
+
#
|
50
|
+
# Returns all keys sorted
|
51
|
+
#
|
52
|
+
# @return [::Array<::Object>]
|
22
53
|
def sorted_keys
|
23
54
|
hash.keys.sort
|
24
55
|
end
|
25
56
|
|
57
|
+
# @api private
|
58
|
+
# @private
|
59
|
+
#
|
60
|
+
# Applies recursion when needed
|
61
|
+
#
|
62
|
+
# @return [::Object]
|
26
63
|
def change_value(value)
|
27
|
-
return value unless
|
28
|
-
value.
|
64
|
+
return value unless recursive
|
65
|
+
return value unless value.is_a?(Hash)
|
66
|
+
self.class.new(value).sort
|
29
67
|
end
|
30
|
-
|
31
|
-
attr_reader :hash, :recursive
|
32
68
|
end
|
33
69
|
end
|
34
70
|
end
|
@@ -3,30 +3,143 @@
|
|
3
3
|
module Darthjee
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
# @api private
|
7
|
+
#
|
8
|
+
# @author Darthjee
|
9
|
+
#
|
10
|
+
# class responsible for squashing a hash
|
11
|
+
#
|
12
|
+
# @see Transformable#squash
|
13
|
+
# @see Transformable#to_deep_hash
|
14
|
+
#
|
15
|
+
# @example (see Transformable#squash)
|
16
|
+
# @example (see #squash)
|
17
|
+
class Squasher
|
18
|
+
attr_reader :joiner
|
9
19
|
|
10
|
-
|
11
|
-
|
12
|
-
|
20
|
+
# @param joiner [::String] string used to join keys
|
21
|
+
def initialize(joiner = '.')
|
22
|
+
@joiner = joiner
|
23
|
+
end
|
24
|
+
|
25
|
+
# Squash a hash creating a new hash
|
26
|
+
#
|
27
|
+
# Squash the hash so that it becomes a single level
|
28
|
+
# hash merging the keys of outter and inner hashes
|
29
|
+
#
|
30
|
+
# @param hash [::Hash] hash to be squashed
|
31
|
+
#
|
32
|
+
# @return [::Hash]
|
33
|
+
#
|
34
|
+
# @example Simple usage
|
35
|
+
# hash = {
|
36
|
+
# person: [{
|
37
|
+
# name: %w[John Wick],
|
38
|
+
# age: 22
|
39
|
+
# }, {
|
40
|
+
# name: %w[John Constantine],
|
41
|
+
# age: 25
|
42
|
+
# }]
|
43
|
+
# }
|
44
|
+
#
|
45
|
+
# squasher = Darthjee::CoreExt::Hash::Squasher.new
|
46
|
+
#
|
47
|
+
# squasher.squash(hash) # changes hash to {
|
48
|
+
# # 'person[0].name[0]' => 'John',
|
49
|
+
# # 'person[0].name[1]' => 'Wick',
|
50
|
+
# # 'person[0].age' => 22,
|
51
|
+
# # 'person[1].name[0]' => 'John',
|
52
|
+
# # 'person[1].name[1]' => 'Constantine',
|
53
|
+
# # 'person[1].age' => 25
|
54
|
+
# # }
|
55
|
+
#
|
56
|
+
# @example Custom joiner
|
57
|
+
# hash = {
|
58
|
+
# person: {
|
59
|
+
# name: 'John',
|
60
|
+
# age: 22
|
61
|
+
# }
|
62
|
+
# }
|
63
|
+
#
|
64
|
+
# squasher = Darthjee::CoreExt::Hash::Squasher.new('> ')
|
65
|
+
#
|
66
|
+
# squasher.squash(hash) # changes hash to {
|
67
|
+
# # 'person> name' => 'John',
|
68
|
+
# # 'person> age' => 22
|
69
|
+
# # }
|
70
|
+
def squash(hash)
|
71
|
+
hash.keys.each do |key|
|
72
|
+
next unless hash[key].is_any?(Hash, Array)
|
73
|
+
|
74
|
+
value = hash.delete(key)
|
75
|
+
add_value_to_hash(hash, key, value)
|
76
|
+
end
|
77
|
+
hash
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# @private
|
83
|
+
#
|
84
|
+
# Perform squashing on array
|
85
|
+
#
|
86
|
+
# @param key [::String] key to be prepended on
|
87
|
+
# hash keys
|
88
|
+
# @param array [::Array] array to be squashed
|
89
|
+
#
|
90
|
+
# @return [::Hash] hash with indexed keys
|
91
|
+
def squash_array(key, array)
|
92
|
+
array.map.with_index.inject({}) do |hash, (element, index)|
|
93
|
+
new_key = "#{key}[#{index}]"
|
94
|
+
add_value_to_hash(hash, new_key, element)
|
13
95
|
end
|
96
|
+
end
|
14
97
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
98
|
+
# @private
|
99
|
+
#
|
100
|
+
# Add positioned values to a hash
|
101
|
+
#
|
102
|
+
# @param hash [::Hash] hash to receive the values
|
103
|
+
# @param key [::String] String to be prepended
|
104
|
+
#
|
105
|
+
# @overload add_value_to_hash(hash, key, sub_hash)
|
106
|
+
# @param sub_hash [::Hash] subhash to be squashed
|
107
|
+
# key prepended and merged into hash
|
108
|
+
#
|
109
|
+
# @overload add_value_to_hash(hash, key, array)
|
110
|
+
# @param array [::Array] array to be squashed into
|
111
|
+
# {::Hash} and merged into hash
|
112
|
+
#
|
113
|
+
# @overload add_value_to_hash(hash, key, object)
|
114
|
+
# @param object [::Object] object to be treated
|
115
|
+
# as value
|
116
|
+
#
|
117
|
+
# @return [::Hash]
|
118
|
+
def add_value_to_hash(hash, key, element)
|
119
|
+
case element
|
120
|
+
when Hash
|
121
|
+
value = squash(element)
|
122
|
+
hash.merge! prepend_to_keys(key, value)
|
123
|
+
when Array
|
124
|
+
hash.merge! squash_array(key, element)
|
125
|
+
else
|
126
|
+
hash.merge!(key => element)
|
24
127
|
end
|
25
128
|
end
|
26
129
|
|
27
|
-
|
28
|
-
|
29
|
-
|
130
|
+
# @private
|
131
|
+
#
|
132
|
+
# Appends prefix to all keys of a hash
|
133
|
+
#
|
134
|
+
# @param prefix [::String] prefix to be prepended
|
135
|
+
# @param hash [::Hash] original hash to me changed
|
136
|
+
# (already squashed)
|
137
|
+
#
|
138
|
+
# @return [::Hash] new hash already squashed
|
139
|
+
def prepend_to_keys(prefix, hash)
|
140
|
+
hash.inject({}) do |subhash, (key, value)|
|
141
|
+
new_key = [prefix, key].join(joiner)
|
142
|
+
subhash.merge!(new_key => value)
|
30
143
|
end
|
31
144
|
end
|
32
145
|
end
|