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