transproc 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,7 +7,7 @@ describe Transproc::ClassTransformations do
7
7
  end
8
8
 
9
9
  it 'returns a new object initialized with the given arguments' do
10
- constructor_inject = t(:constructor_inject, klass)
10
+ constructor_inject = described_class.t(:constructor_inject, klass)
11
11
 
12
12
  input = ['Jane', 25]
13
13
  output = klass.new(*input)
@@ -33,7 +33,7 @@ describe Transproc::ClassTransformations do
33
33
  end
34
34
 
35
35
  it 'allocates a new object and sets instance variables from hash key/value pairs' do
36
- set_ivars = t(:set_ivars, klass)
36
+ set_ivars = described_class.t(:set_ivars, klass)
37
37
 
38
38
  input = { name: 'Jane', age: 25 }
39
39
  output = klass.new(input)
@@ -3,69 +3,69 @@ require 'spec_helper'
3
3
  describe Transproc::Coercions do
4
4
  describe '.to_string' do
5
5
  it 'turns integer into a string' do
6
- expect(t(:to_string)[1]).to eql('1')
6
+ expect(described_class.t(:to_string)[1]).to eql('1')
7
7
  end
8
8
  end
9
9
 
10
10
  describe '.to_symbol' do
11
11
  it 'turns string into a symbol' do
12
- expect(t(:to_symbol)['test']).to eql(:test)
12
+ expect(described_class.t(:to_symbol)['test']).to eql(:test)
13
13
  end
14
14
  end
15
15
 
16
16
  describe '.to_integer' do
17
17
  it 'turns string into an integer' do
18
- expect(t(:to_integer)['1']).to eql(1)
18
+ expect(described_class.t(:to_integer)['1']).to eql(1)
19
19
  end
20
20
  end
21
21
 
22
22
  describe '.to_float' do
23
23
  it 'turns string into a float' do
24
- expect(t(:to_float)['1']).to eql(1.0)
24
+ expect(described_class.t(:to_float)['1']).to eql(1.0)
25
25
  end
26
26
 
27
27
  it 'turns integer into a float' do
28
- expect(t(:to_float)[1]).to eql(1.0)
28
+ expect(described_class.t(:to_float)[1]).to eql(1.0)
29
29
  end
30
30
  end
31
31
 
32
32
  describe '.to_decimal' do
33
33
  it 'turns string into a decimal' do
34
- expect(t(:to_decimal)['1.251']).to eql(BigDecimal('1.251'))
34
+ expect(described_class.t(:to_decimal)['1.251']).to eql(BigDecimal('1.251'))
35
35
  end
36
36
 
37
37
  it 'turns float into a decimal' do
38
- expect(t(:to_decimal)[1.251]).to eql(BigDecimal('1.251'))
38
+ expect(described_class.t(:to_decimal)[1.251]).to eql(BigDecimal('1.251'))
39
39
  end
40
40
 
41
41
  it 'turns integer into a decimal' do
42
- expect(t(:to_decimal)[1]).to eql(BigDecimal('1.0'))
42
+ expect(described_class.t(:to_decimal)[1]).to eql(BigDecimal('1.0'))
43
43
  end
44
44
  end
45
45
 
46
46
  describe '.to_date' do
47
47
  it 'turns string into a date' do
48
48
  date = Date.new(1983, 11, 18)
49
- expect(t(:to_date)['18th, November 1983']).to eql(date)
49
+ expect(described_class.t(:to_date)['18th, November 1983']).to eql(date)
50
50
  end
51
51
  end
52
52
 
53
53
  describe '.to_time' do
54
54
  it 'turns string into a time object' do
55
55
  time = Time.new(2012, 1, 23, 11, 7, 7)
56
- expect(t(:to_time)['2012-01-23 11:07:07']).to eql(time)
56
+ expect(described_class.t(:to_time)['2012-01-23 11:07:07']).to eql(time)
57
57
  end
58
58
  end
59
59
 
60
60
  describe '.to_datetime' do
61
61
  it 'turns string into a date' do
62
62
  datetime = DateTime.new(2012, 1, 23, 11, 7, 7)
63
- expect(t(:to_datetime)['2012-01-23 11:07:07']).to eql(datetime)
63
+ expect(described_class.t(:to_datetime)['2012-01-23 11:07:07']).to eql(datetime)
64
64
  end
65
65
  end
66
66
 
