transproc 0.4.2 → 1.0.0

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