dry-transformer 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/dry-transformer.gemspec +17 -10
- data/lib/dry/transformer/hash.rb +2 -1
- data/lib/dry/transformer/version.rb +1 -1
- metadata +10 -56
- data/.codeclimate.yml +0 -12
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
- data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -30
- data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
- data/.github/workflows/custom_ci.yml +0 -66
- data/.github/workflows/docsite.yml +0 -34
- data/.github/workflows/sync_configs.yml +0 -34
- data/.gitignore +0 -16
- data/.rspec +0 -4
- data/.rubocop.yml +0 -95
- data/CODE_OF_CONDUCT.md +0 -13
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -19
- data/Rakefile +0 -6
- data/docsite/source/built-in-transformations.html.md +0 -47
- data/docsite/source/index.html.md +0 -15
- data/docsite/source/transformation-objects.html.md +0 -32
- data/docsite/source/using-standalone-functions.html.md +0 -82
- data/spec/spec_helper.rb +0 -31
- data/spec/unit/array/combine_spec.rb +0 -224
- data/spec/unit/array_transformations_spec.rb +0 -233
- data/spec/unit/class_transformations_spec.rb +0 -50
- data/spec/unit/coercions_spec.rb +0 -132
- data/spec/unit/conditional_spec.rb +0 -48
- data/spec/unit/function_not_found_error_spec.rb +0 -12
- data/spec/unit/function_spec.rb +0 -193
- data/spec/unit/hash_transformations_spec.rb +0 -490
- data/spec/unit/proc_transformations_spec.rb +0 -20
- data/spec/unit/recursion_spec.rb +0 -145
- data/spec/unit/registry_spec.rb +0 -202
- data/spec/unit/store_spec.rb +0 -198
- data/spec/unit/transformer/class_interface_spec.rb +0 -350
- data/spec/unit/transformer/dsl_spec.rb +0 -15
- data/spec/unit/transformer/instance_methods_spec.rb +0 -25
@@ -1,233 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe Dry::Transformer::ArrayTransformations do
|
4
|
-
let(:hashes) { Dry::Transformer::HashTransformations }
|
5
|
-
|
6
|
-
describe '.extract_key' do
|
7
|
-
it 'extracts values by key from all hashes' do
|
8
|
-
extract_key = described_class.t(:extract_key, 'name')
|
9
|
-
|
10
|
-
input = [
|
11
|
-
{ 'name' => 'Alice', 'role' => 'sender' },
|
12
|
-
{ 'name' => 'Bob', 'role' => 'receiver' },
|
13
|
-
{ 'role' => 'listener' }
|
14
|
-
].freeze
|
15
|
-
|
16
|
-
output = ['Alice', 'Bob', nil]
|
17
|
-
|
18
|
-
expect(extract_key[input]).to eql(output)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
it { expect(described_class).not_to be_contain(:extract_key!) }
|
23
|
-
|
24
|
-
describe '.insert_key' do
|
25
|
-
it 'wraps values to tuples with given key' do
|
26
|
-
insert_key = described_class.t(:insert_key, 'name')
|
27
|
-
|
28
|
-
input = ['Alice', 'Bob', nil].freeze
|
29
|
-
|
30
|
-
output = [
|
31
|
-
{ 'name' => 'Alice' },
|
32
|
-
{ 'name' => 'Bob' },
|
33
|
-
{ 'name' => nil }
|
34
|
-
]
|
35
|
-
|
36
|
-
expect(insert_key[input]).to eql(output)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
it { expect(described_class).not_to be_contain(:insert_key!) }
|
41
|
-
|
42
|
-
describe '.add_keys' do
|
43
|
-
it 'returns a new array with missed keys added to tuples' do
|
44
|
-
add_keys = described_class.t(:add_keys, [:foo, :bar, :baz])
|
45
|
-
|
46
|
-
input = [{ foo: 'bar' }, { bar: 'baz' }].freeze
|
47
|
-
|
48
|
-
output = [
|
49
|
-
{ foo: 'bar', bar: nil, baz: nil },
|
50
|
-
{ foo: nil, bar: 'baz', baz: nil }
|
51
|
-
]
|
52
|
-
|
53
|
-
expect(add_keys[input]).to eql(output)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
it { expect(described_class).not_to be_contain(:add_keys!) }
|
58
|
-
|
59
|
-
describe '.map_array' do
|
60
|
-
it 'applies funtions to all values' do
|
61
|
-
map = described_class.t(:map_array, hashes[:symbolize_keys])
|
62
|
-
|
63
|
-
input = [
|
64
|
-
{ 'name' => 'Jane', 'title' => 'One' }.freeze,
|
65
|
-
{ 'name' => 'Jane', 'title' => 'Two' }.freeze
|
66
|
-
].freeze
|
67
|
-
|
68
|
-
output = [
|
69
|
-
{ name: 'Jane', title: 'One' },
|
70
|
-
{ name: 'Jane', title: 'Two' }
|
71
|
-
]
|
72
|
-
|
73
|
-
expect(map[input]).to eql(output)
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'handles huge arrays' do
|
77
|
-
map = described_class.t(:map_array, hashes[:symbolize_keys])
|
78
|
-
|
79
|
-
input = Array.new(138_706) { |i| { 'key' => i } }
|
80
|
-
|
81
|
-
expect { map[input] }.to_not raise_error
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'handles flat value arrays' do
|
85
|
-
map = described_class.t(:map_array, :upcase.to_proc)
|
86
|
-
|
87
|
-
expect(map['foo']).to eql(%w(FOO))
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
it { expect(described_class).not_to be_contain(:map_array!) }
|
92
|
-
|
93
|
-
describe '.wrap' do
|
94
|
-
it 'returns a new array with wrapped hashes' do
|
95
|
-
wrap = described_class.t(:wrap, :task, [:title])
|
96
|
-
|
97
|
-
input = [{ name: 'Jane', title: 'One' }]
|
98
|
-
output = [{ name: 'Jane', task: { title: 'One' } }]
|
99
|
-
|
100
|
-
expect(wrap[input]).to eql(output)
|
101
|
-
end
|
102
|
-
|
103
|
-
it 'returns a array new with deeply wrapped hashes' do
|
104
|
-
wrap =
|
105
|
-
described_class.t(
|
106
|
-
:map_array,
|
107
|
-
hashes[:nest, :user, [:name, :title]] +
|
108
|
-
hashes[:map_value, :user, hashes[:nest, :task, [:title]]]
|
109
|
-
)
|
110
|
-
|
111
|
-
input = [{ name: 'Jane', title: 'One' }]
|
112
|
-
output = [{ user: { name: 'Jane', task: { title: 'One' } } }]
|
113
|
-
|
114
|
-
expect(wrap[input]).to eql(output)
|
115
|
-
end
|
116
|
-
|
117
|
-
it 'adds data to the existing tuples' do
|
118
|
-
wrap = described_class.t(:wrap, :task, [:title])
|
119
|
-
|
120
|
-
input = [{ name: 'Jane', task: { priority: 1 }, title: 'One' }]
|
121
|
-
output = [{ name: 'Jane', task: { priority: 1, title: 'One' } }]
|
122
|
-
|
123
|
-
expect(wrap[input]).to eql(output)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
describe '.group' do
|
128
|
-
subject(:group) { described_class.t(:group, :tasks, [:title]) }
|
129
|
-
|
130
|
-
it 'returns a new array with grouped hashes' do
|
131
|
-
input = [{ name: 'Jane', title: 'One' }, { name: 'Jane', title: 'Two' }]
|
132
|
-
output = [{ name: 'Jane', tasks: [{ title: 'One' }, { title: 'Two' }] }]
|
133
|
-
|
134
|
-
expect(group[input]).to eql(output)
|
135
|
-
end
|
136
|
-
|
137
|
-
it 'updates the existing group' do
|
138
|
-
input = [
|
139
|
-
{
|
140
|
-
name: 'Jane',
|
141
|
-
title: 'One',
|
142
|
-
tasks: [{ type: 'one' }, { type: 'two' }]
|
143
|
-
},
|
144
|
-
{
|
145
|
-
name: 'Jane',
|
146
|
-
title: 'Two',
|
147
|
-
tasks: [{ type: 'one' }, { type: 'two' }]
|
148
|
-
}
|
149
|
-
]
|
150
|
-
output = [
|
151
|
-
{
|
152
|
-
name: 'Jane',
|
153
|
-
tasks: [
|
154
|
-
{ title: 'One', type: 'one' },
|
155
|
-
{ title: 'One', type: 'two' },
|
156
|
-
{ title: 'Two', type: 'one' },
|
157
|
-
{ title: 'Two', type: 'two' }
|
158
|
-
]
|
159
|
-
}
|
160
|
-
]
|
161
|
-
|
162
|
-
expect(group[input]).to eql(output)
|
163
|
-
end
|
164
|
-
|
165
|
-
it 'ingnores old values except for array of tuples' do
|
166
|
-
input = [
|
167
|
-
{ name: 'Jane', title: 'One', tasks: [{ priority: 1 }, :wrong] },
|
168
|
-
{ name: 'Jane', title: 'Two', tasks: :wrong }
|
169
|
-
]
|
170
|
-
output = [
|
171
|
-
{
|
172
|
-
name: 'Jane',
|
173
|
-
tasks: [{ title: 'One', priority: 1 }, { title: 'Two' }]
|
174
|
-
}
|
175
|
-
]
|
176
|
-
|
177
|
-
expect(group[input]).to eql(output)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
describe '.ungroup' do
|
182
|
-
subject(:ungroup) { described_class.t(:ungroup, :tasks, [:title]) }
|
183
|
-
|
184
|
-
it 'returns a new array with ungrouped hashes' do
|
185
|
-
input = [{ name: 'Jane', tasks: [{ title: 'One' }, { title: 'Two' }] }]
|
186
|
-
output = [{ name: 'Jane', title: 'One' }, { name: 'Jane', title: 'Two' }]
|
187
|
-
|
188
|
-
expect(ungroup[input]).to eql(output)
|
189
|
-
end
|
190
|
-
|
191
|
-
it 'returns an input with empty array removed' do
|
192
|
-
input = [{ name: 'Jane', tasks: [] }]
|
193
|
-
output = [{ name: 'Jane' }]
|
194
|
-
|
195
|
-
expect(ungroup[input]).to eql(output)
|
196
|
-
end
|
197
|
-
|
198
|
-
it 'returns an input when a key is absent' do
|
199
|
-
input = [{ name: 'Jane' }]
|
200
|
-
output = [{ name: 'Jane' }]
|
201
|
-
|
202
|
-
expect(ungroup[input]).to eql(output)
|
203
|
-
end
|
204
|
-
|
205
|
-
it 'ungroups array partially' do
|
206
|
-
input = [
|
207
|
-
{
|
208
|
-
name: 'Jane',
|
209
|
-
tasks: [
|
210
|
-
{ title: 'One', type: 'one' },
|
211
|
-
{ title: 'One', type: 'two' },
|
212
|
-
{ title: 'Two', type: 'one' },
|
213
|
-
{ title: 'Two', type: 'two' }
|
214
|
-
]
|
215
|
-
}
|
216
|
-
]
|
217
|
-
output = [
|
218
|
-
{
|
219
|
-
name: 'Jane',
|
220
|
-
title: 'One',
|
221
|
-
tasks: [{ type: 'one' }, { type: 'two' }]
|
222
|
-
},
|
223
|
-
{
|
224
|
-
name: 'Jane',
|
225
|
-
title: 'Two',
|
226
|
-
tasks: [{ type: 'one' }, { type: 'two' }]
|
227
|
-
}
|
228
|
-
]
|
229
|
-
|
230
|
-
expect(ungroup[input]).to eql(output)
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'dry/equalizer'
|
4
|
-
|
5
|
-
RSpec.describe Dry::Transformer::ClassTransformations do
|
6
|
-
describe '.constructor_inject' do
|
7
|
-
let(:klass) do
|
8
|
-
Struct.new(:name, :age) { include Dry::Equalizer.new(:name, :age) }
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'returns a new object initialized with the given arguments' do
|
12
|
-
constructor_inject = described_class.t(:constructor_inject, klass)
|
13
|
-
|
14
|
-
input = ['Jane', 25]
|
15
|
-
output = klass.new(*input)
|
16
|
-
result = constructor_inject[*input]
|
17
|
-
|
18
|
-
expect(result).to eql(output)
|
19
|
-
expect(result).to be_instance_of(klass)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
describe '.set_ivars' do
|
24
|
-
let(:klass) do
|
25
|
-
Class.new do
|
26
|
-
include Dry::Equalizer.new(:name, :age)
|
27
|
-
|
28
|
-
attr_reader :name, :age, :test
|
29
|
-
|
30
|
-
def initialize(name:, age:)
|
31
|
-
@name = name
|
32
|
-
@age = age
|
33
|
-
@test = true
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'allocates a new object and sets instance variables from hash key/value pairs' do
|
39
|
-
set_ivars = described_class.t(:set_ivars, klass)
|
40
|
-
|
41
|
-
input = { name: 'Jane', age: 25 }
|
42
|
-
output = klass.new(input)
|
43
|
-
result = set_ivars[input]
|
44
|
-
|
45
|
-
expect(result).to eql(output)
|
46
|
-
expect(result.test).to be(nil)
|
47
|
-
expect(result).to be_instance_of(klass)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
data/spec/unit/coercions_spec.rb
DELETED
@@ -1,132 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe Dry::Transformer::Coercions do
|
4
|
-
describe '.identity' do
|
5
|
-
let(:fn) { described_class.t(:identity) }
|
6
|
-
|
7
|
-
it 'returns the original value' do
|
8
|
-
expect(fn[:foo]).to eql :foo
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'returns nil by default' do
|
12
|
-
expect(fn[]).to eql nil
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
describe '.to_string' do
|
17
|
-
it 'turns integer into a string' do
|
18
|
-
expect(described_class.t(:to_string)[1]).to eql('1')
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe '.to_symbol' do
|
23
|
-
it 'turns string into a symbol' do
|
24
|
-
expect(described_class.t(:to_symbol)['test']).to eql(:test)
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'turns non-string into a symbol' do
|
28
|
-
expect(described_class.t(:to_symbol)[1]).to eql(:'1')
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe '.to_integer' do
|
33
|
-
it 'turns string into an integer' do
|
34
|
-
expect(described_class.t(:to_integer)['1']).to eql(1)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
describe '.to_float' do
|
39
|
-
it 'turns string into a float' do
|
40
|
-
expect(described_class.t(:to_float)['1']).to eql(1.0)
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'turns integer into a float' do
|
44
|
-
expect(described_class.t(:to_float)[1]).to eql(1.0)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe '.to_decimal' do
|
49
|
-
it 'turns string into a decimal' do
|
50
|
-
expect(described_class.t(:to_decimal)['1.251']).to eql(BigDecimal('1.251'))
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'turns float into a decimal' do
|
54
|
-
expect(described_class.t(:to_decimal)[1.251]).to eql(BigDecimal('1.251'))
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'turns integer into a decimal' do
|
58
|
-
expect(described_class.t(:to_decimal)[1]).to eql(BigDecimal('1.0'))
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
describe '.to_date' do
|
63
|
-
it 'turns string into a date' do
|
64
|
-
date = Date.new(1983, 11, 18)
|
65
|
-
expect(described_class.t(:to_date)['18th, November 1983']).to eql(date)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
describe '.to_time' do
|
70
|
-
it 'turns string into a time object' do
|
71
|
-
time = Time.new(2012, 1, 23, 11, 7, 7)
|
72
|
-
expect(described_class.t(:to_time)['2012-01-23 11:07:07']).to eql(time)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
describe '.to_datetime' do
|
77
|
-
it 'turns string into a date' do
|
78
|
-
datetime = DateTime.new(2012, 1, 23, 11, 7, 7)
|
79
|
-
expect(described_class.t(:to_datetime)['2012-01-23 11:07:07']).to eql(datetime)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
describe '.to_boolean' do
|
84
|
-
subject(:coercer) { described_class.t(:to_boolean) }
|
85
|
-
|
86
|
-
Dry::Transformer::Coercions::TRUE_VALUES.each do |value|
|
87
|
-
it "turns #{value.inspect} to true" do
|
88
|
-
expect(coercer[value]).to be(true)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
Dry::Transformer::Coercions::FALSE_VALUES.each do |value|
|
93
|
-
it "turns #{value.inspect} to false" do
|
94
|
-
expect(coercer[value]).to be(false)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
describe '.to_tuples' do
|
100
|
-
subject(:to_tuples) { described_class.t(:to_tuples) }
|
101
|
-
|
102
|
-
context 'non-array' do
|
103
|
-
let(:input) { :foo }
|
104
|
-
|
105
|
-
it 'returns an array with one blank tuple' do
|
106
|
-
output = [{}]
|
107
|
-
|
108
|
-
expect(to_tuples[input]).to eql(output)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
context 'empty array' do
|
113
|
-
let(:input) { [] }
|
114
|
-
|
115
|
-
it 'returns an array with one blank tuple' do
|
116
|
-
output = [{}]
|
117
|
-
|
118
|
-
expect(to_tuples[input]).to eql(output)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
context 'array of tuples' do
|
123
|
-
let(:input) { [:foo, { bar: :BAZ }, :qux] }
|
124
|
-
|
125
|
-
it 'returns an array with tuples only' do
|
126
|
-
output = [{ bar: :BAZ }]
|
127
|
-
|
128
|
-
expect(to_tuples[input]).to eql(output)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
RSpec.describe Dry::Transformer::Conditional do
|
4
|
-
describe '.not' do
|
5
|
-
let(:fn) { described_class.t(:not, -> value { value.is_a? String }) }
|
6
|
-
subject { fn[input] }
|
7
|
-
|
8
|
-
context 'when predicate returns truthy value' do
|
9
|
-
let(:input) { 'foo' }
|
10
|
-
let(:output) { false }
|
11
|
-
|
12
|
-
it 'applies the first transformation' do
|
13
|
-
expect(subject).to eql output
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
context 'when predicate returns falsey value' do
|
18
|
-
let(:input) { :foo }
|
19
|
-
let(:output) { true }
|
20
|
-
|
21
|
-
it 'applies the first transformation' do
|
22
|
-
expect(subject).to eql output
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
describe '.guard' do
|
28
|
-
let(:fn) { described_class.t(:guard, condition, operation) }
|
29
|
-
let(:condition) { ->(value) { value.is_a?(::String) } }
|
30
|
-
let(:operation) { Dry::Transformer::Coercions.t(:to_integer) }
|
31
|
-
|
32
|
-
context 'when predicate returns truthy value' do
|
33
|
-
it 'applies the transformation and returns the result' do
|
34
|
-
input = '2'
|
35
|
-
|
36
|
-
expect(fn[input]).to eql(2)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'when predicate returns falsey value' do
|
41
|
-
it 'returns the original value' do
|
42
|
-
input = { 'foo' => 'bar' }
|
43
|
-
|
44
|
-
expect(fn[input]).to eql('foo' => 'bar')
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|