67
67
  describe '.to_boolean' do
68
- subject(:coercer) { t(:to_boolean) }
68
+ subject(:coercer) { described_class.t(:to_boolean) }
69
69
 
70
70
  Transproc::Coercions::TRUE_VALUES.each do |value|
71
71
  it "turns #{value.inspect} to true" do
@@ -81,7 +81,7 @@ describe Transproc::Coercions do
81
81
  end
82
82
 
83
83
  describe '.to_tuples' do
84
- subject(:to_tuples) { t(:to_tuples) }
84
+ subject(:to_tuples) { described_class.t(:to_tuples) }
85
85
 
86
86
  context 'non-array' do
87
87
  let(:input) { :foo }
@@ -1,14 +1,23 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Transproc::Composer do
4
+ before do
5
+ module Foo
6
+ extend Transproc::Registry
7
+ import Transproc::ArrayTransformations
8
+ import Transproc::HashTransformations
9
+ import Transproc::Coercions
10
+ end
11
+ end
12
+
4
13
  subject(:object) do
5
14
  Class.new do
6
15
  include Transproc::Composer
7
16
 
8
17
  def fn
9
18
  compose do |fns|
10
- fns << t(:map_array, t(:symbolize_keys)) <<
11
- t(:map_array, t(:map_value, :age, t(:to_integer)))
19
+ fns << Foo[:map_array, Foo[:symbolize_keys]] <<
20
+ Foo[:map_array, Foo[:map_value, :age, Foo[:to_integer]]]
12
21
  end
13
22
  end
14
23
  end.new
@@ -17,4 +26,6 @@ describe Transproc::Composer do
17
26
  it 'allows composing functions' do
18
27
  expect(object.fn[[{ 'age' => '12' }]]).to eql([{ age: 12 }])
19
28
  end
29
+
30
+ after { Object.send :remove_const, :Foo }
20
31
  end
@@ -2,7 +2,9 @@ require 'spec_helper'
2
2
 
3
3
  describe Transproc::Conditional do
4
4
  describe '.guard' do
5
- let(:fn) { t(:guard, ->(value) { value.is_a?(::String) }, t(:to_integer)) }
5
+ let(:fn) { described_class.t(:guard, condition, operation) }
6
+ let(:condition) { ->(value) { value.is_a?(::String) } }
7
+ let(:operation) { Transproc::Coercions.t(:to_integer) }
6
8
 
7
9
  context 'when predicate returns truthy value' do
8
10
  it 'applies the transformation and returns the result' do
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ describe Transproc::FunctionNotFoundError do
4
+ it 'complains that the function not registered globally' do
5
+ expect { Transproc(:foo) }.to raise_error do |error|
6
+ expect(error).to be_kind_of described_class
7
+ expect(error.message["foo"]).not_to be_nil
8
+ expect(error.message["global"]).not_to be_nil
9
+ end
10
+ end
11
+
12
+ it 'complains that the function not registered locally' do
13
+ Foo = Module.new { extend Transproc::Registry }
14
+
15
+ expect { Foo[:foo] }.to raise_error do |error|
16
+ expect(error).to be_kind_of described_class
17
+ expect(error.message["function Foo[:foo]"]).not_to be_nil
18
+ end
19
+ end
20
+ end
@@ -1,10 +1,28 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'Transproc::Function' do
3
+ describe Transproc::Function do
4
+ let(:hashes) { Transproc::HashTransformations }
5
+
6
+ describe '#name' do
7
+ let(:block) { proc { |v| v } }
8
+
9
+ it 'returns the name of the module function' do
10
+ expect(hashes[:symbolize_keys].name).to eql :symbolize_keys
11
+ end
12
+
13
+ it 'returns the explicitly assigned name' do
14
+ expect(described_class.new(block, name: :identity).name).to eql :identity
15
+ end
16
+
17
+ it 'returns the unnamed closure' do
18
+ expect(described_class.new(block).name).to eql block
19
+ end
20
+ end
21
+
4
22
  describe '#>>' do
5
23
  it 'composes named functions' do
6
- f1 = t(:symbolize_keys)
7
- f2 = t(:rename_keys, user_name: :name)
24
+ f1 = hashes[:symbolize_keys]
25
+ f2 = hashes[:rename_keys, user_name: :name]
8
26
 
9
27
  f3 = f1 >> f2
10
28
 
