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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +19 -8
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +7 -0
  5. data/.rubocop_todo.yml +7 -3
  6. data/Dockerfile +9 -0
  7. data/README.md +5 -6
  8. data/Rakefile +2 -0
  9. data/config/yardstick.rb +13 -0
  10. data/config/yardstick.yml +35 -0
  11. data/core_ext.gemspec +9 -7
  12. data/docker-compose.yml +3 -6
  13. data/lib/darthjee/core_ext/array.rb +2 -2
  14. data/lib/darthjee/core_ext/class.rb +90 -4
  15. data/lib/darthjee/core_ext/enumerable.rb +5 -1
  16. data/lib/darthjee/core_ext/hash.rb +30 -0
  17. data/lib/darthjee/core_ext/hash/cameliazable.rb +91 -0
  18. data/lib/darthjee/core_ext/hash/chain_fetcher.rb +10 -0
  19. data/lib/darthjee/core_ext/hash/key_changeable.rb +85 -53
  20. data/lib/darthjee/core_ext/hash/key_changer.rb +41 -31
  21. data/lib/darthjee/core_ext/hash/value_changer.rb +128 -11
  22. data/lib/darthjee/core_ext/version.rb +1 -1
  23. data/spec/integration/yard/{array → darthjee/core_ext/array}/hash_builder_spec.rb +3 -3
  24. data/spec/integration/yard/{array_spec.rb → darthjee/core_ext/array_spec.rb} +0 -0
  25. data/spec/integration/yard/darthjee/core_ext/class/default_value_spec.rb +143 -0
  26. data/spec/integration/yard/{date → darthjee/core_ext/date}/days_between_spec.rb +6 -6
  27. data/spec/integration/yard/{enumerable_spec.rb → darthjee/core_ext/enumerable_spec.rb} +0 -0
  28. data/spec/integration/yard/darthjee/core_ext/hash/cameliazable_spec.rb +34 -0
  29. data/spec/integration/yard/darthjee/core_ext/hash/chain_fetcher_spec.rb +51 -0
  30. data/spec/integration/yard/darthjee/core_ext/hash/key_changeable_spec.rb +48 -0
  31. data/spec/integration/yard/{hash → darthjee/core_ext/hash}/transformable_spec.rb +7 -3
  32. data/spec/integration/yard/darthjee/core_ext/hash/value_changer_spec.rb +66 -0
  33. data/spec/integration/yard/darthjee/core_ext/hash_spec.rb +42 -0
  34. data/spec/lib/array_spec.rb +27 -17
  35. data/spec/lib/class_spec.rb +108 -7
  36. data/spec/lib/darthjee/core_ext/hash/deep_hash_constructor_spec.rb +1 -1
  37. data/spec/lib/darthjee/core_ext/hash/key_changer_spec.rb +8 -8
  38. data/spec/lib/darthjee/core_ext/hash/keys_sorter_spec.rb +1 -0
  39. data/spec/lib/darthjee/core_ext/hash/to_hash_mapper_spec.rb +1 -0
  40. data/spec/lib/darthjee/core_ext/hash/value_changer_spec.rb +246 -0
  41. data/spec/lib/date_spec.rb +5 -4
  42. data/spec/lib/hash_spec.rb +45 -32
  43. data/spec/lib/math_spec.rb +1 -0
  44. data/spec/lib/numeric_spec.rb +39 -17
  45. data/spec/lib/object_spec.rb +7 -7
  46. data/spec/lib/symbol_spec.rb +2 -2
  47. data/spec/lib/time_spec.rb +5 -4
  48. data/spec/support/models/default_reader_model.rb +8 -0
  49. data/spec/support/models/default_value_model.rb +2 -0
  50. data/spec/support/models/dummy_iterator.rb +15 -0
  51. data/spec/support/models/dummy_transformer.rb +15 -0
  52. data/spec/support/shared_examples/array/array_random.rb +2 -1
  53. data/spec/support/shared_examples/clean.rb +20 -20
  54. data/spec/support/shared_examples/date.rb +18 -13
  55. data/spec/support/shared_examples/hash/chain_fetch.rb +4 -3
  56. data/spec/support/shared_examples/hash/chain_hash_keys_changer.rb +14 -7
  57. data/spec/support/shared_examples/hash/hash_keys_changer.rb +10 -4
  58. data/spec/support/shared_examples/hash/hash_transpose.rb +1 -1
  59. data/spec/support/shared_examples/hash/keys_appender.rb +14 -4
  60. data/spec/support/shared_examples/hash/keys_camelizer.rb +7 -7
  61. data/spec/support/shared_examples/hash/keys_sorter.rb +3 -3
  62. data/spec/support/shared_examples/hash/keys_underscorer.rb +2 -2
  63. data/spec/support/shared_examples/hash/map_to_hash.rb +14 -12
  64. data/spec/support/shared_examples/hash/remap.rb +4 -4
  65. data/spec/support/shared_examples/hash/value_changer.rb +40 -33
  66. metadata +70 -20
  67. data/spec/integration/yard/class/default_value_spec.rb +0 -58
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Hash do
6
+ describe 'yard' do
7
+ describe '#chain_fetch' do
8
+ subject(:hash) do
9
+ {
10
+ a: {
11
+ b: { c: 1, d: 2 }
12
+ }
13
+ }
14
+ end
15
+
16
+ context 'when requesting keys that exist' do
17
+ it 'returns the value found' do
18
+ expect(hash.chain_fetch(:a, :b, :c)).to eq(1)
19
+ end
20
+ end
21
+
22
+ context 'when key is not found' do
23
+ context 'when no block is given' do
24
+ it do
25
+ expect { hash.chain_fetch(:a, :c, :d) }.to raise_error(KeyError)
26
+ end
27
+ end
28
+
29
+ context 'when a block is given' do
30
+ it do
31
+ expect { hash.chain_fetch(:a, :c, :d) { 10 } }.not_to raise_error
32
+ end
33
+
34
+ it 'returns the result of the block' do
35
+ result = hash.chain_fetch(:a, :c, :d) { |*args| args }
36
+ expect(result).to eq([:c, [:d]])
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -129,8 +129,8 @@ describe Array do
129
129
  end
