transproc 0.4.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -108,21 +108,19 @@ describe Transproc::Recursion do
108
108
  end
109
109
 
110
110
  describe '.hash_recursion' do
111
- let(:original) do
111
+ let(:input) do
112
112
  {
113
113
  'foo' => 'bar',
114
114
  'bar' => {
115
115
  'foo' => 'bar',
116
116
  'bar' => {
117
117
  'foo' => 'bar'
118
- }
119
- },
118
+ }.freeze
119
+ }.freeze,
120
120
  'baz' => 'bar'
121
- }
121
+ }.freeze
122
122
  end
123
123
 
124
- let(:input) { original.dup }
125
-
126
124
  let(:output) do
127
125
  {
128
126
  foo: 'bar',
@@ -136,26 +134,12 @@ describe Transproc::Recursion do
136
134
  }
137
135
  end
138
136
 
139
- context 'when function is non-destructive' do
140
- let(:map) do
141
- described_class.t(:hash_recursion, hashes.t(:symbolize_keys))
142
- end
143
-
144
- it 'applies funtions to all values recursively' do
145
- expect(map[input]).to eql(output)
146
- expect(input).to eql(original)
147
- end
137
+ let(:map) do
138
+ described_class.t(:hash_recursion, hashes.t(:symbolize_keys))
148
139
  end
149
140
 
150
- context 'when function is destructive' do
151
- let(:map) do
152
- described_class.t(:hash_recursion, hashes.t(:symbolize_keys!))
153
- end
154
-
155
- it 'applies funtions to all values recursively and destructively' do
156
- expect(map[input]).to eql(output)
157
- expect(input).to eql(output)
158
- end
141
+ it 'applies funtions to all values recursively' do
142
+ expect(map[input]).to eql(output)
159
143
  end
160
144
  end
161
145
  end
@@ -44,6 +44,86 @@ describe Transproc::Registry do
44
44
  end
45
45
  end
46
46
 
47
+ describe '.contain?' do
48
+ context 'with absent function' do
49
+ it { expect(foo.contain?(:something)).to be false }
50
+ end
51
+
52
+ context 'with class method' do
53
+ it { expect(foo.contain?(:prefix)).to be true }
54
+ end
55
+
56
+ context 'with imported methods' do
57
+ before { bar.import foo }
58
+
59
+ it { expect(bar.contain?(:prefix)).to be true }
60
+ end
61
+ end
62
+
63
+ describe '.register' do
64
+ it { expect(foo).not_to be_contain(:increment) }
65
+
66
+ it { expect(foo).to be_contain(:prefix) }
67
+
68
+ def do_register
69
+ foo.register(:increment, ->(v) { v + 1 })
70
+ end
71
+
72
+ it 'returns self' do
73
+ expect(do_register).to eq foo
74
+ end
75
+
76
+ it 'registers function' do
77
+ do_register
78
+ expect(foo).to be_contain(:increment)
79
+ end
80
+
81
+ it 'preserves previous functions' do
82
+ do_register
83
+ expect(foo).to be_contain(:prefix)
84
+ end
85
+
86
+ it 'makes function available' do
87
+ do_register
88
+ expect(foo[:increment][2]).to eq 3
89
+ end
90
+
91
+ it 'rejects to overwrite existing' do
92
+ expect { foo.register(:prefix) {} }
93
+ .to raise_error(Transproc::FunctionAlreadyRegisteredError)
94
+ end
95
+
96
+ it 'registers and fetches transproc function' do
97
+ function = foo[:prefix, '1']
98
+ foo.register(:prefix_one, function)
99
+
100
+ expect(foo[:prefix_one]).to eq function
101
+ end
102
+
103
+ it 'registers and fetches composite' do
104
+ composite = foo[:prefix, '1'] + foo[:prefix, '2']
105
+ foo.register(:double_prefix, composite)
106
+
107
+ expect(foo[:double_prefix]).to eq composite
108
+ end
109
+
110
+ context 'with block argument' do
111
+ def do_register
112
+ foo.register(:increment) { |v| v + 1 }
113
+ end
114
+
115
+ it 'registers function' do
116
+ do_register
117
+ expect(foo).to be_contain(:increment)
118
+ end
119
+
120
+ it 'makes function available' do
121
+ do_register
122
+ expect(foo[:increment][2]).to eq 3
123
+ end
124
+ end
125
+ end
126
+
47
127
  describe '.import' do