@@ -19,7 +37,7 @@ describe 'Transproc::Function' do
19
37
 
20
38
  expect(f3['user_name' => 'Jane']).to eql(name: 'Jane')
21
39
 
22
- f4 = f3 >> t(:nest, :details, [:name])
40
+ f4 = f3 >> hashes[:nest, :details, [:name]]
23
41
 
24
42
  expect(f4.to_ast).to eql(
25
43
  [
@@ -54,7 +72,7 @@ describe 'Transproc::Function' do
54
72
  end
55
73
 
56
74
  it 'plays well with registered compositions' do
57
- Transproc.register(:user_names, t(:symbolize_keys) + t(:rename_keys, user_name: :name))
75
+ Transproc.register(:user_names, hashes[:symbolize_keys] + hashes[:rename_keys, user_name: :name])
58
76
  f = t(:user_names)
59
77
 
60
78
  expect(f['user_name' => 'Jane']).to eql(name: 'Jane')
@@ -70,10 +88,33 @@ describe 'Transproc::Function' do
70
88
 
71
89
  it 'plays well with registered functions' do
72
90
  Transproc.register(:to_s, t(:to_string))
73
- f = t(:to_s)
91
+ fn = t(:to_s)
92
+
93
+ expect(fn[:ok]).to eql('ok')
94
+ expect(fn.to_ast).to eql([:to_string, []])
95
+ end
96
+ end
97
+
98
+ describe '#==' do
99
+ let(:fns) do
100
+ Module.new do
101
+ extend Transproc::Registry
102
+ import :wrap, from: Transproc::ArrayTransformations
103
+ end
104
+ end
105
+
106
+ it 'returns true when the other is equal' do
107
+ left = fns[:wrap, :user, [:name, :email]]
108
+ right = fns[:wrap, :user, [:name, :email]]
109
+
110
+ expect(left == right).to be(true)
111
+ end
112
+
113
+ it 'returns false when the other is not a fn' do
114
+ left = fns[:wrap, :user, [:name, :email]]
115
+ right = 'boo!'
74
116
 
75
- expect(f[:ok]).to eql('ok')
76
- expect(f.to_ast).to eql([:to_string, []])
117
+ expect(left == right).to be(false)
77
118
  end
78
119
  end
79
120
  end
@@ -1,9 +1,10 @@
1
1
  require 'spec_helper'
2
+ require 'transproc/rspec'
2
3
 
3
4
  describe Transproc::HashTransformations do
4
5
  describe '.map_keys' do
5
6
  it 'returns a new hash with given proc applied to keys' do
6
- map_keys = t(:map_keys, ->(key) { key.strip })
7
+ map_keys = described_class.t(:map_keys, ->(key) { key.strip })
7
8
 
8
9
  input = { ' foo ' => 'bar' }
9
10
  output = { 'foo' => 'bar' }
@@ -15,7 +16,7 @@ describe Transproc::HashTransformations do
15
16
 
16
17
  describe '.map_keys!' do
17
18
  it 'returns updated hash with given proc applied to keys' do
18
- map_keys = t(:map_keys!, ->(key) { key.strip })
19
+ map_keys = described_class.t(:map_keys!, ->(key) { key.strip })
19
20
 
20
21
  input = { ' foo ' => 'bar' }
21
22
  output = { 'foo' => 'bar' }
@@ -27,7 +28,7 @@ describe Transproc::HashTransformations do
27
28
 
28
29
  describe '.symbolize_keys' do
29
30
  it 'returns a new hash with symbolized keys' do
30
- symbolize_keys = t(:symbolize_keys)
31
+ symbolize_keys = described_class.t(:symbolize_keys)
31
32
 
32
33
  input = { 'foo' => 'bar' }
33
34
  output = { foo: 'bar' }
@@ -37,9 +38,21 @@ describe Transproc::HashTransformations do
37
38
  end
38
39
  end
39
40
 
41
+ describe '.deep_symbolize_keys' do
42
+ it 'returns a new hash with symbolized keys' do
43
+ symbolize_keys = described_class.t(:deep_symbolize_keys)
44
+
45
+ input = { 'foo' => 'bar', 'baz' => [{ 'one' => 1 }, 'two'] }
46
+ output = { foo: 'bar', baz: [{ one: 1 }, 'two'] }
47
+
48
+ expect(symbolize_keys[input]).to eql(output)
49
+ expect(input).to eql({ 'foo' => 'bar', 'baz' => [{ 'one' => 1 }, 'two'] })
50
+ end
51
+ end
52
+
40
53
  describe '.symbolize_keys!' do
41
54
  it 'returns updated hash with symbolized keys' do
42
- symbolize_keys = t(:symbolize_keys!)
55
+ symbolize_keys = described_class.t(:symbolize_keys!)
43
56
 
44
57
  input = { 'foo' => 'bar' }
45
58
  output = { foo: 'bar' }
@@ -52,7 +65,7 @@ describe Transproc::HashTransformations do
52
65
 
53
66
  describe '.stringify_keys' do
54
67
  it 'returns a new hash with stringified keys' do
55
- stringify_keys = t(:stringify_keys)
68
+ stringify_keys = described_class.t(:stringify_keys)
56
69
 
57
70
  input = { foo: 'bar' }
58
71
  output = { 'foo' => 'bar' }
@@ -64,7 +77,7 @@ describe Transproc::HashTransformations do
64
77
 
65
78
  describe '.stringify_keys!' do
66
79
  it 'returns a new hash with stringified keys' do
67
- stringify_keys = t(:stringify_keys!)
80
+ stringify_keys = described_class.t(:stringify_keys!)
68
81
 
69
82
  input = { foo: 'bar' }
70
83
  output = { 'foo' => 'bar' }
@@ -76,7 +89,7 @@ describe Transproc::HashTransformations do
76
89
 
77
90
  describe '.map_values' do
78
91
  it 'returns a new hash with given proc applied to values' do
79
- map_values = t(:map_values, ->(value) { value.strip })
92
+ map_values = described_class.t(:map_values, ->(value) { value.strip })
80
93
 
81
94
  input = { 'foo' => ' bar ' }
82
95
  output = { 'foo' => 'bar' }
@@ -88,7 +101,7 @@ describe Transproc::HashTransformations do
88
101
 
89
102
  describe '.map_values!' do
90
103
  it 'returns updated hash with given proc applied to values' do
91
- map_values = t(:map_values!, ->(value) { value.strip })
104
+ map_values = described_class.t(:map_values!, ->(value) { value.strip })
92
105
 
93
106
  input = { 'foo' => ' bar ' }
94
107
  output = { 'foo' => 'bar' }
@@ -100,7 +113,7 @@ describe Transproc::HashTransformations do
100
113
 
101
114
  describe '.rename_keys' do
102
115
  it 'returns a new hash with applied functions' do
103
- map = t(:rename_keys, 'foo' => :foo)
116
+ map = described_class.t(:rename_keys, 'foo' => :foo)
104
117
 
105
118
  input = { 'foo' => 'bar', :bar => 'baz' }
106
119
  output = { foo: 'bar', bar: 'baz' }
@@ -112,7 +125,7 @@ describe Transproc::HashTransformations do
112
125
 
113
126
  describe '.rename_keys!' do
114
127
  it 'returns updated hash with applied functions' do
115
- map = t(:rename_keys!, 'foo' => :foo)
128
+ map = described_class.t(:rename_keys!, 'foo' => :foo)
116
129
 
117
130
  input = { 'foo' => 'bar', :bar => 'baz' }
118
131
  output = { foo: 'bar', bar: 'baz' }
@@ -125,7 +138,8 @@ describe Transproc::HashTransformations do
125
138
 
126
139
  describe '.map_value' do
127
140
  it 'applies function to value under specified key' do
128
- transformation = t(:map_value, :user, t(:symbolize_keys))
141
+ transformation =
142
+ described_class.t(:map_value, :user, described_class.t(:symbolize_keys))
129
143
 
130
144
  input = { user: { 'name' => 'Jane' } }
131
145
  output = { user: { name: 'Jane' } }
@@ -137,7 +151,9 @@ describe Transproc::HashTransformations do
137
151
 
138
152
  describe '.map_value!' do
139
153
  it 'applies function to value under specified key' do
140
- transformation = t(:map_value!, :user, t(:symbolize_keys))
154
+ transformation =
155
+ described_class
156
+ .t(:map_value!, :user, described_class.t(:symbolize_keys))
141
157
 
142
158
  input = { user: { 'name' => 'Jane' } }
143
159
  output = { user: { name: 'Jane' } }
@@ -150,7 +166,7 @@ describe Transproc::HashTransformations do
150
166
 
151
167
  describe '.nest' do
152
168
  it 'returns new hash with keys nested under a new key' do
153
- nest = t(:nest, :baz, ['foo'])
169
+ nest = described_class.t(:nest, :baz, ['foo'])
154
170
 
155
171
  input = { 'foo' => 'bar' }
156
172
  output = { baz: { 'foo' => 'bar' } }
@@ -162,7 +178,7 @@ describe Transproc::HashTransformations do
162
178
 
163
179
  describe '.nest!' do
164
180
  it 'returns new hash with keys nested under a new key' do
165
- nest = t(:nest!, :baz, ['one', 'two', 'not-here'])
181
+ nest = described_class.t(:nest!, :baz, ['one', 'two', 'not-here'])
166
182
 
167
183
  input = { 'foo' => 'bar', 'one' => nil, 'two' => false }
168
184
  output = { 'foo' => 'bar', baz: { 'one' => nil, 'two' => false } }
@@ -173,7 +189,7 @@ describe Transproc::HashTransformations do
173
189
  end
174
190
 
175
191
  it 'returns new hash with keys nested under the existing key' do
176
- nest = t(:nest!, :baz, ['two'])
192
+ nest = described_class.t(:nest!, :baz, ['two'])
177
193
 
178
194
  input = { 'foo' => 'bar', baz: { 'one' => nil }, 'two' => false }
179
195
  output = { 'foo' => 'bar', baz: { 'one' => nil, 'two' => false } }
@@ -184,7 +200,7 @@ describe Transproc::HashTransformations do
184
200
  end
185
201
 
186
202
  it 'rewrites the existing key if its value is not a hash' do
187
- nest = t(:nest!, :baz, ['two'])
203
+ nest = described_class.t(:nest!, :baz, ['two'])
188
204
 
189
205
  input = { 'foo' => 'bar', baz: 'one', 'two' => false }
190
206
  output = { 'foo' => 'bar', baz: { 'two' => false } }
@@ -195,7 +211,7 @@ describe Transproc::HashTransformations do
195
211
  end
196
212
 
197
213
  it 'returns new hash with an empty hash under a new key when nest-keys are missing' do
198
- nest = t(:nest!, :baz, ['foo'])
214
+ nest = described_class.t(:nest!, :baz, ['foo'])
199
215
 
200
216
  input = { 'bar' => 'foo' }
201
217
  output = { 'bar' => 'foo', baz: {} }
@@ -208,7 +224,7 @@ describe Transproc::HashTransformations do
208
224
 
209
225
  describe '.unwrap!' do
210
226
  it 'returns updated hash with nested keys lifted to the root' do
211
- unwrap = t(:unwrap!, 'wrapped', %w(one))
227
+ unwrap = described_class.t(:unwrap!, 'wrapped', %w(one))
212
228
 
213
229
  input = { 'foo' => 'bar', 'wrapped' => { 'one' => nil, 'two' => false } }
214
230
  output = { 'foo' => 'bar', 'one' => nil, 'wrapped' => { 'two' => false } }
@@ -219,7 +235,7 @@ describe Transproc::HashTransformations do
219
235
  end
220
236
 
221
237
  it 'lifts all keys if none are passed' do
222
- unwrap = t(:unwrap!, 'wrapped')
238
+ unwrap = described_class.t(:unwrap!, 'wrapped')
223
239
 
224
240
  input = { 'wrapped' => { 'one' => nil, 'two' => false } }
225
241
  output = { 'one' => nil, 'two' => false }
@@ -230,7 +246,7 @@ describe Transproc::HashTransformations do
230
246
  end
231
247
 
232
248
  it 'ignores unknown keys' do
233
- unwrap = t(:unwrap!, 'wrapped', %w(one two three))
249
+ unwrap = described_class.t(:unwrap!, 'wrapped', %w(one two three))
234
250
 
235
251
  input = { 'wrapped' => { 'one' => nil, 'two' => false } }
236
252
  output = { 'one' => nil, 'two' => false }
@@ -243,7 +259,7 @@ describe Transproc::HashTransformations do
243
259
 
244
260
  describe '.unwrap' do
245
261
  it 'returns new hash with nested keys lifted to the root' do
246
- unwrap = t(:unwrap, 'wrapped')
262
+ unwrap = described_class.t(:unwrap, 'wrapped')
247
263
 
248
264
  input = {
249
265
  'foo' => 'bar',
@@ -260,8 +276,8 @@ describe Transproc::HashTransformations do
260
276
 
261
277
  describe 'nested transform' do
262
278
  it 'applies functions to nested hashes' do
263
- symbolize_keys = t(:symbolize_keys)
264
- map_user_key = t(:map_value, :user, symbolize_keys)
279
+ symbolize_keys = described_class.t(:symbolize_keys)
280
+ map_user_key = described_class.t(:map_value, :user, symbolize_keys)
265
281
 
266
282
  transformation = symbolize_keys >> map_user_key
267
283
 
@@ -274,8 +290,8 @@ describe Transproc::HashTransformations do
274
290
 
275
291
  describe 'combining transformations' do
276
292
  it 'applies functions to the hash' do
277
- symbolize_keys = t(:symbolize_keys)
278
- map = t(:rename_keys, user_name: :name, user_email: :email)
293
+ symbolize_keys = described_class.t(:symbolize_keys)
294
+ map = described_class.t(:rename_keys, user_name: :name, user_email: :email)
279
295
 
280
296
  transformation = symbolize_keys >> map
281
297
 
@@ -290,7 +306,7 @@ describe Transproc::HashTransformations do
290
306
 
291
307
  describe '.reject_keys!' do
292
308
  it 'returns an updated hash with rejected keys' do
293
- reject_keys = t(:reject_keys, [:name, :age])
309
+ reject_keys = described_class.t(:reject_keys, [:name, :age])
294
310
 
295
311
  input = { name: 'Jane', email: 'jane@doe.org', age: 21 }
296
312
  output = { email: 'jane@doe.org' }
@@ -301,7 +317,7 @@ describe Transproc::HashTransformations do
301
317
 
302
318
  describe '.reject_keys' do
303
319
  it 'returns a new hash with rejected keys' do
304
- reject_keys = t(:reject_keys, [:name, :age])
320
+ reject_keys = described_class.t(:reject_keys, [:name, :age])
305
321
 
306
322
  input = { name: 'Jane', email: 'jane@doe.org', age: 21 }
307
323
  output = { email: 'jane@doe.org' }
@@ -313,7 +329,7 @@ describe Transproc::HashTransformations do
313
329
 
314
330
  describe '.accept_keys!' do
315
331
  it 'returns an updated hash with accepted keys' do
316
- accept_keys = t(:accept_keys, [:age])
332
+ accept_keys = described_class.t(:accept_keys, [:age])
317
333
 
318
334
  input = { name: 'Jane', email: 'jane@doe.org', age: 21 }
319
335
  output = { age: 21 }
@@ -324,7 +340,7 @@ describe Transproc::HashTransformations do
324
340
 
325
341
  describe '.reject_keys' do
326
342
  it 'returns a new hash with rejected keys' do
327
- accept_keys = t(:accept_keys, [:age])
343
+ accept_keys = described_class.t(:accept_keys, [:age])
328
344
 
329
345
  input = { name: 'Jane', email: 'jane@doe.org', age: 21 }
330
346
  output = { age: 21 }
@@ -342,22 +358,14 @@ describe Transproc::HashTransformations do
342
358
  }
343
359
  end
344
360
 
345
- it 'returns an updated hash with folded key' do
346
- fold = t(:fold, :tasks, :title)
347
-
348
- output = { name: 'Jane', tasks: ['be nice', 'sleep well'] }
349
-
350
- expect { fold[input] }.not_to change { input }
351
- expect(fold[input]).to eq output
361
+ it_behaves_like :transforming_immutable_data do
362
+ let(:arguments) { [:fold, :tasks, :title] }
363
+ let(:output) { { name: 'Jane', tasks: ['be nice', 'sleep well'] } }
352
364
  end
353
365
 
354
- it 'does not compact results' do
355
- fold = t(:fold, :tasks, :priority)
356
-
357
- output = { name: 'Jane', tasks: [1, nil] }
358
-
359
- expect { fold[input] }.not_to change { input }
360
- expect(fold[input]).to eql output
366
+ it_behaves_like :transforming_immutable_data do
367
+ let(:arguments) { [:fold, :tasks, :priority] }
368
+ let(:output) { { name: 'Jane', tasks: [1, nil] } }
361
369
  end
362
370
  end
363
371
 
@@ -369,22 +377,14 @@ describe Transproc::HashTransformations do
369
377
  }
370
378
  end
371
379
 
372
- it 'returns an updated hash with folded key' do
373
- fold = t(:fold!, :tasks, :title)
374
-
375
- output = { name: 'Jane', tasks: ['be nice', 'sleep well'] }
376
-
377
- expect(fold[input]).to eql output
378
- expect(input).to eql output
380
+ it_behaves_like :mutating_input_data do
381
+ let(:arguments) { [:fold!, :tasks, :title] }
382
+ let(:output) { { name: 'Jane', tasks: ['be nice', 'sleep well'] } }
379
383
  end
380
384
 
381
- it 'does not compact results' do
382
- fold = t(:fold!, :tasks, :priority)
383
-
384
- output = { name: 'Jane', tasks: [1, nil] }
385
-
386
- expect(fold[input]).to eql output
387
- expect(input).to eql output
385
+ it_behaves_like :mutating_input_data do
386
+ let(:arguments) { [:fold!, :tasks, :priority] }
387
+ let(:output) { { name: 'Jane', tasks: [1, nil] } }
388
388
  end
389
389
  end
390
390
 
@@ -403,7 +403,7 @@ describe Transproc::HashTransformations do
403
403
  end
404
404
 
405
405
  it 'splits a tuple into array partially by given keys' do
406
- split = t(:split, :tasks, [:priority])
406
+ split = described_class.t(:split, :tasks, [:priority])
407
407
 
408
408
  output = [
409
409
  {
@@ -424,7 +424,7 @@ describe Transproc::HashTransformations do
424
424
  end
425
425
 
426
426
  it 'splits a tuple into array fully by all subkeys' do
427
- split = t(:split, :tasks, [:priority, :title])
427
+ split = described_class.t(:split, :tasks, [:priority, :title])
428
428
 
429
429
  output = [
430
430
  { name: 'Joe', title: 'sleep well', priority: 1 },
@@ -451,24 +451,62 @@ describe Transproc::HashTransformations do
451
451
  }
452
452
  ]
453
453
 
454
- split = t(:split, :tasks, [])
454
+ split = described_class.t(:split, :tasks, [])
455
455
  expect(split[input]).to eql output
456
456
 
457
- split = t(:split, :tasks, [:absent])
457
+ split = described_class.t(:split, :tasks, [:absent])
458
458
  expect(split[input]).to eql output
459
459
  end
460
460
 
461
461
  it 'returns an array of initial tuple when attribute is absent' do
462
- split = t(:split, :absent, [:priority, :title])
462
+ split = described_class.t(:split, :absent, [:priority, :title])
463
463
  expect(split[input]).to eql [input]
464
464
  end
465
465
 
466
466
  it 'ignores empty array' do
467
467
  input = { name: 'Joe', tasks: [] }
468
468
 
469
- split = t(:split, :tasks, [:title])
469
+ split = described_class.t(:split, :tasks, [:title])
470
470
 
471
471
  expect(split[input]).to eql [{ name: 'Joe' }]
472
472
  end
473
473
  end
474
+
475
+ describe ':eval_values' do
476
+ it 'recursively evaluates values' do
477
+ evaluate = described_class.t(:eval_values, 1)
478
+
479
+ input = {
480
+ one: 1, two: -> i { i+1 },
481
+ three: -> i { i+2 }, four: 4,
482
+ more: [{ one: -> i { i }, two: 2 }]
483
+ }
484
+
485
+ output = {
486
+ one: 1, two: 2,
487
+ three: 3, four: 4,
488
+ more: [{ one: 1, two: 2 }]
489
+ }
490
+
491
+ expect(evaluate[input]).to eql(output)
492
+ end
493
+
494
+ it 'recursively evaluates values matching key names' do
495
+ evaluate = described_class.t(:eval_values, 1, [:one, :two])
496
+
497
+ input = {
498
+ one: 1, two: -> i { i+1 },
499
+ three: -> i { i+2 }, four: 4,
500
+ array: [{ one: -> i { i }, two: 2 }],
501
+ hash: { one: -> i { i } }
502
+ }
503
+
504
+ result = evaluate[input]
505
+
506
+ expect(result[:three]).to be_a(Proc)
507
+ expect(result).to include(two: 2)
508
+ expect(result[:array]).to eql([{ one: 1, two: 2 }])
509
+ expect(result[:hash]).to eql(one: 1)
510
+ end
511
+ end
474
512
  end