130
130
 
131
131
  describe '#as_hash' do
132
- let(:array) { [1, 2, 3] }
133
- let(:keys) { %w[a b c] }
132
+ let(:array) { [1, 2, 3] }
133
+ let(:keys) { %w[a b c] }
134
134
  let(:expected) { { 'a' => 1, 'b' => 2, 'c' => 3 } }
135
135
 
136
136
  it 'creates a hash using the array as value and the argument as keys' do
@@ -171,11 +171,13 @@ describe Array do
171
171
 
172
172
  context 'when block returns nil' do
173
173
  let(:block) { proc {} }
174
+
174
175
  it { expect(value).to be_nil }
175
176
  end
176
177
 
177
178
  context 'when block returns false' do
178
179
  let(:block) { proc { false } }
180
+
179
181
  it { expect(value).to be_nil }
180
182
  end
181
183
 
@@ -184,14 +186,17 @@ describe Array do
184
186
 
185
187
  it { expect(value).to eq('1') }
186
188
 
187
- context 'but not for the first value' do
188
- let(:transformer) { double(:transformer) }
189
+ context 'when first value returns nothing' do
189
190
  let(:block) { proc { |v| transformer.transform(v) } }
190
191
 
191
- before do
192
- allow(transformer).to receive(:transform) do |v|
193
- v.to_s if v > 1
192
+ let(:transformer) do
193
+ DummyTransformer.new do |value|
194
+ value.to_s if value > 1
194
195
  end
196
+ end
197
+
198
+ before do
199
+ allow(transformer).to receive(:transform).and_call_original
195
200
  value
196
201
  end
197
202
 
@@ -204,10 +209,10 @@ describe Array do
204
209
  end
205
210
 
206
211
  describe '#random' do
207
- it_behaves_like 'a method that returns a random element', :random
208
-
209
212
  let(:array) { [8, 4, 2] }
210
213
 
214
+ it_behaves_like 'a method that returns a random element', :random
215
+
211
216
  it 'removes an the returned element' do
212
217
  expect do
213
218
  array.random
@@ -216,14 +221,14 @@ describe Array do
216
221
  end
217
222
 
218
223
  describe '#random!' do
219
- it_behaves_like 'a method that returns a random element', :random!
220
-
221
224
  let(:array) { [8, 4, 2] }
222
225
 
226
+ it_behaves_like 'a method that returns a random element', :random!
227
+
223
228
  it 'removes an the returned element' do
224
229
  expect do
225
230
  array.random!
226
- end.to change { array.size }.by(-1)
231
+ end.to change(array, :size).by(-1)
227
232
  end
228
233
  end
229
234
 
@@ -233,11 +238,13 @@ describe Array do
233
238
 
234
239
  context 'when block returns nil' do
235
240
  let(:block) { proc {} }
