transproc 1.0.3 → 1.1.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/.codeclimate.yml +15 -0
- data/.gitignore +3 -0
- data/.travis.yml +10 -10
- data/CHANGELOG.md +14 -2
- data/Gemfile +5 -17
- data/lib/transproc.rb +3 -4
- data/lib/transproc/all.rb +2 -0
- data/lib/transproc/array.rb +2 -0
- data/lib/transproc/array/combine.rb +2 -0
- data/lib/transproc/class.rb +2 -0
- data/lib/transproc/coercions.rb +2 -0
- data/lib/transproc/compiler.rb +45 -0
- data/lib/transproc/composer.rb +2 -0
- data/lib/transproc/composite.rb +2 -0
- data/lib/transproc/conditional.rb +2 -0
- data/lib/transproc/constants.rb +5 -0
- data/lib/transproc/error.rb +2 -0
- data/lib/transproc/function.rb +2 -0
- data/lib/transproc/functions.rb +2 -0
- data/lib/transproc/hash.rb +31 -0
- data/lib/transproc/proc.rb +2 -0
- data/lib/transproc/recursion.rb +2 -0
- data/lib/transproc/registry.rb +1 -0
- data/lib/transproc/store.rb +1 -0
- data/lib/transproc/support/deprecations.rb +2 -0
- data/lib/transproc/transformer.rb +7 -1
- data/lib/transproc/transformer/class_interface.rb +31 -65
- data/lib/transproc/transformer/deprecated/class_interface.rb +80 -0
- data/lib/transproc/transformer/dsl.rb +51 -0
- data/lib/transproc/version.rb +3 -1
- data/spec/spec_helper.rb +5 -7
- data/spec/unit/array/combine_spec.rb +3 -1
- data/spec/unit/array_transformations_spec.rb +1 -1
- data/spec/unit/class_transformations_spec.rb +9 -6
- data/spec/unit/coercions_spec.rb +1 -1
- data/spec/unit/composer_spec.rb +1 -1
- data/spec/unit/conditional_spec.rb +1 -1
- data/spec/unit/function_not_found_error_spec.rb +1 -1
- data/spec/unit/function_spec.rb +1 -1
- data/spec/unit/hash_transformations_spec.rb +12 -1
- data/spec/unit/proc_transformations_spec.rb +3 -1
- data/spec/unit/recursion_spec.rb +1 -1
- data/spec/unit/registry_spec.rb +1 -1
- data/spec/unit/store_spec.rb +2 -1
- data/spec/unit/transformer/class_interface_spec.rb +364 -0
- data/spec/unit/transformer/dsl_spec.rb +15 -0
- data/spec/unit/transformer/instance_methods_spec.rb +25 -0
- data/spec/unit/transformer_spec.rb +128 -40
- data/spec/unit/transproc_spec.rb +1 -1
- data/transproc.gemspec +0 -4
- metadata +15 -53
- data/.rubocop.yml +0 -66
- data/.rubocop_todo.yml +0 -11
- data/rakelib/mutant.rake +0 -16
- data/rakelib/rubocop.rake +0 -18
- data/spec/support/mutant.rb +0 -10
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Transproc
|
4
|
+
class Transformer
|
5
|
+
module Deprecated
|
6
|
+
# @api public
|
7
|
+
module ClassInterface
|
8
|
+
# @api public
|
9
|
+
def new(*args)
|
10
|
+
super(*args).tap do |transformer|
|
11
|
+
transformer.instance_variable_set('@transproc', transproc) if transformations.any?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
def inherited(subclass)
|
17
|
+
super
|
18
|
+
|
19
|
+
if transformations.any?
|
20
|
+
subclass.instance_variable_set('@transformations', transformations.dup)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Define an anonymous transproc derived from given Transformer
|
25
|
+
# Evaluates block with transformations and returns initialized transproc.
|
26
|
+
# Does not mutate original Transformer
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
#
|
30
|
+
# class MyTransformer < Transproc::Transformer[MyContainer]
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# transproc = MyTransformer.define do
|
34
|
+
# map_values t(:to_string)
|
35
|
+
# end
|
36
|
+
# transproc.call(a: 1, b: 2)
|
37
|
+
# # => {a: '1', b: '2'}
|
38
|
+
#
|
39
|
+
# @yield Block allowing to define transformations. The same as class level DSL
|
40
|
+
#
|
41
|
+
# @return [Function] Composed transproc
|
42
|
+
#
|
43
|
+
# @api public
|
44
|
+
def define(&block)
|
45
|
+
return transproc unless block_given?
|
46
|
+
|
47
|
+
Class.new(Transformer[container]).tap { |klass| klass.instance_eval(&block) }.transproc
|
48
|
+
end
|
49
|
+
alias build define
|
50
|
+
|
51
|
+
# @api private
|
52
|
+
def method_missing(method, *args, &block)
|
53
|
+
super unless container.contain?(method)
|
54
|
+
func = block ? t(method, *args, define(&block)) : t(method, *args)
|
55
|
+
transformations << func
|
56
|
+
func
|
57
|
+
end
|
58
|
+
|
59
|
+
# @api private
|
60
|
+
def respond_to_missing?(method, _include_private = false)
|
61
|
+
super || container.contain?(method)
|
62
|
+
end
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
def transproc
|
66
|
+
transformations.reduce(:>>)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# An array containing the transformation pipeline
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
def transformations
|
75
|
+
@transformations ||= []
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'transproc/compiler'
|
4
|
+
|
5
|
+
module Transproc
|
6
|
+
class Transformer
|
7
|
+
# @api public
|
8
|
+
class DSL
|
9
|
+
# @api private
|
10
|
+
attr_reader :container
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
attr_reader :ast
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
def initialize(container, ast: [], &block)
|
17
|
+
@container = container
|
18
|
+
@ast = ast
|
19
|
+
instance_eval(&block) if block
|
20
|
+
end
|
21
|
+
|
22
|
+
# @api private
|
23
|
+
def dup
|
24
|
+
self.class.new(container, ast: ast.dup)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
def call(transformer)
|
29
|
+
Compiler.new(container, transformer).(ast)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
def node(&block)
|
36
|
+
[:t, self.class.new(container, &block).ast]
|
37
|
+
end
|
38
|
+
|
39
|
+
# @api private
|
40
|
+
def respond_to_missing?(method, _include_private = false)
|
41
|
+
super || container.contain?(method)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @api private
|
45
|
+
def method_missing(meth, *args, &block)
|
46
|
+
arg_nodes = *args.map { |a| [:arg, a] }
|
47
|
+
ast << [:fn, (block ? [meth, [*arg_nodes, node(&block)]] : [meth, arg_nodes])]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/transproc/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
if RUBY_ENGINE == 'ruby' && ENV['COVERAGE'] == 'true'
|
2
4
|
require 'yaml'
|
3
5
|
rubies = YAML.load(File.read(File.join(__dir__, '..', '.travis.yml')))['rvm']
|
@@ -11,15 +13,11 @@ if RUBY_ENGINE == 'ruby' && ENV['COVERAGE'] == 'true'
|
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
14
|
-
require 'equalizer'
|
15
|
-
require 'anima'
|
16
|
-
require 'ostruct'
|
17
|
-
require 'transproc/all'
|
18
|
-
|
19
16
|
begin
|
20
17
|
require 'byebug'
|
21
|
-
rescue LoadError
|
22
|
-
|
18
|
+
rescue LoadError;end
|
19
|
+
|
20
|
+
require 'transproc/all'
|
23
21
|
|
24
22
|
root = Pathname(__FILE__).dirname
|
25
23
|
Dir[root.join('support/*.rb').to_s].each { |f| require f }
|
@@ -1,9 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/equalizer'
|
2
4
|
|
3
5
|
describe Transproc::ClassTransformations do
|
4
6
|
describe '.constructor_inject' do
|
5
7
|
let(:klass) do
|
6
|
-
Struct.new(:name, :age) { include Equalizer.new(:name, :age) }
|
8
|
+
Struct.new(:name, :age) { include Dry::Equalizer.new(:name, :age) }
|
7
9
|
end
|
8
10
|
|
9
11
|
it 'returns a new object initialized with the given arguments' do
|
@@ -21,12 +23,13 @@ describe Transproc::ClassTransformations do
|
|
21
23
|
describe '.set_ivars' do
|
22
24
|
let(:klass) do
|
23
25
|
Class.new do
|
24
|
-
include
|
26
|
+
include Dry::Equalizer.new(:name, :age)
|
25
27
|
|
26
|
-
attr_reader :test
|
28
|
+
attr_reader :name, :age, :test
|
27
29
|
|
28
|
-
def initialize(
|
29
|
-
|
30
|
+
def initialize(name:, age:)
|
31
|
+
@name = name
|
32
|
+
@age = age
|
30
33
|
@test = true
|
31
34
|
end
|
32
35
|
end
|
data/spec/unit/coercions_spec.rb
CHANGED
data/spec/unit/composer_spec.rb
CHANGED
data/spec/unit/function_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
describe Transproc::HashTransformations do
|
4
4
|
describe '.map_keys' do
|
@@ -50,6 +50,17 @@ describe Transproc::HashTransformations do
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
+
describe '.deep_stringify_keys' do
|
54
|
+
it 'returns a new hash with symbolized keys' do
|
55
|
+
stringify_keys = described_class.t(:deep_stringify_keys)
|
56
|
+
|
57
|
+
input = { foo: 'bar', baz: [{ one: 1 }, 'two'] }
|
58
|
+
output = { 'foo' => 'bar', 'baz' => [{ 'one' => 1 }, 'two'] }
|
59
|
+
|
60
|
+
expect(stringify_keys[input]).to eql(output)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
53
64
|
it { expect(described_class).not_to be_contain(:stringify_keys!) }
|
54
65
|
|
55
66
|
describe '.map_values' do
|
data/spec/unit/recursion_spec.rb
CHANGED
data/spec/unit/registry_spec.rb
CHANGED
data/spec/unit/store_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
describe Transproc::Store do
|
4
4
|
let(:store) { described_class.new methods }
|
@@ -186,6 +186,7 @@ describe Transproc::Store do
|
|
186
186
|
end
|
187
187
|
|
188
188
|
it 'skips Transproc::Registry singleton methods' do
|
189
|
+
pending "this fails for some reason" if RUBY_ENGINE == "jruby"
|
189
190
|
expect(subject.methods.keys).to contain_exactly(:foo, :bar, :baz, :qux)
|
190
191
|
end
|
191
192
|
end
|
@@ -0,0 +1,364 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
require 'dry/equalizer'
|
5
|
+
|
6
|
+
describe Transproc::Transformer do
|
7
|
+
let(:container) { Module.new { extend Transproc::Registry } }
|
8
|
+
let(:klass) { Transproc::Transformer[container] }
|
9
|
+
let(:transformer) { klass.new }
|
10
|
+
|
11
|
+
describe '.import' do
|
12
|
+
it 'allows importing functions into an auto-configured registry' do
|
13
|
+
klass = Class.new(Transproc::Transformer) do
|
14
|
+
import Transproc::ArrayTransformations
|
15
|
+
import Transproc::Coercions
|
16
|
+
|
17
|
+
define! do
|
18
|
+
map_array(&:to_symbol)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
transformer = klass.new
|
23
|
+
|
24
|
+
expect(transformer.(['foo', 'bar'])).to eql([:foo, :bar])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '.new' do
|
29
|
+
it 'supports arguments' do
|
30
|
+
klass = Class.new(Transproc::Transformer) do
|
31
|
+
import Transproc::ArrayTransformations
|
32
|
+
import Transproc::Coercions
|
33
|
+
|
34
|
+
define! do
|
35
|
+
map_array(&:to_symbol)
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(good)
|
39
|
+
@good = good
|
40
|
+
end
|
41
|
+
|
42
|
+
def good?
|
43
|
+
@good
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
transformer = klass.new(true)
|
48
|
+
|
49
|
+
expect(transformer).to be_good
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '.container' do
|
54
|
+
it 'returns the configured container' do
|
55
|
+
expect(klass.container).to be(container)
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with setter argument' do
|
59
|
+
let(:container) { double(:custom_container) }
|
60
|
+
|
61
|
+
it 'sets and returns the container' do
|
62
|
+
klass.container(container)
|
63
|
+
|
64
|
+
expect(klass.container).to be(container)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'inheritance' do
|
70
|
+
let(:container) do
|
71
|
+
Module.new do
|
72
|
+
extend Transproc::Registry
|
73
|
+
|
74
|
+
def self.arbitrary(value, fn)
|
75
|
+
fn[value]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
let(:superclass) do
|
81
|
+
Class.new(Transproc::Transformer[container]) do
|
82
|
+
define! do
|
83
|
+
arbitrary ->(v) { v + 1 }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:subclass) do
|
89
|
+
Class.new(superclass) do
|
90
|
+
define! do
|
91
|
+
arbitrary ->(v) { v * 2 }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'inherits container from superclass' do
|
97
|
+
expect(subclass.container).to be(superclass.container)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'inherits transproc from superclass' do
|
101
|
+
expect(superclass.new.call(2)).to be(3)
|
102
|
+
expect(subclass.new.call(2)).to be(6)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '.[]' do
|
107
|
+
subject(:subclass) { klass[another_container] }
|
108
|
+
|
109
|
+
let(:another_container) { double('Transproc') }
|
110
|
+
|
111
|
+
it 'sets a container' do
|
112
|
+
expect(subclass.container).to be(another_container)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'returns a class' do
|
116
|
+
expect(subclass).to be_a(Class)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'creates a subclass of Transformer' do
|
120
|
+
expect(subclass).to be < Transproc::Transformer
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'does not change super class' do
|
124
|
+
expect(klass.container).to be(container)
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'does not inherit transproc' do
|
128
|
+
expect(klass[container].new.transproc).to be_nil
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'with predefined transformer' do
|
132
|
+
let(:klass) do
|
133
|
+
Class.new(Transproc::Transformer[container]) do
|
134
|
+
container.import Transproc::Coercions
|
135
|
+
container.import Transproc::HashTransformations
|
136
|
+
|
137
|
+
map_value :attr, t(:to_symbol)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
it "inherits parent's transproc" do
|
142
|
+
expect(klass[container].new.transproc).to eql(klass.new.transproc)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe '.define' do
|
148
|
+
let(:container) do
|
149
|
+
Module.new do
|
150
|
+
extend Transproc::Registry
|
151
|
+
|
152
|
+
import Transproc::HashTransformations
|
153
|
+
|
154
|
+
def self.to_symbol(v)
|
155
|
+
v.to_sym
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
let(:klass) { Transproc::Transformer[container] }
|
161
|
+
|
162
|
+
it 'defines anonymous transproc' do
|
163
|
+
transproc = klass.define do
|
164
|
+
map_value(:attr, t(:to_symbol))
|
165
|
+
end
|
166
|
+
|
167
|
+
expect(transproc[attr: 'abc']).to eq(attr: :abc)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'has .build alias' do
|
171
|
+
transproc = klass.build do
|
172
|
+
map_value(:attr, t(:to_symbol))
|
173
|
+
end
|
174
|
+
|
175
|
+
expect(transproc[attr: 'abc']).to eq(attr: :abc)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'does not affect original transformer' do
|
179
|
+
klass.define do
|
180
|
+
map_value(:attr, :to_sym.to_proc)
|
181
|
+
end
|
182
|
+
|
183
|
+
expect(klass.new.transproc).to be_nil
|
184
|
+
end
|
185
|
+
|
186
|
+
context 'with custom container' do
|
187
|
+
let(:container) do
|
188
|
+
Module.new do
|
189
|
+
extend Transproc::Registry
|
190
|
+
|
191
|
+
def self.arbitrary(value, fn)
|
192
|
+
fn[value]
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
let(:klass) { described_class[container] }
|
198
|
+
|
199
|
+
it 'uses a container from the transformer' do
|
200
|
+
transproc = klass.define! do
|
201
|
+
arbitrary ->(v) { v + 1 }
|
202
|
+
end.new
|
203
|
+
|
204
|
+
expect(transproc.call(2)).to eq 3
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'with predefined transformer' do
|
209
|
+
let(:klass) do
|
210
|
+
Class.new(described_class[container]) do
|
211
|
+
define! do
|
212
|
+
map_value :attr, ->(v) { v + 1 }
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'builds transformation from the DSL definition' do
|
218
|
+
transproc = klass.new
|
219
|
+
|
220
|
+
expect(transproc.call(attr: 2)).to eql(attr: 3)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe '.t' do
|
226
|
+
subject(:klass) { Transproc::Transformer[container] }
|
227
|
+
|
228
|
+
let(:container) do
|
229
|
+
Module.new do
|
230
|
+
extend Transproc::Registry
|
231
|
+
|
232
|
+
import Transproc::HashTransformations
|
233
|
+
import Transproc::Conditional
|
234
|
+
|
235
|
+
def self.custom(value, suffix)
|
236
|
+
value + suffix
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'returns a registed function' do
|
242
|
+
expect(klass.t(:custom, '_bar')).to eql(container[:custom, '_bar'])
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'is useful in DSL' do
|
246
|
+
transproc = Class.new(klass) do
|
247
|
+
map_value :a, t(:custom, '_bar')
|
248
|
+
end.new
|
249
|
+
|
250
|
+
expect(transproc.call(a: 'foo')).to eq(a: 'foo_bar')
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'works in nested block' do
|
254
|
+
transproc = Class.new(klass) do
|
255
|
+
map_values do
|
256
|
+
is String, t(:custom, '_bar')
|
257
|
+
end
|
258
|
+
end.new
|
259
|
+
|
260
|
+
expect(transproc.call(a: 'foo', b: :symbol)).to eq(a: 'foo_bar', b: :symbol)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe '.method_missing' do
|
265
|
+
it 'responds to missing when there is a corresponding function' do
|
266
|
+
container.import Transproc::HashTransformations
|
267
|
+
|
268
|
+
expect(klass.method(:map_values)).to be_a(Method)
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'raises when there is no corresponding function or instance method' do
|
272
|
+
expect { klass.not_here }.to raise_error(NoMethodError, /not_here/)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe '#call' do
|
277
|
+
let(:container) do
|
278
|
+
Module.new do
|
279
|
+
extend Transproc::Registry
|
280
|
+
|
281
|
+
import Transproc::HashTransformations
|
282
|
+
import Transproc::ArrayTransformations
|
283
|
+
import Transproc::ClassTransformations
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
let(:klass) do
|
288
|
+
Class.new(Transproc::Transformer[container]) do
|
289
|
+
map_array do
|
290
|
+
symbolize_keys
|
291
|
+
rename_keys user_name: :name
|
292
|
+
nest :address, [:city, :street, :zipcode]
|
293
|
+
|
294
|
+
map_value :address do
|
295
|
+
constructor_inject Test::Address
|
296
|
+
end
|
297
|
+
|
298
|
+
constructor_inject Test::User
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
let(:input) do
|
304
|
+
[
|
305
|
+
{ 'user_name' => 'Jane',
|
306
|
+
'city' => 'NYC',
|
307
|
+
'street' => 'Street 1',
|
308
|
+
'zipcode' => '123'
|
309
|
+
}
|
310
|
+
]
|
311
|
+
end
|
312
|
+
|
313
|
+
let(:expected_output) do
|
314
|
+
[
|
315
|
+
Test::User.new(
|
316
|
+
name: 'Jane',
|
317
|
+
address: Test::Address.new(
|
318
|
+
city: 'NYC',
|
319
|
+
street: 'Street 1',
|
320
|
+
zipcode: '123'
|
321
|
+
)
|
322
|
+
)
|
323
|
+
]
|
324
|
+
end
|
325
|
+
|
326
|
+
before do
|
327
|
+
module Test
|
328
|
+
class User < OpenStruct
|
329
|
+
include Dry::Equalizer(:name, :address)
|
330
|
+
end
|
331
|
+
|
332
|
+
class Address < OpenStruct
|
333
|
+
include Dry::Equalizer(:city, :street, :zipcode)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
it "transforms input" do
|
339
|
+
expect(transformer.(input)).to eql(expected_output)
|
340
|
+
end
|
341
|
+
|
342
|
+
context 'with custom registry' do
|
343
|
+
let(:klass) do
|
344
|
+
Class.new(Transproc::Transformer[registry]) do
|
345
|
+
append ' is awesome'
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
let(:registry) do
|
350
|
+
Module.new do
|
351
|
+
extend Transproc::Registry
|
352
|
+
|
353
|
+
def self.append(value, suffix)
|
354
|
+
value + suffix
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
it 'uses custom functions' do
|
360
|
+
expect(transformer.('transproc')).to eql('transproc is awesome')
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|