transproc 1.0.0 → 1.0.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 +24 -17
- data/README.md +3 -3
- data/lib/transproc/array.rb +4 -48
- data/lib/transproc/array/combine.rb +56 -0
- data/lib/transproc/function.rb +2 -1
- data/lib/transproc/hash.rb +17 -9
- data/lib/transproc/registry.rb +3 -2
- data/lib/transproc/version.rb +1 -1
- data/spec/unit/array/combine_spec.rb +214 -0
- data/spec/unit/array_transformations_spec.rb +0 -51
- data/spec/unit/function_spec.rb +15 -0
- data/spec/unit/registry_spec.rb +8 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd81b477e8c02b0e1644d7dd91c0dd798a09d24f
|
4
|
+
data.tar.gz: 6dde0346785ecc1de03f0beb9458cee9c427b5e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da55a09ce5a269141913ef066754d2e49a6e0cd45debdac119df3aff3788d0a287e654b43590c9c73223fd2b8ccfed48e4a6c850889259747414517c4eef21ad
|
7
|
+
data.tar.gz: 37c85578845d113c1f792cc02d83c9b697c585c8426fe8f76dc3b913a7ff307b97bc226cf039a95f40a1861d091e9a339b13016f71a512a7557e0a2428592a11
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,11 @@
|
|
1
|
-
|
1
|
+
# v1.0.1 2017-02-25
|
2
|
+
|
3
|
+
* `combine` is now multiple times faster, depending on the level of nesting (Kukunin + splattael)
|
4
|
+
* `nest` (thus `wrap` too) is ~2x faster now (solnic)
|
5
|
+
|
6
|
+
[Compare v1.0.0...v1.0.1](https://github.com/solnic/transproc/compare/v1.0.0...v1.0.1)
|
7
|
+
|
8
|
+
# v1.0.0 2017-01-29
|
2
9
|
|
3
10
|
## Added
|
4
11
|
|
@@ -14,7 +21,7 @@
|
|
14
21
|
|
15
22
|
[Compare v0.4.2...v1.0.0](https://github.com/solnic/transproc/compare/v0.4.2...v1.0.0)
|
16
23
|
|
17
|
-
|
24
|
+
# v0.4.2 2017-01-12
|
18
25
|
|
19
26
|
## Added
|
20
27
|
|
@@ -26,7 +33,7 @@
|
|
26
33
|
|
27
34
|
[Compare v0.4.1...v0.4.2](https://github.com/solnic/transproc/compare/v0.4.1...v0.4.2)
|
28
35
|
|
29
|
-
|
36
|
+
# v0.4.1 2016-11-08
|
30
37
|
|
31
38
|
## Added
|
32
39
|
|
@@ -38,7 +45,7 @@
|
|
38
45
|
|
39
46
|
[Compare v0.4.0...v0.4.1](https://github.com/solnic/transproc/compare/v0.4.0...v0.4.1)
|
40
47
|
|
41
|
-
|
48
|
+
# v0.4.0 2015-11-23
|
42
49
|
|
43
50
|
## Fixed
|
44
51
|
|
@@ -50,7 +57,7 @@
|
|
50
57
|
|
51
58
|
[Compare v0.3.2...v0.4.0](https://github.com/solnic/transproc/compare/v0.3.2...v0.4.0)
|
52
59
|
|
53
|
-
|
60
|
+
# v0.3.2 2015-08-17
|
54
61
|
|
55
62
|
## Changed
|
56
63
|
|
@@ -62,7 +69,7 @@
|
|
62
69
|
|
63
70
|
[Compare v0.3.1...v0.3.2](https://github.com/solnic/transproc/compare/v0.3.1...v0.3.2)
|
64
71
|
|
65
|
-
|
72
|
+
# v0.3.1 2015-08-06
|
66
73
|
|
67
74
|
### Added
|
68
75
|
|
@@ -74,7 +81,7 @@
|
|
74
81
|
|
75
82
|
[Compare v0.3.0...v0.3.1](https://github.com/solnic/transproc/compare/v0.3.0...v0.3.1)
|
76
83
|
|
77
|
-
|
84
|
+
# v0.3.0 2015-07-12
|
78
85
|
|
79
86
|
This release deprecates a couple of APIs and changes the way functions can be
|
80
87
|
accessed. The global `Transproc()` function registry is now deprecated and you
|
@@ -104,7 +111,7 @@ in 1.0.0.
|
|
104
111
|
|
105
112
|
[Compare v0.2.4...v0.3.0](https://github.com/solnic/transproc/compare/v0.2.4...v0.3.0)
|
106
113
|
|
107
|
-
|
114
|
+
# v0.2.4 2015-06-20
|
108
115
|
|
109
116
|
### Added
|
110
117
|
|
@@ -118,7 +125,7 @@ in 1.0.0.
|
|
118
125
|
|
119
126
|
[Compare v0.2.3...v0.2.4](https://github.com/solnic/transproc/compare/v0.2.3...v0.2.4)
|
120
127
|
|
121
|
-
|
128
|
+
# v0.2.3 2015-06-02
|
122
129
|
|
123
130
|
### Added
|
124
131
|
|
@@ -134,7 +141,7 @@ in 1.0.0.
|
|
134
141
|
|
135
142
|
[Compare v0.2.2...v0.2.3](https://github.com/solnic/transproc/compare/v0.2.2...v0.2.3)
|
136
143
|
|
137
|
-
|
144
|
+
# v0.2.2 2015-05-22
|
138
145
|
|
139
146
|
### Added
|
140
147
|
|
@@ -148,7 +155,7 @@ in 1.0.0.
|
|
148
155
|
|
149
156
|
[Compare v0.2.1...v0.2.2](https://github.com/solnic/transproc/compare/v0.2.1...v0.2.2)
|
150
157
|
|
151
|
-
|
158
|
+
# v0.2.1 2015-05-17
|
152
159
|
|
153
160
|
### Added
|
154
161
|
|
@@ -177,7 +184,7 @@ in 1.0.0.
|
|
177
184
|
|
178
185
|
[Compare v0.2.0...v0.2.1](https://github.com/solnic/transproc/compare/v0.2.0...v0.2.1)
|
179
186
|
|
180
|
-
|
187
|
+
# v0.2.0 2015-04-14
|
181
188
|
|
182
189
|
### Added
|
183
190
|
|
@@ -199,7 +206,7 @@ in 1.0.0.
|
|
199
206
|
|
200
207
|
[Compare v0.1.3...v0.2.0](https://github.com/solnic/transproc/compare/v0.1.3...v0.2.0)
|
201
208
|
|
202
|
-
|
209
|
+
# v0.1.3 2015-04-07
|
203
210
|
|
204
211
|
### Added
|
205
212
|
|
@@ -212,7 +219,7 @@ in 1.0.0.
|
|
212
219
|
|
213
220
|
[Compare v0.1.2...v0.1.3](https://github.com/solnic/transproc/compare/v0.1.2...v0.1.3)
|
214
221
|
|
215
|
-
|
222
|
+
# v0.1.2 2015-03-14
|
216
223
|
|
217
224
|
### Changed
|
218
225
|
|
@@ -220,7 +227,7 @@ in 1.0.0.
|
|
220
227
|
|
221
228
|
[Compare v0.1.1...v0.1.2](https://github.com/solnic/transproc/compare/v0.1.1...v0.1.2)
|
222
229
|
|
223
|
-
|
230
|
+
# v0.1.1 2015-03-13
|
224
231
|
|
225
232
|
### Changed
|
226
233
|
|
@@ -234,7 +241,7 @@ in 1.0.0.
|
|
234
241
|
|
235
242
|
[Compare v0.1.0...v0.1.1](https://github.com/solnic/transproc/compare/v0.1.0...v0.1.1)
|
236
243
|
|
237
|
-
|
244
|
+
# v0.1.0 2014-12-28
|
238
245
|
|
239
246
|
### Added
|
240
247
|
|
@@ -247,6 +254,6 @@ in 1.0.0.
|
|
247
254
|
|
248
255
|
[Compare v0.0.1...v0.1.0](https://github.com/solnic/transproc/compare/v0.0.1...v0.1.0)
|
249
256
|
|
250
|
-
|
257
|
+
# v0.0.1 2014-12-24
|
251
258
|
|
252
259
|
First public release \o/
|
data/README.md
CHANGED
@@ -45,15 +45,15 @@ Or install it yourself as:
|
|
45
45
|
Simple transformations are defined as easy as:
|
46
46
|
|
47
47
|
```ruby
|
48
|
-
|
49
|
-
|
48
|
+
increment = Transproc::Function.new(-> (data) { data + 1 })
|
49
|
+
increment[1] # => 2
|
50
50
|
```
|
51
51
|
|
52
52
|
It's easy to compose transformations:
|
53
53
|
|
54
54
|
```ruby
|
55
55
|
to_string = Transproc::Function.new(:to_s.to_proc)
|
56
|
-
(
|
56
|
+
(increment >> to_string)[1] => '2'
|
57
57
|
```
|
58
58
|
|
59
59
|
It's easy to pass additional arguments to transformations:
|
data/lib/transproc/array.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'transproc/coercions'
|
2
2
|
require 'transproc/hash'
|
3
|
+
require 'transproc/array/combine'
|
3
4
|
|
4
5
|
module Transproc
|
5
6
|
# Transformation functions for Array objects
|
@@ -58,7 +59,7 @@ module Transproc
|
|
58
59
|
# @api public
|
59
60
|
def self.wrap(array, key, keys)
|
60
61
|
nest = HashTransformations[:nest, key, keys]
|
61
|
-
|
62
|
+
array.map { |element| nest.call(element) }
|
62
63
|
end
|
63
64
|
|
64
65
|
# Group array values using provided root key and value keys
|
@@ -118,53 +119,8 @@ module Transproc
|
|
118
119
|
array.flat_map { |item| HashTransformations.split(item, key, keys) }
|
119
120
|
end
|
120
121
|
|
121
|
-
|
122
|
-
|
123
|
-
def self.combine(array, mappings, cache = CACHE.dup)
|
124
|
-
root, groups = array
|
125
|
-
|
126
|
-
root.map do |parent|
|
127
|
-
child_hash = {}
|
128
|
-
|
129
|
-
for candidates in groups
|
130
|
-
index = groups.index(candidates)
|
131
|
-
data = mappings[index]
|
132
|
-
|
133
|
-
key = data[0]
|
134
|
-
keys = data[1]
|
135
|
-
|
136
|
-
children =
|
137
|
-
if data.size == 2
|
138
|
-
candidates
|
139
|
-
else
|
140
|
-
combine(candidates, data[2])
|
141
|
-
end
|
142
|
-
|
143
|
-
child_keys = keys.size > 1 ? keys.values : keys.values[0]
|
144
|
-
pk_names = keys.size > 1 ? keys.keys : keys.keys[0]
|
145
|
-
|
146
|
-
pkey_value =
|
147
|
-
if pk_names.is_a?(Array)
|
148
|
-
parent.values_at(*pk_names)
|
149
|
-
else
|
150
|
-
parent[pk_names]
|
151
|
-
end
|
152
|
-
|
153
|
-
cache[key][child_keys] ||= children.group_by do |child|
|
154
|
-
if child_keys.is_a?(Array)
|
155
|
-
child.values_at(*child_keys)
|
156
|
-
else
|
157
|
-
child[child_keys]
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
child_arr = cache[key][child_keys][pkey_value] || []
|
162
|
-
|
163
|
-
child_hash[key] = child_arr
|
164
|
-
end
|
165
|
-
|
166
|
-
parent.merge(child_hash)
|
167
|
-
end
|
122
|
+
def self.combine(array, mappings)
|
123
|
+
Combine.combine(array, mappings)
|
168
124
|
end
|
169
125
|
|
170
126
|
# Converts the array of hashes to array of values, extracted by given key
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Transproc
|
2
|
+
module ArrayTransformations
|
3
|
+
class Combine
|
4
|
+
class << self
|
5
|
+
def combine(array, mappings)
|
6
|
+
root, nodes = array
|
7
|
+
return root if nodes.nil?
|
8
|
+
groups = group_nodes(nodes, mappings)
|
9
|
+
|
10
|
+
root.map do |element|
|
11
|
+
element.dup.tap { |copy| add_groups_to_element(copy, groups, mappings) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def add_groups_to_element(element, groups, mappings)
|
18
|
+
groups.each_with_index do |candidates, index|
|
19
|
+
mapping = mappings[index]
|
20
|
+
resource_key = mapping[0]
|
21
|
+
element[resource_key] = element_candidates(element, candidates, mapping[1].keys)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def element_candidates(element, candidates, keys)
|
26
|
+
candidates[element_candidates_key(element, keys)] || []
|
27
|
+
end
|
28
|
+
|
29
|
+
def group_nodes(nodes, mappings)
|
30
|
+
nodes.each_with_index.map do |candidates, index|
|
31
|
+
mapping = mappings[index]
|
32
|
+
group_candidates(candidates, mapping)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def group_candidates(candidates, mapping)
|
37
|
+
nested_mapping = mapping[2]
|
38
|
+
candidates = combine(candidates, nested_mapping) unless nested_mapping.nil?
|
39
|
+
group_candidates_by_keys(candidates, mapping[1].values)
|
40
|
+
end
|
41
|
+
|
42
|
+
def group_candidates_by_keys(candidates, keys)
|
43
|
+
return candidates.group_by { |a| a.values_at(*keys) } if keys.size > 1
|
44
|
+
|
45
|
+
key = keys.first
|
46
|
+
candidates.group_by { |a| a[key] }
|
47
|
+
end
|
48
|
+
|
49
|
+
def element_candidates_key(element, keys)
|
50
|
+
return element.values_at(*keys) if keys.size > 1
|
51
|
+
element[keys.first]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/transproc/function.rb
CHANGED
data/lib/transproc/hash.rb
CHANGED
@@ -209,18 +209,26 @@ module Transproc
|
|
209
209
|
# @return [Hash]
|
210
210
|
#
|
211
211
|
# @api public
|
212
|
-
def self.nest(
|
213
|
-
|
212
|
+
def self.nest(hash, root, keys)
|
213
|
+
child = {}
|
214
214
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
215
|
+
keys.each do |key|
|
216
|
+
child[key] = hash[key] if hash.key?(key)
|
217
|
+
end
|
218
|
+
|
219
|
+
output = Hash[hash]
|
220
|
+
|
221
|
+
child.each_key { |key| output.delete(key) }
|
222
|
+
|
223
|
+
old_root = hash[root]
|
224
|
+
|
225
|
+
if old_root.is_a?(Hash)
|
226
|
+
output[root] = old_root.merge(child)
|
221
227
|
else
|
222
|
-
|
228
|
+
output[root] = child
|
223
229
|
end
|
230
|
+
|
231
|
+
output
|
224
232
|
end
|
225
233
|
|
226
234
|
# Collapse a nested hash from a specified key
|
data/lib/transproc/registry.rb
CHANGED
@@ -46,8 +46,9 @@ module Transproc
|
|
46
46
|
#
|
47
47
|
def [](fn, *args)
|
48
48
|
fetched = fetch(fn)
|
49
|
-
|
50
|
-
Function.new(fetched, args: args, name: fn)
|
49
|
+
|
50
|
+
return Function.new(fetched, args: args, name: fn) unless already_wrapped?(fetched)
|
51
|
+
args.empty? ? fetched : fetched.with(*args)
|
51
52
|
end
|
52
53
|
alias_method :t, :[]
|
53
54
|
|
data/lib/transproc/version.rb
CHANGED
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Transproc::ArrayTransformations do
|
4
|
+
describe '.combine' do
|
5
|
+
subject(:result) { described_class.t(:combine, mappings)[input] }
|
6
|
+
|
7
|
+
let(:input) { [[]] }
|
8
|
+
let(:mappings) { [] }
|
9
|
+
|
10
|
+
it { is_expected.to be_a(Array) }
|
11
|
+
|
12
|
+
it { is_expected.to eq([]) }
|
13
|
+
|
14
|
+
context 'without groups' do
|
15
|
+
let(:input) do
|
16
|
+
[
|
17
|
+
[
|
18
|
+
{name: 'Jane', email: 'jane@doe.org'}.freeze,
|
19
|
+
{name: 'Joe', email: 'joe@doe.org'}.freeze
|
20
|
+
].freeze
|
21
|
+
].freeze
|
22
|
+
end
|
23
|
+
|
24
|
+
it { is_expected.to eq input.first }
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'does not modify its input' do
|
28
|
+
input = [
|
29
|
+
[{ name: 'Jane' }],
|
30
|
+
[[{ user: 'Jane', title: 'One' }]]
|
31
|
+
]
|
32
|
+
|
33
|
+
output = [
|
34
|
+
{ name: 'Jane', tasks: [{ user: 'Jane', title: 'One' }] }
|
35
|
+
]
|
36
|
+
|
37
|
+
combined = described_class.combine(input, [[:tasks, name: :user]])
|
38
|
+
|
39
|
+
expect(combined).to eql(output)
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with one group' do
|
43
|
+
let(:input) do
|
44
|
+
[
|
45
|
+
[
|
46
|
+
{name: 'Jane', email: 'jane@doe.org'}.freeze,
|
47
|
+
{name: 'Joe', email: 'joe@doe.org'}.freeze
|
48
|
+
].freeze,
|
49
|
+
[
|
50
|
+
[
|
51
|
+
{user: 'Jane', title: 'One'}.freeze,
|
52
|
+
{user: 'Jane', title: 'Two'}.freeze,
|
53
|
+
{user: 'Joe', title: 'Three'}.freeze
|
54
|
+
]
|
55
|
+
]
|
56
|
+
].freeze
|
57
|
+
end
|
58
|
+
let(:mappings) { [[:tasks, {name: :user}]] }
|
59
|
+
|
60
|
+
it 'merges hashes from arrays using provided join keys' do
|
61
|
+
output = [
|
62
|
+
{name: 'Jane', email: 'jane@doe.org', tasks: [
|
63
|
+
{user: 'Jane', title: 'One'},
|
64
|
+
{user: 'Jane', title: 'Two'}
|
65
|
+
]},
|
66
|
+
{name: 'Joe', email: 'joe@doe.org', tasks: [
|
67
|
+
{user: 'Joe', title: 'Three'}
|
68
|
+
]}
|
69
|
+
]
|
70
|
+
is_expected.to eql(output)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with empty nodes' do
|
75
|
+
let(:input) do
|
76
|
+
[
|
77
|
+
[{name: 'Jane', email: 'jane@doe.org'}.freeze].freeze,
|
78
|
+
[
|
79
|
+
[]
|
80
|
+
]
|
81
|
+
].freeze
|
82
|
+
end
|
83
|
+
|
84
|
+
let(:mappings) { [[:tasks, {name: :user}]] }
|
85
|
+
|
86
|
+
it { is_expected.to eq([{name: 'Jane', email: 'jane@doe.org', tasks: []}]) }
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'with double mapping' do
|
90
|
+
let(:input) do
|
91
|
+
[
|
92
|
+
[
|
93
|
+
{name: 'Jane', email: 'jane@doe.org'}.freeze
|
94
|
+
].freeze,
|
95
|
+
[
|
96
|
+
[
|
97
|
+
{user: 'Jane', user_email: 'jane@doe.org', title: 'One'}.freeze,
|
98
|
+
{user: 'Jane', user_email: '', title: 'Two'}.freeze
|
99
|
+
].freeze
|
100
|
+
].freeze
|
101
|
+
].freeze
|
102
|
+
end
|
103
|
+
|
104
|
+
let(:mappings) { [[:tasks, {name: :user, email: :user_email}]] }
|
105
|
+
|
106
|
+
it 'searches by two keys simultaneously' do
|
107
|
+
output = [
|
108
|
+
{name: 'Jane', email: 'jane@doe.org', tasks: [
|
109
|
+
{user: 'Jane', user_email: 'jane@doe.org', title: 'One'}
|
110
|
+
]}
|
111
|
+
]
|
112
|
+
is_expected.to eql(output)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'integration test' do
|
117
|
+
let(:input) do
|
118
|
+
[
|
119
|
+
[
|
120
|
+
{name: 'Jane', email: 'jane@doe.org'},
|
121
|
+
{name: 'Joe', email: 'joe@doe.org'}
|
122
|
+
],
|
123
|
+
[
|
124
|
+
[
|
125
|
+
# user tasks
|
126
|
+
[
|
127
|
+
{user: 'Jane', title: 'One'},
|
128
|
+
{user: 'Jane', title: 'Two'},
|
129
|
+
{user: 'Joe', title: 'Three'}
|
130
|
+
],
|
131
|
+
[
|
132
|
+
# task tags
|
133
|
+
[
|
134
|
+
{task: 'One', tag: 'red'},
|
135
|
+
{task: 'Three', tag: 'blue'}
|
136
|
+
]
|
137
|
+
]
|
138
|
+
]
|
139
|
+
]
|
140
|
+
]
|
141
|
+
end
|
142
|
+
|
143
|
+
let(:mappings) { [[:tasks, {name: :user}, [[:tags, title: :task]]]] }
|
144
|
+
|
145
|
+
it 'merges hashes from arrays using provided join keys' do
|
146
|
+
output = [
|
147
|
+
{name: 'Jane', email: 'jane@doe.org', tasks: [
|
148
|
+
{user: 'Jane', title: 'One', tags: [{task: 'One', tag: 'red'}]},
|
149
|
+
{user: 'Jane', title: 'Two', tags: []}
|
150
|
+
]},
|
151
|
+
{
|
152
|
+
name: 'Joe', email: 'joe@doe.org', tasks: [
|
153
|
+
{
|
154
|
+
user: 'Joe', title: 'Three', tags: [
|
155
|
+
{task: 'Three', tag: 'blue'}
|
156
|
+
]
|
157
|
+
}
|
158
|
+
]
|
159
|
+
}
|
160
|
+
]
|
161
|
+
is_expected.to eql(output)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'merges hashes from arrays using provided join keys' do
|
166
|
+
input = [
|
167
|
+
# parent users
|
168
|
+
[
|
169
|
+
{ name: 'Jane', email: 'jane@doe.org' }.freeze,
|
170
|
+
{ name: 'Joe', email: 'joe@doe.org' }.freeze
|
171
|
+
].freeze,
|
172
|
+
[
|
173
|
+
[
|
174
|
+
# user tasks
|
175
|
+
[
|
176
|
+
{ user: 'Jane', title: 'One' }.freeze,
|
177
|
+
{ user: 'Jane', title: 'Two' }.freeze,
|
178
|
+
{ user: 'Joe', title: 'Three' }.freeze
|
179
|
+
].freeze,
|
180
|
+
[
|
181
|
+
# task tags
|
182
|
+
[
|
183
|
+
{ task: 'One', tag: 'red' }.freeze,
|
184
|
+
{ task: 'Three', tag: 'blue' }.freeze
|
185
|
+
].freeze
|
186
|
+
].freeze
|
187
|
+
].freeze
|
188
|
+
].freeze
|
189
|
+
].freeze
|
190
|
+
|
191
|
+
output = [
|
192
|
+
{ name: 'Jane', email: 'jane@doe.org', tasks: [
|
193
|
+
{ user: 'Jane', title: 'One', tags: [{ task: 'One', tag: 'red' }] },
|
194
|
+
{ user: 'Jane', title: 'Two', tags: [] }]
|
195
|
+
},
|
196
|
+
{
|
197
|
+
name: 'Joe', email: 'joe@doe.org', tasks: [
|
198
|
+
{
|
199
|
+
user: 'Joe', title: 'Three', tags: [
|
200
|
+
{ task: 'Three', tag: 'blue' }
|
201
|
+
]
|
202
|
+
}
|
203
|
+
]
|
204
|
+
}
|
205
|
+
]
|
206
|
+
|
207
|
+
combine = described_class.t(:combine, [
|
208
|
+
[:tasks, { name: :user }, [[:tags, title: :task]]]
|
209
|
+
])
|
210
|
+
|
211
|
+
expect(combine[input]).to eql(output)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -230,55 +230,4 @@ describe Transproc::ArrayTransformations do
|
|
230
230
|
expect(ungroup[input]).to eql(output)
|
231
231
|
end
|
232
232
|
end
|
233
|
-
|
234
|
-
describe '.combine' do
|
235
|
-
it 'merges hashes from arrays using provided join keys' do
|
236
|
-
input = [
|
237
|
-
# parent users
|
238
|
-
[
|
239
|
-
{ name: 'Jane', email: 'jane@doe.org' },
|
240
|
-
{ name: 'Joe', email: 'joe@doe.org' }
|
241
|
-
],
|
242
|
-
[
|
243
|
-
[
|
244
|
-
# user tasks
|
245
|
-
[
|
246
|
-
{ user: 'Jane', title: 'One' },
|
247
|
-
{ user: 'Jane', title: 'Two' },
|
248
|
-
{ user: 'Joe', title: 'Three' }
|
249
|
-
],
|
250
|
-
[
|
251
|
-
# task tags
|
252
|
-
[
|
253
|
-
{ task: 'One', tag: 'red' },
|
254
|
-
{ task: 'Three', tag: 'blue' }
|
255
|
-
]
|
256
|
-
]
|
257
|
-
]
|
258
|
-
]
|
259
|
-
]
|
260
|
-
|
261
|
-
output = [
|
262
|
-
{ name: 'Jane', email: 'jane@doe.org', tasks: [
|
263
|
-
{ user: 'Jane', title: 'One', tags: [{ task: 'One', tag: 'red' }] },
|
264
|
-
{ user: 'Jane', title: 'Two', tags: [] }]
|
265
|
-
},
|
266
|
-
{
|
267
|
-
name: 'Joe', email: 'joe@doe.org', tasks: [
|
268
|
-
{
|
269
|
-
user: 'Joe', title: 'Three', tags: [
|
270
|
-
{ task: 'Three', tag: 'blue' }
|
271
|
-
]
|
272
|
-
}
|
273
|
-
]
|
274
|
-
}
|
275
|
-
]
|
276
|
-
|
277
|
-
combine = described_class.t(:combine, [
|
278
|
-
[:tasks, { name: :user }, [[:tags, title: :task]]]
|
279
|
-
])
|
280
|
-
|
281
|
-
expect(combine[input]).to eql(output)
|
282
|
-
end
|
283
|
-
end
|
284
233
|
end
|
data/spec/unit/function_spec.rb
CHANGED
@@ -98,6 +98,21 @@ describe Transproc::Function do
|
|
98
98
|
expect(fn[:ok]).to eql('ok')
|
99
99
|
expect(fn.to_ast).to eql([:to_string, []])
|
100
100
|
end
|
101
|
+
|
102
|
+
it 'plays well with functions as arguments' do
|
103
|
+
container.register(:map_array, Transproc::ArrayTransformations.t(:map_array))
|
104
|
+
container.register(:to_symbol, Transproc::Coercions.t(:to_symbol))
|
105
|
+
fn = container.t(:map_array, container.t(:to_symbol))
|
106
|
+
|
107
|
+
expect(fn.call(%w(a b c))).to eql([:a, :b, :c])
|
108
|
+
expect(fn.to_ast).to eql(
|
109
|
+
[
|
110
|
+
:map_array, [
|
111
|
+
[:to_symbol, []]
|
112
|
+
]
|
113
|
+
]
|
114
|
+
)
|
115
|
+
end
|
101
116
|
end
|
102
117
|
|
103
118
|
describe '#==' do
|
data/spec/unit/registry_spec.rb
CHANGED
@@ -100,6 +100,14 @@ describe Transproc::Registry do
|
|
100
100
|
expect(foo[:prefix_one]).to eq function
|
101
101
|
end
|
102
102
|
|
103
|
+
it 'allows to overwrite function arguments' do
|
104
|
+
foo.register(:map_array, Transproc::ArrayTransformations.t(:map_array))
|
105
|
+
|
106
|
+
fn = foo[:map_array, ->(value) { value.to_sym }]
|
107
|
+
|
108
|
+
expect(fn.call(%w(a b c))).to eq([:a, :b, :c])
|
109
|
+
end
|
110
|
+
|
103
111
|
it 'registers and fetches composite' do
|
104
112
|
composite = foo[:prefix, '1'] + foo[:prefix, '2']
|
105
113
|
foo.register(:double_prefix, composite)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: transproc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-02-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -73,6 +73,7 @@ files:
|
|
73
73
|
- lib/transproc.rb
|
74
74
|
- lib/transproc/all.rb
|
75
75
|
- lib/transproc/array.rb
|
76
|
+
- lib/transproc/array/combine.rb
|
76
77
|
- lib/transproc/class.rb
|
77
78
|
- lib/transproc/coercions.rb
|
78
79
|
- lib/transproc/composer.rb
|
@@ -94,6 +95,7 @@ files:
|
|
94
95
|
- rakelib/rubocop.rake
|
95
96
|
- spec/spec_helper.rb
|
96
97
|
- spec/support/mutant.rb
|
98
|
+
- spec/unit/array/combine_spec.rb
|
97
99
|
- spec/unit/array_transformations_spec.rb
|
98
100
|
- spec/unit/class_transformations_spec.rb
|
99
101
|
- spec/unit/coercions_spec.rb
|
@@ -129,13 +131,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
131
|
version: '0'
|
130
132
|
requirements: []
|
131
133
|
rubyforge_project:
|
132
|
-
rubygems_version: 2.
|
134
|
+
rubygems_version: 2.6.9
|
133
135
|
signing_key:
|
134
136
|
specification_version: 4
|
135
137
|
summary: Transform Ruby objects in functional style
|
136
138
|
test_files:
|
137
139
|
- spec/spec_helper.rb
|
138
140
|
- spec/support/mutant.rb
|
141
|
+
- spec/unit/array/combine_spec.rb
|
139
142
|
- spec/unit/array_transformations_spec.rb
|
140
143
|
- spec/unit/class_transformations_spec.rb
|
141
144
|
- spec/unit/coercions_spec.rb
|