241
+
236
242
  it { expect(filtered).to be_empty }
237
243
  end
238
244
 
239
245
  context 'when block returns false' do
240
246
  let(:block) { proc { false } }
247
+
241
248
  it { expect(filtered).to be_empty }
242
249
  end
243
250
 
@@ -246,14 +253,17 @@ describe Array do
246
253
 
247
254
  it { expect(filtered).to eq(array.map(&:to_s)) }
248
255
 
249
- context 'but not for the first value' do
250
- let(:transformer) { double(:transformer) }
256
+ context 'when first value returns nothing' do
251
257
  let(:block) { proc { |v| transformer.transform(v) } }
252
258
 
253
- before do
254
- allow(transformer).to receive(:transform) do |v|
255
- v.to_s if v[:value] > 1
259
+ let(:transformer) do
260
+ DummyTransformer.new do |value|
261
+ value.to_s if value[:value] > 1
256
262
  end
263
+ end
264
+
265
+ before do
266
+ allow(transformer).to receive(:transform).and_call_original
257
267
  filtered
258
268
  end
259
269
 
@@ -4,10 +4,24 @@ require 'spec_helper'
4
4
 
5
5
  describe Class do
6
6
  describe '.default_value' do
7
- subject { DefaultValueModel.new }
7
+ subject(:model) { DefaultValueModel.new }
8
8
 
9
9
  it 'accepts default value' do
10
- expect(subject.x).to eq(10)
10
+ expect(model.x).to eq(10)
11
+ end
12
+
13
+ context 'when changing the instance of default value' do
14
+ before do
15
+ model.array[1] = 30
16
+ end
17
+
18
+ it 'changes the value for the instance' do
19
+ expect(model.array).to eq([10, 30])
20
+ end
21
+
22
+ it 'changes the value for new instances' do
23
+ expect(model.class.new.array).to eq([10, 30])
24
+ end
11
25
  end
12
26
 
13
27
  it do
@@ -16,18 +30,105 @@ describe Class do
16
30
  end
17
31
 
18
32
  describe '.default_values' do
19
- subject { DefaultValueModel.new }
33
+ subject(:model) { DefaultValueModel.new }
20
34
 
21
- it 'accepts default values' do
22
- expect(subject.y).to eq(20)
35
+ it 'accepts default values for first method' do
36
+ expect(model.y).to eq(20)
23
37
  end
24
38
 
25
- it 'accepts default values' do
26
- expect(subject.z).to eq(20)
39
+ it 'accepts default values for second method' do
40
+ expect(model.z).to eq(20)
27
41
  end
28
42
 
29
43
  it do
30
44
  expect(Object).not_to respond_to(:default_values)
31
45
  end
46
+
47
+ context 'when changing the instance of default value' do
48
+ before do
49
+ model.hash[:a] = 2
50
+ end
51
+
52
+ it 'changes the value for the instance' do
53
+ expect(model.hash).to eq(a: 2)
54
+ end
55
+
56
+ it 'changes the value for new instances' do
57
+ expect(model.class.new.hash).to eq(a: 2)
58
+ end
59
+
60
+ it 'changes the value for all methods' do
61
+ expect(model.json).to eq(a: 2)
62
+ end
63
+ end
64
+ end
65
+
66
+ describe '.default_reader' do
67
+ subject(:model) { DefaultReaderModel.new }
68
+
69
+ it 'returns the default value' do
70
+ expect(model.name).to eq('John')
71
+ end
72
+
73
+ context 'when the variable is set with a new value' do
74
+ before { model.name = 'Bob' }
75
+
76
+ it 'returns the new value' do
77
+ expect(model.name).to eq('Bob')
78
+ end
79
+ end
80
+
81
+ context 'when the variable is set to be false' do
82
+ before { model.name = false }
83
+
84
+ it do
85
+ expect(model.name).to be_falsey
86
+ end
87
+ end
88
+
89
+ context 'when the variable is set to be nil' do
90
+ before { model.name = nil }
91
+
92
+ it do
93
+ expect(model.name).to be_nil
94
+ end
95
+ end
96
+
97
+ context 'when changing the value of one instance' do
98
+ it 'does not change the value of other instances' do
99
+ expect { model.name = 'Bob' }
100
+ .not_to(change { model.class.new.name })
101
+ end
102
+ end
103
+
104
+ it do
105
+ expect(Object).not_to respond_to(:default_value)
106
+ end
107
+ end
108
+
109
+ describe '.default_readers' do
110
+ subject(:model) { DefaultReaderModel.new }
111
+
112
+ context 'when calling first method' do
113
+ it 'returns the default value' do
114
+ expect(model.cars).to eq(2)
115
+ end
116
+
117
+ context 'when the value is set with a new value' do
118
+ before { model.cars = 10 }
119
+
120
+ it 'returns the new value' do
121
+ expect(model.cars).to eq(10)
122
+ end
123
+
124
+ it 'does not affect second method' do
125
+ expect(model.houses).to eq(2)
126
+ end
127
+ end
128
+ end
129
+
130
+ it do
131
+ expect(Object).not_to respond_to(:default_readers)
132
+ end
32
133
  end