48
128
  context 'a module' do
49
129
  subject(:import) { bar.import foo }
@@ -33,11 +33,46 @@ describe Transproc::Store do
33
33
  expect(store.fetch(:foo)).to eql methods[:foo]
34
34
  end
35
35
 
36
+ it 'does not accepts anything but symbol as key' do
37
+ expect { store.fetch('foo') }.to raise_error KeyError
38
+ end
39
+
36
40
  it 'raises KeyError if requested proc is unknown' do
37
41
  expect { store.fetch(:bar) }.to raise_error KeyError
38
42
  end
39
43
  end # describe #fetch
40
44
 
45
+ describe '#contain?' do
46
+ it 'returns true for registered proc' do
47
+ expect(store.contain?(:foo)).to be true
48
+ end
49
+
50
+ it 'returns false if requested proc is unknown' do
51
+ expect(store.contain?(:bar)).to be false
52
+ end
53
+ end # describe #fetch
54
+
55
+ describe '#register' do
56
+ subject { new_store }
57
+ let(:new_store) { store.register(:increment, ->(v) { v + 1 }) }
58
+
59
+ it { is_expected.to be_contain(:increment) }
60
+
61
+ it { expect(new_store.fetch(:increment)[2]).to eq 3 }
62
+
63
+ it 'preserves existing methods' do
64
+ expect(new_store).to be_contain(:foo)
65
+ end
66
+
67
+ context 'with block argument' do
68
+ let(:new_store) { store.register(:increment) { |v| v + 1 } }
69
+
70
+ it 'works as well as with proc' do
71
+ expect(new_store.fetch(:increment)[2]).to eq 3
72
+ end
73
+ end
74
+ end
75
+
41
76
  describe '#import', :focus do
42
77
  before do
43
78
  module Bar
@@ -1,15 +1,20 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Transproc::Transformer do
4
- let(:klass) { Class.new(Transproc::Transformer) }
4
+ let(:container) { Module.new { extend Transproc::Registry } }
5
+ let(:klass) { Transproc::Transformer[container] }
5
6
  let(:transformer) { klass.new }
6
7
 
7
8
  describe '.container' do
8
- context 'without setter argument' do
9
- subject! { klass.container }
9
+ it { expect(klass.container).to eq container }
10
10
 
11
- it 'defaults to Transproc' do
12
- is_expected.to eq(Transproc)
11
+ context 'with default transformer' do
12
+ let(:klass) { described_class }
13
+
14
+ it 'raises exception because there is no container by default' do
15
+ message = 'Transformer function registry is empty. '\
16
+ 'Provide your registry via Transproc::Transformer[YourRegistry]'
17
+ expect { klass.container }.to raise_error(ArgumentError, message)
13
18
  end
14
19
  end
15
20
 
@@ -22,18 +27,189 @@ describe Transproc::Transformer do
22
27
  end
23
28
  end
24
29
 
30
+ describe 'inheritance' do
31
+ let(:container) do
32
+ Module.new do
33
+ extend Transproc::Registry
34
+
35
+ def self.arbitrary(value, fn)
36
+ fn[value]
37
+ end
38
+ end
39
+ end
40
+ let(:superclass) do
41
+ Class.new(Transproc::Transformer[container]) do
42
+ arbitrary ->(v) { v + 1 }
43
+ end
44
+ end
45
+ let(:subclass) do
46
+ Class.new(superclass) do
47
+ arbitrary ->(v) { v * 2 }
48
+ end
49
+ end
50
+
51
+ it 'inherits container from superclass' do
52
+ expect(subclass.container).to eq superclass.container
53
+ end
54
+
55
+ it 'does not inherit transproc from superclass' do
56
+ expect(superclass.new.call(2)).to eq 3
57
+ expect(subclass.new.call(2)).to eq 4
58
+ end
59
+ end
60
+
25
61
  describe '.[]' do
