darthjee-core_ext 1.7.3 → 1.7.4

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.
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