33
134
  end
@@ -3,7 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Darthjee::CoreExt::Hash::DeepHashConstructor do
6
- let(:subject) { described_class.new('.') }
6
+ let(:subject) { described_class.new('.') }
7
7
  let(:deep_hash) { subject.deep_hash(hash) }
8
8
 
9
9
  describe '.deep_hash' do
@@ -3,7 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Darthjee::CoreExt::Hash::KeyChanger do
6
- let(:subject) { described_class.new(hash) }
6
+ subject(:key_changer) { described_class.new(hash) }
7
7
 
8
8
  describe '#remap_keys!' do
9
9
  it_behaves_like 'a method that remaps the keys', :remap do
@@ -17,14 +17,14 @@ describe Darthjee::CoreExt::Hash::KeyChanger do
17
17
  let(:hash) { { keyUnderscore: 1 } }
18
18
 
19
19
  it 'underscore all the keys' do
20
- expect(subject.underscore_keys).to eq(key_underscore: 1)
20
+ expect(key_changer.underscore_keys).to eq(key_underscore: 1)
21
21
  end
22
22
 
23
23
  context 'when hash is a many level hash' do
24
24
  let(:hash) { { keyUnderscore: { anotherKey: 1 } } }
25
25
 
26
26
  it 'underscore all the keys' do
27
- result = subject.underscore_keys
27
+ result = key_changer.underscore_keys
28
28
  expect(result).to eq(key_underscore: { another_key: 1 })
29
29
  end
30
30
  end
@@ -34,14 +34,14 @@ describe Darthjee::CoreExt::Hash::KeyChanger do
34
34
 
35
35
  it 'underscore all the keys' do
36
36
  result = { key_underscore: [{ another_key: 1 }] }
37
- expect(subject.underscore_keys).to eq(result)
37
+ expect(key_changer.underscore_keys).to eq(result)
38
38
  end
39
39
  end
40
40
 
41
- context 'changes the hash' do
41
+ context 'when call changes the hash' do
42
42
  it 'underscore all the keys' do
43
43
  expect do
44
- subject.underscore_keys
44
+ key_changer.underscore_keys
45
45
  end.to(change { hash })
46
46
  end
47
47
  end
@@ -51,7 +51,7 @@ describe Darthjee::CoreExt::Hash::KeyChanger do
51
51
  let(:hash) { { keyUnderscore: { anotherKey: 1 } } }
52
52
 
53
53
  it 'underscore all the keys' do
54
- result = subject.underscore_keys(recursive: false)
54
+ result = key_changer.underscore_keys(recursive: false)
55
55
  expect(result).to eq(key_underscore: { anotherKey: 1 })
56
56
  end
57
57
  end
@@ -60,7 +60,7 @@ describe Darthjee::CoreExt::Hash::KeyChanger do
60
60
  let(:hash) { { keyUnderscore: [{ anotherKey: 1 }] } }
61
61
 
62
62
  it 'underscore all the keys' do
63
- result = subject.underscore_keys(recursive: false)
63
+ result = key_changer.underscore_keys(recursive: false)
64
64
  expect(result).to eq(key_underscore: [{ anotherKey: 1 }])
65
65
  end
66
66
  end
@@ -5,6 +5,7 @@ require 'spec_helper'
5
5
  describe Darthjee::CoreExt::Hash::KeysSorter do
6
6
  it_behaves_like 'a class with a keys sort method' do
7
7
  subject { described_class.new(hash, **options) }
8
+
8
9
  let(:result) { subject.sort }
9
10
  end
10
11
  end
@@ -5,6 +5,7 @@ require 'spec_helper'
5
5
  describe Darthjee::CoreExt::Hash::ToHashMapper do
6
6
  it_behaves_like 'a hash with map_to_hash method' do
7
7
  subject { described_class.new(hash) }
