darthjee-core_ext 1.7.3 → 1.7.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +19 -8
- data/.gitignore +1 -0
- data/.rubocop.yml +7 -0
- data/.rubocop_todo.yml +7 -3
- data/Dockerfile +9 -0
- data/README.md +5 -6
- data/Rakefile +2 -0
- data/config/yardstick.rb +13 -0
- data/config/yardstick.yml +35 -0
- data/core_ext.gemspec +9 -7
- data/docker-compose.yml +3 -6
- data/lib/darthjee/core_ext/array.rb +2 -2
- data/lib/darthjee/core_ext/class.rb +90 -4
- data/lib/darthjee/core_ext/enumerable.rb +5 -1
- data/lib/darthjee/core_ext/hash.rb +30 -0
- data/lib/darthjee/core_ext/hash/cameliazable.rb +91 -0
- data/lib/darthjee/core_ext/hash/chain_fetcher.rb +10 -0
- data/lib/darthjee/core_ext/hash/key_changeable.rb +85 -53
- data/lib/darthjee/core_ext/hash/key_changer.rb +41 -31
- data/lib/darthjee/core_ext/hash/value_changer.rb +128 -11
- data/lib/darthjee/core_ext/version.rb +1 -1
- data/spec/integration/yard/{array → darthjee/core_ext/array}/hash_builder_spec.rb +3 -3
- data/spec/integration/yard/{array_spec.rb → darthjee/core_ext/array_spec.rb} +0 -0
- data/spec/integration/yard/darthjee/core_ext/class/default_value_spec.rb +143 -0
- data/spec/integration/yard/{date → darthjee/core_ext/date}/days_between_spec.rb +6 -6
- data/spec/integration/yard/{enumerable_spec.rb → darthjee/core_ext/enumerable_spec.rb} +0 -0
- data/spec/integration/yard/darthjee/core_ext/hash/cameliazable_spec.rb +34 -0
- data/spec/integration/yard/darthjee/core_ext/hash/chain_fetcher_spec.rb +51 -0
- data/spec/integration/yard/darthjee/core_ext/hash/key_changeable_spec.rb +48 -0
- data/spec/integration/yard/{hash → darthjee/core_ext/hash}/transformable_spec.rb +7 -3
- data/spec/integration/yard/darthjee/core_ext/hash/value_changer_spec.rb +66 -0
- data/spec/integration/yard/darthjee/core_ext/hash_spec.rb +42 -0
- data/spec/lib/array_spec.rb +27 -17
- data/spec/lib/class_spec.rb +108 -7
- data/spec/lib/darthjee/core_ext/hash/deep_hash_constructor_spec.rb +1 -1
- data/spec/lib/darthjee/core_ext/hash/key_changer_spec.rb +8 -8
- data/spec/lib/darthjee/core_ext/hash/keys_sorter_spec.rb +1 -0
- data/spec/lib/darthjee/core_ext/hash/to_hash_mapper_spec.rb +1 -0
- data/spec/lib/darthjee/core_ext/hash/value_changer_spec.rb +246 -0
- data/spec/lib/date_spec.rb +5 -4
- data/spec/lib/hash_spec.rb +45 -32
- data/spec/lib/math_spec.rb +1 -0
- data/spec/lib/numeric_spec.rb +39 -17
- data/spec/lib/object_spec.rb +7 -7
- data/spec/lib/symbol_spec.rb +2 -2
- data/spec/lib/time_spec.rb +5 -4
- data/spec/support/models/default_reader_model.rb +8 -0
- data/spec/support/models/default_value_model.rb +2 -0
- data/spec/support/models/dummy_iterator.rb +15 -0
- data/spec/support/models/dummy_transformer.rb +15 -0
- data/spec/support/shared_examples/array/array_random.rb +2 -1
- data/spec/support/shared_examples/clean.rb +20 -20
- data/spec/support/shared_examples/date.rb +18 -13
- data/spec/support/shared_examples/hash/chain_fetch.rb +4 -3
- data/spec/support/shared_examples/hash/chain_hash_keys_changer.rb +14 -7
- data/spec/support/shared_examples/hash/hash_keys_changer.rb +10 -4
- data/spec/support/shared_examples/hash/hash_transpose.rb +1 -1
- data/spec/support/shared_examples/hash/keys_appender.rb +14 -4
- data/spec/support/shared_examples/hash/keys_camelizer.rb +7 -7
- data/spec/support/shared_examples/hash/keys_sorter.rb +3 -3
- data/spec/support/shared_examples/hash/keys_underscorer.rb +2 -2
- data/spec/support/shared_examples/hash/map_to_hash.rb +14 -12
- data/spec/support/shared_examples/hash/remap.rb +4 -4
- data/spec/support/shared_examples/hash/value_changer.rb +40 -33
- metadata +70 -20
- data/spec/integration/yard/class/default_value_spec.rb +0 -58
@@ -3,6 +3,11 @@
|
|
3
3
|
module Darthjee
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
|
+
# Class responsible for running ::Hash#chain_fetch
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
#
|
10
|
+
# @see Darthjee::CoreExt::Hash#chain_fetch
|
6
11
|
class ChainFetcher
|
7
12
|
def initialize(hash, *keys, &block)
|
8
13
|
@hash = hash
|
@@ -10,6 +15,11 @@ module Darthjee
|
|
10
15
|
@block = block
|
11
16
|
end
|
12
17
|
|
18
|
+
# Crawls through the hash fetching the keys in chain
|
19
|
+
#
|
20
|
+
# @example (see Darthjee::CoreExt::Hash#chain_fetch)
|
21
|
+
#
|
22
|
+
# @return [Object] value fetched from array
|
13
23
|
def fetch
|
14
24
|
block.present? ? fetch_with_block : fetch_without_block
|
15
25
|
end
|
@@ -3,73 +3,85 @@
|
|
3
3
|
module Darthjee
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
|
+
# Module holding methods responsible for
|
7
|
+
# changing / transforming keys of a Hash
|
8
|
+
#
|
9
|
+
# @api public
|
6
10
|
module KeyChangeable
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
camelize_keys!(options)
|
23
|
-
end
|
24
|
-
|
25
|
-
def camelize_keys(options = {})
|
26
|
-
dup.camelize_keys!(options)
|
27
|
-
end
|
28
|
-
|
29
|
-
def camelize_keys!(options = {})
|
30
|
-
Hash::KeyChanger.new(self).camelize_keys(options)
|
11
|
+
# Change all keys by publically sending methods to the keys without
|
12
|
+
# changing the original hash
|
13
|
+
#
|
14
|
+
# @return [::Hash] New hash with the resulting keys
|
15
|
+
# @param [::Array<Symbol>] calls methods to be called form the key`
|
16
|
+
#
|
17
|
+
# @see #change_keys
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# hash = { first: 1, second: 2 }
|
21
|
+
# resut = hash.chain_change_keys(:to_s, :size, :to_s, :to_sym)
|
22
|
+
# result # returns { :'5' => 1, :'6' => 2 }
|
23
|
+
def chain_change_keys(*calls)
|
24
|
+
deep_dup.chain_change_keys!(*calls)
|
31
25
|
end
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
# Change all keys by publically sending methods to the keys
|
28
|
+
# changing the original hash
|
29
|
+
#
|
30
|
+
# @return [::Hash] New hash with the resulting keys
|
31
|
+
# @param [::Array<Symbol>] calls methods to be called form the key`
|
32
|
+
#
|
33
|
+
# @see #chain_change_keys
|
34
|
+
#
|
35
|
+
# @example (see #chain_change_keys)
|
36
|
+
def chain_change_keys!(*calls)
|
37
|
+
options = calls.extract_options!
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
calls.inject(self) do |h, m|
|
40
|
+
h.change_keys!(options, &m)
|
41
|
+
end
|
39
42
|
end
|
40
43
|
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
+
# Change all keys returning the new hash
|
45
|
+
#
|
46
|
+
# @return new Hash with modified keys
|
47
|
+
# @param [::Hash] options options to passed to KeyChanger
|
48
|
+
# @option options [Boolean] recursive: flag defining the
|
49
|
+
# change to happen also
|
50
|
+
# on inner hashes (defaults to: true)
|
51
|
+
#
|
52
|
+
# @see Hash::KeyChanger#change_keys
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# hash = { '1' => 1, '2' => { '3' => 2} }
|
56
|
+
#
|
57
|
+
# result = hash.change_keys do |k|
|
58
|
+
# (k.to_i + 1).to_s.to_sym
|
59
|
+
# end
|
60
|
+
# result # returns { :'2' => 1, :'3' => { :'4' => 2 } }
|
61
|
+
#
|
62
|
+
# result = hash.change_keys(recursive:false) do |k|
|
63
|
+
# (k.to_i + 1).to_s.to_sym
|
64
|
+
# end
|
65
|
+
# result # returns { :'2' => 1, :'3' => { '3' => 2 } }
|
44
66
|
def change_keys(options = {}, &block)
|
45
67
|
deep_dup.change_keys!(options, &block)
|
46
68
|
end
|
47
69
|
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
70
|
+
# Change all keys modifying and returning the hash
|
71
|
+
#
|
72
|
+
# @return self
|
73
|
+
# @param [::Hash] options options to passed to KeyChanger
|
74
|
+
# @option options [Boolean] recursive: flag defining the
|
75
|
+
# change to happen also
|
76
|
+
# on inner hashes (defaults to: true)
|
77
|
+
#
|
78
|
+
# @see Hash::KeyChanger#change_keys
|
79
|
+
#
|
80
|
+
# @example (see #change_keys)
|
51
81
|
def change_keys!(options = {}, &block)
|
52
82
|
Hash::KeyChanger.new(self).change_keys(options, &block)
|
53
83
|
end
|
54
84
|
|
55
|
-
# change all publicaly sending method calls
|
56
|
-
# options: { recursive: true }
|
57
|
-
# ex: { a: 1 }.chain_change_keys(:to_s, :upcase) == { "A" =>1 }
|
58
|
-
def chain_change_keys(*calls)
|
59
|
-
deep_dup.chain_change_keys!(*calls)
|
60
|
-
end
|
61
|
-
|
62
|
-
# change all publicaly sending method calls
|
63
|
-
# options: { recursive: true }
|
64
|
-
# ex: { a: 1 }.chain_change_keys(:to_s, :upcase) == { "A" =>1 }
|
65
|
-
def chain_change_keys!(*calls)
|
66
|
-
options = calls.extract_options!
|
67
|
-
|
68
|
-
calls.inject(self) do |h, m|
|
69
|
-
h.change_keys!(options, &m)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
85
|
# prepend a string to all keys
|
74
86
|
# options {
|
75
87
|
# recursive: true,
|
@@ -125,6 +137,26 @@ module Darthjee
|
|
125
137
|
Hash::ValueChanger.new(options, &block).change(self)
|
126
138
|
end
|
127
139
|
|
140
|
+
# Changes the key of the hash without changing it
|
141
|
+
#
|
142
|
+
# @return [::Hash] new hash
|
143
|
+
#
|
144
|
+
# @example
|
145
|
+
# hash = { a: 1, b: 2 }
|
146
|
+
# hash.remap_keys(a: :b, b: :c) # returns { b: 1, c: 2 }
|
147
|
+
def remap_keys(remap)
|
148
|
+
dup.remap_keys!(remap)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Changes the key of the hash changing the original
|
152
|
+
#
|
153
|
+
# @return [::Hash] self
|
154
|
+
#
|
155
|
+
# @example (see #remap_keys)
|
156
|
+
def remap_keys!(keys_map)
|
157
|
+
KeyChanger.new(self).remap(keys_map)
|
158
|
+
end
|
159
|
+
|
128
160
|
private
|
129
161
|
|
130
162
|
# changes the text of the keys
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module Darthjee
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
|
+
# @api private
|
6
7
|
class KeyChanger
|
7
8
|
def initialize(hash)
|
8
9
|
@hash = hash
|
@@ -16,10 +17,20 @@ module Darthjee
|
|
16
17
|
hash.merge! new_hash
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
# Change the keys of the given hash returning the new hash
|
21
|
+
#
|
22
|
+
# @return New hash after keys tranformation
|
23
|
+
#
|
24
|
+
# @param [::Hash] options options for transformation
|
25
|
+
# @option options [Boolean] recursive: flag defining
|
26
|
+
# the change to happen also
|
27
|
+
# on inner hashes (defaults to: true)
|
28
|
+
#
|
29
|
+
# @example (see Hash#change_keys)
|
30
|
+
def change_keys(options = {}, &block)
|
31
|
+
options = {
|
32
|
+
recursive: true
|
33
|
+
}.merge!(options)
|
23
34
|
|
24
35
|
if options[:recursive]
|
25
36
|
hash.deep_transform_keys!(&block)
|
@@ -28,31 +39,37 @@ module Darthjee
|
|
28
39
|
end
|
29
40
|
end
|
30
41
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
42
|
+
# Performs camelization of the keys of the hash
|
43
|
+
#
|
44
|
+
# @return [::Hash] the given hash with it's keys changed
|
45
|
+
# @param [::Hash] options options
|
46
|
+
# @option options [::Boolean] uppercase_first_letter: flag
|
47
|
+
# defining the type of CamelCase
|
48
|
+
#
|
49
|
+
# @example (see Hash#camelize_keys)
|
50
|
+
def camelize_keys(options = {})
|
51
|
+
options = {
|
52
|
+
uppercase_first_letter: true
|
53
|
+
}.merge!(options)
|
35
54
|
|
36
55
|
type = options[:uppercase_first_letter] ? :upper : :lower
|
37
56
|
|
38
|
-
change_keys do |k|
|
57
|
+
change_keys(options) do |k|
|
39
58
|
k.camelize(type)
|
40
59
|
end
|
41
60
|
end
|
42
61
|
|
43
|
-
def underscore_keys(
|
44
|
-
|
45
|
-
|
46
|
-
change_keys(&:underscore)
|
62
|
+
def underscore_keys(options = {})
|
63
|
+
change_keys(options, &:underscore)
|
47
64
|
end
|
48
65
|
|
49
66
|
def change_text(options = {})
|
50
|
-
|
51
|
-
|
52
|
-
|
67
|
+
options = {
|
68
|
+
type: :keep
|
69
|
+
}.merge!(options)
|
53
70
|
|
54
|
-
change_keys do |key|
|
55
|
-
cast_new_key yield(key), key.class
|
71
|
+
change_keys(options) do |key|
|
72
|
+
cast_new_key yield(key), key.class, options
|
56
73
|
end
|
57
74
|
end
|
58
75
|
|
@@ -60,16 +77,8 @@ module Darthjee
|
|
60
77
|
|
61
78
|
attr_reader :hash
|
62
79
|
|
63
|
-
def
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
def options
|
68
|
-
@options ||= {}
|
69
|
-
end
|
70
|
-
|
71
|
-
def cast_new_key(key, old_clazz)
|
72
|
-
case class_cast(old_clazz)
|
80
|
+
def cast_new_key(key, old_clazz, options)
|
81
|
+
case class_cast(old_clazz, options)
|
73
82
|
when :symbol then
|
74
83
|
key.to_sym
|
75
84
|
when :string then
|
@@ -77,12 +86,13 @@ module Darthjee
|
|
77
86
|
end
|
78
87
|
end
|
79
88
|
|
80
|
-
def keep_class?
|
89
|
+
def keep_class?(options)
|
81
90
|
options[:type] == :keep
|
82
91
|
end
|
83
92
|
|
84
|
-
def class_cast(old_clazz)
|
85
|
-
keep_class? && old_clazz.to_s.downcase.to_sym
|
93
|
+
def class_cast(old_clazz, options)
|
94
|
+
klass = keep_class?(options) && old_clazz.to_s.downcase.to_sym
|
95
|
+
klass || options[:type]
|
86
96
|
end
|
87
97
|
end
|
88
98
|
end
|
@@ -3,37 +3,136 @@
|
|
3
3
|
module Darthjee
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
|
+
# Class responsible for changing values on a hash
|
7
|
+
#
|
8
|
+
# @attribute [Boolean] recursive
|
9
|
+
# flag telling to apply transformation recursively
|
10
|
+
# @attribute [Boolean] skip_inner
|
11
|
+
# flag telling to not apply change block call to inner hashes
|
12
|
+
# @attribute [::Proc] block
|
13
|
+
# block to be called when changing the values
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# (see initialize)
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# (see #change)
|
6
20
|
class ValueChanger
|
7
|
-
attr_accessor :
|
21
|
+
attr_accessor :recursive, :skip_inner, :block
|
8
22
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
23
|
+
# @param [Boolean] recursive
|
24
|
+
# flag telling to apply transformation recursively
|
25
|
+
# @param [Boolean] skip_inner
|
26
|
+
# flag telling to not apply change block call to inner hashes
|
27
|
+
# @param [::Proc] block
|
28
|
+
# block to be called when changing the values
|
29
|
+
#
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# changer = Darthjee::CoreExt::Hash::ValueChanger.new(
|
33
|
+
# recursive: false,
|
34
|
+
# skip_inner: false,
|
35
|
+
# &:class
|
36
|
+
# )
|
37
|
+
#
|
38
|
+
# hash = { a: 1, b: { c: 2 }, d: [{ e: 1 }] }
|
39
|
+
# changer.change(hash) # {
|
40
|
+
# # a: Integer,
|
41
|
+
# # b: Hash,
|
42
|
+
# # d: Array
|
43
|
+
# # }
|
44
|
+
def initialize(recursive: true, skip_inner: true, &block)
|
45
|
+
@recursive = recursive
|
46
|
+
@skip_inner = skip_inner
|
14
47
|
|
15
48
|
@block = block
|
16
49
|
end
|
17
50
|
|
51
|
+
# Change the given object
|
52
|
+
#
|
53
|
+
# @return the resulting object (hash or array)
|
54
|
+
# with it`s values changed
|
55
|
+
# @param [::Hash/::Array] object
|
56
|
+
# object to have it's values changed
|
57
|
+
#
|
58
|
+
# @example
|
59
|
+
# changer = Darthjee::CoreExt::Hash::ValueChanger.new do |value|
|
60
|
+
# value.to_s.size
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# hash = { a: 15, b: { c: 2 }, d: [{ e: 100 }] }
|
64
|
+
# changer.change(hash) # {
|
65
|
+
# # a: 2,
|
66
|
+
# # b: { c: 1 },
|
67
|
+
# # d: [{ e: 3 }]
|
68
|
+
# # }
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# changer = Darthjee::CoreExt::Hash::ValueChanger.new(
|
72
|
+
# skip_inner: true
|
73
|
+
# ) do |value|
|
74
|
+
# value.to_s.size
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# hash = { a: 15, b: { c: 2 }, d: [{ e: 100 }] }
|
78
|
+
# changer.change(hash) # {
|
79
|
+
# # a: 2,
|
80
|
+
# # b: 11,
|
81
|
+
# # d: 7
|
82
|
+
# # }
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
# changer = Darthjee::CoreExt::Hash::ValueChanger.new(
|
86
|
+
# recursive: true
|
87
|
+
# ) do |value|
|
88
|
+
# value.to_s.size
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# hash = { a: 15, b: { c: 2 }, d: [{ e: 100 }] }
|
92
|
+
# changer.change(hash) # {
|
93
|
+
# # a: 2,
|
94
|
+
# # b: { c: 1 },
|
95
|
+
# # d: [{ e: 3 }]
|
96
|
+
# # }
|
97
|
+
#
|
98
|
+
# @example
|
99
|
+
# changer = Darthjee::CoreExt::Hash::ValueChanger.new do |value|
|
100
|
+
# value.to_s.size
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# array = [15, { c: 2 }, [{ e: 100 }]]
|
104
|
+
#
|
105
|
+
# changer.change(array) # [
|
106
|
+
# # 2,
|
107
|
+
# # { c: 1 },
|
108
|
+
# # [{ e: 3 }]
|
109
|
+
# # ]
|
18
110
|
def change(object)
|
19
111
|
if object.respond_to?(:change_values)
|
20
112
|
change_hash(object)
|
21
113
|
elsif iterable?(object)
|
22
114
|
change_array(object)
|
115
|
+
else
|
116
|
+
object
|
23
117
|
end
|
24
118
|
end
|
25
119
|
|
26
120
|
private
|
27
121
|
|
122
|
+
# Apply change logic to hash object
|
123
|
+
#
|
124
|
+
# @private
|
28
125
|
def change_hash(original_hash)
|
29
126
|
original_hash.tap do |hash|
|
30
127
|
original_hash.each do |key, value|
|
31
|
-
|
32
|
-
hash[key] = value
|
128
|
+
hash[key] = new_value(value)
|
33
129
|
end
|
34
130
|
end
|
35
131
|
end
|
36
132
|
|
133
|
+
# Apply change logic to iterator
|
134
|
+
#
|
135
|
+
# @private
|
37
136
|
def change_array(array)
|
38
137
|
method = %w[map! map].find { |m| array.respond_to? m }
|
39
138
|
|
@@ -48,8 +147,16 @@ module Darthjee
|
|
48
147
|
end
|
49
148
|
end
|
50
149
|
|
150
|
+
# check wehether block should be called over
|
151
|
+
# value or not
|
152
|
+
#
|
153
|
+
# when the block is not iterable (not Array or Hash)
|
154
|
+
# or when skip_inner option is set to be false,
|
155
|
+
# then block should be called
|
156
|
+
#
|
157
|
+
# @private
|
51
158
|
def change_value?(value)
|
52
|
-
!iterable?(value) || !
|
159
|
+
!iterable?(value) || !skip_inner
|
53
160
|
end
|
54
161
|
|
55
162
|
def iterable?(value)
|
@@ -58,11 +165,21 @@ module Darthjee
|
|
58
165
|
|
59
166
|
def new_value(value)
|
60
167
|
value = block.call(value) if change_value?(value)
|
61
|
-
|
168
|
+
|
169
|
+
return value unless apply_recursion?(value)
|
170
|
+
|
171
|
+
change(value)
|
62
172
|
end
|
63
173
|
|
64
174
|
def apply_recursion?(value)
|
65
|
-
iterable?(value) &&
|
175
|
+
iterable?(value) && recursive
|
176
|
+
end
|
177
|
+
|
178
|
+
def options
|
179
|
+
@options ||= {
|
180
|
+
recursive: recursive,
|
181
|
+
skip_inner: skip_inner
|
182
|
+
}
|
66
183
|
end
|
67
184
|
end
|
68
185
|
end
|