dry-transformer 0.1.0 → 0.1.1
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 +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
|