26
- let(:container) { double('Transproc') }
62
+ let(:another_container) { double('Transproc') }
27
63
 
28
- subject!(:klass) { Transproc::Transformer[container] }
64
+ subject(:subclass) { klass[another_container] }
29
65
 
30
- it { expect(klass.container).to eq(container) }
66
+ it { expect(subclass.container).to eq(another_container) }
31
67
  it { is_expected.to be_a(::Class) }
68
+ it { expect(subclass.ancestors).to include(Transproc::Transformer) }
69
+
70
+ it 'does not change super class' do
71
+ expect(klass.container).to eq(container)
72
+ end
73
+
74
+ context 'with predefined transformer' do
75
+ let(:klass) do
76
+ Class.new(Transproc::Transformer) do
77
+ map_value :attr, t(:to_symbol)
78
+ end
79
+ end
80
+ end
81
+
82
+ it 'does not inherit transproc' do
83
+ expect(klass[container].transproc).to be_nil
84
+ end
85
+ end
86
+
87
+ describe '.define' do
88
+ let(:container) do
89
+ Module.new do
90
+ extend Transproc::Registry
91
+
92
+ import Transproc::HashTransformations
93
+
94
+ def self.to_symbol(v)
95
+ v.to_sym
96
+ end
97
+ end
98
+ end
99
+ let(:klass) { Transproc::Transformer[container] }
100
+
101
+ it 'defines anonymous transproc' do
102
+ transproc = klass.define do
103
+ map_value(:attr, t(:to_symbol))
104
+ end
105
+ expect(transproc[attr: 'abc']).to eq(attr: :abc)
106
+ end
107
+
108
+ it 'has .build alias' do
109
+ transproc = klass.build do
110
+ map_value(:attr, t(:to_symbol))
111
+ end
112
+ expect(transproc[attr: 'abc']).to eq(attr: :abc)
113
+ end
114
+
115
+ it 'does not affect original transformer' do
116
+ klass.define do
117
+ map_value(:attr, :to_sym.to_proc)
118
+ end
119
+ expect(klass.transproc).to be_nil
120
+ end
121
+
122
+ context 'with custom container' do
123
+ let(:container) do
124
+ Module.new do
125
+ extend Transproc::Registry
126
+
127
+ def self.arbitrary(value, fn)
128
+ fn[value]
129
+ end
130
+ end
131
+ end
132
+ let(:klass) { described_class[container] }
133
+
134
+ it 'uses a container from the transformer' do
135
+ transproc = klass.define do
136
+ arbitrary ->(v) { v + 1 }
137
+ end
138
+ expect(transproc.call(2)).to eq 3
139
+ end
140
+ end
141
+
142
+ context 'with predefined transformer' do
143
+ let(:klass) do
144
+ Class.new(described_class[container]) do
145
+ map_value :attr, ->(v) { v + 1 }
146
+ end
147
+ end
148
+
149
+ it 'just initializes transformer if no block was given' do
150
+ transproc = klass.define
151
+ expect(transproc.call(attr: 2)).to eq(attr: 3)
152
+ end
153
+
154
+ it 'does not inherit transproc from superclass' do
155
+ transproc = klass.define do
156
+ map_value :attr, ->(v) { v * 2 }
157
+ end
158
+ expect(transproc.call(attr: 2)).to eq(attr: 4)
159
+ end
160
+ end
161
+ end
162
+
163
+ describe '.t' do
164
+ let(:container) do
165
+ Module.new do
166
+ extend Transproc::Registry
167
+
168
+ import Transproc::HashTransformations
169
+ import Transproc::Conditional
170
+
171
+ def self.custom(value, suffix)
172
+ value + suffix
173
+ end
174
+ end
175
+ end
176
+
177
+ subject!(:klass) { Transproc::Transformer[container] }
178
+
179
+ it { expect(klass.t(:custom, '_bar')).to eq container[:custom, '_bar'] }
180
+
181
+ it 'is useful in DSL' do
182
+ transproc = Class.new(klass) do
183
+ map_value :a, t(:custom, '_bar')
184
+ end.new
185
+
186
+ expect(transproc.call(a: 'foo')).to eq(a: 'foo_bar')
187
+ end
188
+
189
+ it 'works in nested block' do
190
+ transproc = Class.new(klass) do
191
+ map_values do
192
+ is String, t(:custom, '_bar')
193
+ end
194
+ end.new
195
+
196
+ expect(transproc.call(a: 'foo', b: :symbol)).to eq(a: 'foo_bar', b: :symbol)
197
+ end
32
198
  end
