transproc 0.4.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +132 -2
- data/lib/transproc.rb +0 -71
- data/lib/transproc/array.rb +36 -74
- data/lib/transproc/class.rb +0 -4
- data/lib/transproc/coercions.rb +0 -4
- data/lib/transproc/composer.rb +0 -26
- data/lib/transproc/conditional.rb +0 -4
- data/lib/transproc/hash.rb +43 -159
- data/lib/transproc/proc.rb +0 -4
- data/lib/transproc/recursion.rb +0 -4
- data/lib/transproc/registry.rb +35 -1
- data/lib/transproc/store.rb +22 -1
- data/lib/transproc/transformer/class_interface.rb +63 -19
- data/lib/transproc/version.rb +1 -1
- data/spec/spec_helper.rb +0 -4
- data/spec/unit/array_transformations_spec.rb +18 -90
- data/spec/unit/function_not_found_error_spec.rb +1 -9
- data/spec/unit/function_spec.rb +17 -12
- data/spec/unit/hash_transformations_spec.rb +78 -240
- data/spec/unit/recursion_spec.rb +8 -24
- data/spec/unit/registry_spec.rb +80 -0
- data/spec/unit/store_spec.rb +35 -0
- data/spec/unit/transformer_spec.rb +205 -9
- data/spec/unit/transproc_spec.rb +2 -45
- metadata +2 -3
- data/lib/transproc/rspec.rb +0 -71
data/spec/unit/recursion_spec.rb
CHANGED
@@ -108,21 +108,19 @@ describe Transproc::Recursion do
|
|
108
108
|
end
|
109
109
|
|
110
110
|
describe '.hash_recursion' do
|
111
|
-
let(:
|
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
|
-
|
140
|
-
|
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
|
-
|
151
|
-
|
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
|
data/spec/unit/registry_spec.rb
CHANGED
@@ -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 }
|
data/spec/unit/store_spec.rb
CHANGED
@@ -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(:
|
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
|
-
|
9
|
-
subject! { klass.container }
|
9
|
+
it { expect(klass.container).to eq container }
|
10
10
|
|
11
|
-
|
12
|
-
|
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(:
|
62
|
+
let(:another_container) { double('Transproc') }
|
27
63
|
|
28
|
-
subject
|
64
|
+
subject(:subclass) { klass[another_container] }
|
29
65
|
|
30
|
-
it { expect(
|
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
|
data/spec/unit/transproc_spec.rb
CHANGED
@@ -6,55 +6,12 @@ describe Transproc do
|
|
6
6
|
input = '1'
|
7
7
|
output = 1.0
|
8
8
|
|
9
|
-
to_i =
|
10
|
-
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
|