8
+
8
9
  let(:mapped) { subject.map(&mapping_block) }
9
10
  end
10
11
  end
@@ -0,0 +1,246 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Darthjee::CoreExt::Hash::ValueChanger do
6
+ subject(:changer) { described_class.new(options, &block) }
7
+
8
+ let(:block) { proc { |value| value.to_s.size } }
9
+
10
+ describe '#change' do
11
+ let(:options) { {} }
12
+
13
+ context 'when object is a Hash' do
14
+ let(:object) { { a: 22, b: 333 } }
15
+
16
+ it 'returns the hash with changed values' do
17
+ expect(changer.change(object)).to eq(a: 2, b: 3)
18
+ end
19
+ end
20
+
21
+ context 'when object is an array' do
22
+ let(:object) { [{ a: 22 }, { b: 333 }] }
23
+
24
+ it 'iterates over array' do
25
+ expect(changer.change(object)).to eq([{ a: 2 }, { b: 3 }])
26
+ end
27
+
28
+ it 'changes original array' do
29
+ expect { changer.change(object) }.to(change { object })
30
+ end
31
+
32
+ context 'when skiping recursion option' do
33
+ let(:options) { { recursive: false } }
34
+
35
+ it 'iterates over main array' do
36
+ expect(changer.change(object)).to eq([{ a: 2 }, { b: 3 }])
37
+ end
38
+ end
39
+
40
+ context 'when passing skip inner option as false' do
41
+ let(:options) { { skip_inner: false } }
42
+
43
+ it 'does not consider values as inner hashes' do
44
+ expect(changer.change(object)).to eq([{ a: 2 }, { b: 3 }])
45
+ end
46
+ end
47
+
48
+ context 'when passing skip inner false and skiping recursion option' do
49
+ let(:options) { { skip_inner: false, recursive: false } }
50
+
51
+ it 'does not consider values as inner hashes' do
52
+ expect(changer.change(object)).to eq([{ a: 2 }, { b: 3 }])
53
+ end
54
+ end
55
+ end
56
+
57
+ context 'when there is an inner hash' do
58
+ let(:object) { { a: { b: 333 } } }
59
+
60
+ it 'iterates over inner hash' do
61
+ expect(changer.change(object)).to eq(a: { b: 3 })
62
+ end
63
+
64
+ context 'when skiping recursion option' do
65
+ let(:options) { { recursive: false } }
66
+
67
+ it 'does not iterate over array' do
68
+ expect(changer.change(object)).to eq(a: { b: 333 })
69
+ end
70
+ end
71
+
72
+ context 'when passing skip inner option as false' do
73
+ let(:options) { { skip_inner: false } }
74
+
75
+ it 'apply change on inner hash' do
76
+ expect(changer.change(object)).to eq(a: 9)
77
+ end
78
+ end
79
+
80
+ context 'when passing skip inner false and skiping recursion option' do
81
+ let(:options) { { skip_inner: false, recursive: false } }
82
+
83
+ it 'applies the transformation before attempting recusrsive' do
84
+ expect(changer.change(object)).to eq(a: 9)
85
+ end
86
+ end
87
+ end
88
+
89
+ context 'when values are arrays' do
90
+ let(:object) { { a: [{ b: 333 }] } }
91
+
92
+ it 'iterates over array and inner hash' do
93
+ expect(changer.change(object)).to eq(a: [{ b: 3 }])
94
+ end
95
+
96
+ context 'when skiping recursion option' do
97
+ let(:options) { { recursive: false } }
98
+
99
+ it 'does not iterate over array' do
100
+ expect(changer.change(object)).to eq(a: [{ b: 333 }])
101
+ end
102
+ end
103
+
104
+ context 'when passing skip inner option as false' do
105
+ let(:options) { { skip_inner: false } }
106
+
107
+ it 'applies transformation over inner hash' do
108
+ expect(changer.change(object)).to eq(a: 11)
109
+ end
110
+ end
111
+
112
+ context 'when passing skip inner false and skiping recursion option' do
113
+ let(:options) { { skip_inner: false, recursive: false } }
114
+
115
+ it 'applies transformation before going recursive' do
116
+ expect(changer.change(object)).to eq(a: 11)
117
+ end
118
+ end
119
+ end
120
+
121
+ context 'when values are arrays within arrays' do
122
+ let(:object) { { a: [[100], [1000]] } }
123
+
124
+ it 'iterates over the inner arrays' do
125
+ expect(changer.change(object)).to eq(a: [[3], [4]])
126
+ end
127
+
128
+ context 'when skiping recursion option' do
129
+ let(:options) { { recursive: false } }
130
+
131
+ it 'does not iterate over array' do
132
+ expect(changer.change(object)).to eq(a: [[100], [1000]])
133
+ end
134
+ end
135
+
136
+ context 'when passing skip inner option as false' do
137
+ let(:options) { { skip_inner: false } }
138
+
139
+ it 'applies transformation over the whole array' do
140
+ expect(changer.change(object)).to eq(a: 15)
141
+ end
142
+ end
143
+
144
+ context 'when passing skip inner false and skiping recursion option' do
145
+ let(:options) { { skip_inner: false, recursive: false } }
146
+
147
+ it 'applies transformation before going recursive' do
148
+ expect(changer.change(object)).to eq(a: 15)
149
+ end
150
+ end
151
+ end
152
+
153
+ context 'when object is an array of arrays' do
154
+ let(:object) { [[{ a: 100 }], [{ b: { c: 1000 } }]] }
155
+
156
+ it 'iterates over the inner arrays' do
157
+ expect(changer.change(object)).to eq([[{ a: 3 }], [{ b: { c: 4 } }]])
158
+ end
159
+
160
+ context 'when skiping recursion option' do
161
+ let(:options) { { recursive: false } }
162
+
163
+ it 'stops recursive after the first hash' do
164
+ expected = [[{ a: 3 }], [{ b: { c: 1000 } }]]
165
+ expect(changer.change(object)).to eq(expected)
166
+ end
167
+ end
168
+
169
+ context 'when passing skip inner option as false' do
170
+ let(:options) { { skip_inner: false } }
171
+
172
+ it 'applies transformation on the first value of a hash' do
173
+ expect(changer.change(object)).to eq([[{ a: 3 }], [{ b: 10 }]])
174
+ end
175
+ end
176
+
177
+ context 'when passing skip inner false and skiping recursion option' do
178
+ let(:options) { { skip_inner: false, recursive: false } }
179
+
180
+ it 'applies transformation before going recursive' do
181
+ expect(changer.change(object)).to eq([[{ a: 3 }], [{ b: 10 }]])
182
+ end
183
+ end
184
+ end
185
+
186
+ context 'when transformation returns a hash and skip_inner is false' do
187
+ let(:object) { { a: [{ b: 333 }], c: { d: 10 }, e: [] } }
188
+ let(:options) { { skip_inner: false } }
189
+ let(:block) do
190
+ proc do |value|
191
+ value.is_a?(Array) ? { size: value.size } : value.to_s.size
192
+ end
193
+ end
194
+
195
+ it 'treat result of transformation as new hashes to be transformed' do
196
+ expected = { a: { size: 1 }, c: 8, e: { size: 1 } }
197
+ expect(changer.change(object)).to eq(expected)
198
+ end
199
+
200
+ context 'when skipping recursion' do
201
+ let(:options) { { skip_inner: false, recursive: false } }
202
+
203
+ it 'does not iterate over returned hash' do
204
+ expected = { a: { size: 1 }, c: 8, e: { size: 0 } }
205
+ expect(changer.change(object)).to eq(expected)
206
+ end
207
+ end
208
+ end
209
+
210
+ context 'when value is not an array but responds to #map' do
211
+ let(:array) { [{ b: 22 }, { c: 333 }] }
212
+ let(:object) { { a: DummyIterator.new(array) } }
213
+
214
+ it 'iterates over array' do
215
+ expected = { a: [{ b: 2 }, { c: 3 }] }
216
+ expect(changer.change(object)).to eq(expected)
217
+ end
218
+
219
+ it 'does not change original array' do
220
+ expect { changer.change(object) }.not_to(change { array })
221
+ end
222
+ end
223
+
224
+ context 'when object is not an array but responds to #map' do
225
+ let(:array) { [{ b: 22 }, { c: 333 }] }
226
+ let(:object) { DummyIterator.new(array) }
227
+
228
+ it 'iterates over array' do
229
+ expected = [{ b: 2 }, { c: 3 }]
230
+ expect(changer.change(object)).to eq(expected)
231
+ end
232
+
233
+ it 'does not change original array' do
234
+ expect { changer.change(object) }.not_to(change { array })
235
+ end
236
+ end
237
+
238
+ context 'when object is not an array or hash' do
239
+ let(:object) { Object.new }
240
+
241
+ it 'returns object' do
242
+ expect(changer.change(object)).to eq(object)
243
+ end
244
+ end
245
+ end
246
+ end