33
199
 
34
200
  describe '#call' do
201
+ let(:container) do
202
+ Module.new do
203
+ extend Transproc::Registry
204
+
205
+ import Transproc::HashTransformations
206
+ import Transproc::ArrayTransformations
207
+ import Transproc::ClassTransformations
208
+ end
209
+ end
210
+
35
211
  let(:klass) do
36
- Class.new(Transproc::Transformer) do
212
+ Class.new(Transproc::Transformer[container]) do
37
213
  map_array do
38
214
  symbolize_keys
39
215
  rename_keys user_name: :name
@@ -82,5 +258,25 @@ describe Transproc::Transformer do
82
258
  subject! { transformer.call(input) }
83
259
 
84
260
  it { is_expected.to eq(output) }
261
+
262
+ context 'with custom registry' do
263
+ let(:klass) do
264
+ Class.new(Transproc::Transformer[registry]) do
265
+ custom ' is awesome'
266
+ end
267
+ end
268
+ let(:registry) do
269
+ Module.new do
270
+ extend Transproc::Registry
271
+
272
+ def self.custom(value, suffix)
273
+ value + suffix
274
+ end
275
+ end
276
+ end
277
+ let(:input) { 'transproc' }
278
+
279
+ it { is_expected.to eq('transproc is awesome') }
280
+ end
85
281
  end
86
282
  end
@@ -6,55 +6,12 @@ describe Transproc do
6
6
  input = '1'
7
7
  output = 1.0
8
8
 
9
- to_i = t(-> value { value.to_i })
10
- to_f = t(-> value { value.to_f })
9
+ to_i = Transproc::Function.new(->(value) { value.to_i })
10
+ to_f = Transproc::Function.new(->(value) { value.to_f })
11
11
 
12
12
  result = to_i >> to_f
13
13
 
14
14
  expect(result[input]).to eql(output)
15
15
  end
16
16
  end
17
-
18
- describe '.register' do
19
- it 'allows registering functions by name' do
20
- Transproc.register(:id, -> value { value })
21
-
22
- value = 'hello world'
23
-
24
- result = t(:id)[value]
25
-
26
- expect(result).to be(value)
27
- end
28
-
29
- it 'allows registering function by passing a block' do
30
- Transproc.register(:to_boolean1) { |value| value == 'true' }
31
-
32
- result = t(-> value { value.to_s }) >> t(:to_boolean1)
33
-
34
- expect(result[:true]).to be(true)
35
- expect(result[:false]).to be(false)
36
- end
37
-
38
- it 'raises a Transproc::FunctionAlreadyRegisteredError if a function is already registered' do
39
- Transproc.register(:bogus) {}
40
- expect { Transproc.register(:bogus) {} }.to raise_error(Transproc::FunctionAlreadyRegisteredError)
41
- end
42
- end
43
-
44
- describe 'nonextistent functions' do
45
- it 'raises a Transproc::FunctionNotFoundError if asking for function that is non exsistent' do
46
- expect {
47
- Transproc(:i_do_not_exist)
48
- raise('expected the :i_do_not_exist function to not exist')
49
- }.to raise_error(Transproc::FunctionNotFoundError)
50
- end
51
- end
52
-
53
- describe 'accessing a function with args' do
54
- it 'curries the args' do
55
- fn = Transproc(:map_array, Transproc(:to_string))
56
-
57
- expect(fn.args).to include(Transproc(:to_string))
58
- end
59
- end
60
17
  end