transproc 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8df075878909a89bb9304ac442044a20d768860b
4
- data.tar.gz: 2ebde290094e7cf302891f536c043af3c933f6b3
3
+ metadata.gz: a5ce7c814504a4dbdb337c06e34e0d8ba76240c2
4
+ data.tar.gz: 7634b2a430e84411fdf9b3454f8a9e530167efef
5
5
  SHA512:
6
- metadata.gz: 5baa7f8034bb8e727c1a0f8870a4f5e9f5ec9c9d4f04ad39400572473fa543aca6ab6540ba6658a75570acf068010f0637102ac973772e349cc8a59949c602d8
7
- data.tar.gz: 86a696d76233333a933bec5fd4ac83052cc4ce04bab8ae9bb9c11204caae818fa9020392846ff7a948b3c30fdaaa28257cad8448cf46a0d90a3a166b26b4962c
6
+ metadata.gz: 03cdc29204c0aeec12217dfc88a838d052fa3dbed8be7b66c1c8326ccd09bb9a0a2445dd4c535916da0e0fa2546340882867adcc897586e1e0f2b42244cf1c74
7
+ data.tar.gz: a0c2124b3455b1d240a27420214a0ba5b31c8114a2002032fba26e02938fdb1ed99183a2b4a01bfdc250e16fd58a06b92612a78f5b7c8e017e95ab20bf6efabe
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --color
2
2
  --require spec_helper
3
+ --warnings
@@ -1,3 +1,19 @@
1
+ ## v0.2.3 2015-06-02
2
+
3
+ ### Added
4
+
5
+ * `:split` splits a hash to array by a list of values from a specified key of the hash (nepalez)
6
+ * `:ungroup` is an inverse array transormation with respect to the `:group` (nepalez)
7
+ * `:insert_key` (and `:insert_key!`) is the partial inversion of `:extract_key`.
8
+ The method converts array of values into array of tuples with given key (nepalez)
9
+ * `:add_keys` (and `:add_keys!`) adds missing keys to all tuples in array (nepalez)
10
+
11
+ ### Fixed
12
+
13
+ * Warning about circular requires is gone now (splattael)
14
+
15
+ [Compare v0.2.2...v0.2.3](https://github.com/solnic/transproc/compare/v0.2.2...v0.2.3)
16
+
1
17
  ## v0.2.2 2015-05-22
2
18
 
3
19
  ### Added
@@ -1,5 +1,6 @@
1
1
  require 'transproc/version'
2
2
  require 'transproc/function'
3
+ require 'transproc/functions'
3
4
  require 'transproc/composer'
4
5
  require 'transproc/error'
5
6
 
@@ -42,29 +43,11 @@ module Transproc
42
43
  def functions
43
44
  @_functions ||= {}
44
45
  end
45
-
46
- # Function container extension
47
- #
48
- # @example
49
- # module MyTransformations
50
- # extend Transproc::Functions
51
- #
52
- # def boom!(value)
53
- # "#{value} BOOM!"
54
- # end
55
- # end
56
- #
57
- # Transproc(:boom!)['w00t!'] # => "w00t! BOOM!"
58
- #
59
- # @api public
60
- module Functions
61
- def method_added(meth)
62
- module_function meth
63
- Transproc.register(meth, method(meth))
64
- end
65
- end
66
46
  end
67
47
 
48
+ require 'transproc/array'
49
+ require 'transproc/hash'
50
+
68
51
  # Access registered functions
69
52
  #
70
53
  # @example
@@ -1,5 +1,3 @@
1
- require 'transproc/hash'
2
-
3
1
  module Transproc
4
2
  # Transformation functions for Array objects
5
3
  #
@@ -99,6 +97,30 @@ module Transproc
99
97
  end
100
98
  end
101
99
 
100
+ # Ungroup array values using provided root key and value keys
101
+ #
102
+ # @example
103
+ # fn = Transproc(:group, :tags, [:tag_name])
104
+ #
105
+ # fn.call [
106
+ # { task: 'Group it', tags: [{ tag: 'task' }, { tag: 'important' }]
107
+ # ]
108
+ # # => [
109
+ # { task: 'Group it', tag: 'task' },
110
+ # { task: 'Group it', tag: 'important' }
111
+ # ]
112
+ #
113
+ # @param [Array] array The input array
114
+ # @param [Object] key The nesting root key
115
+ # @param [Object] keys The nesting value keys
116
+ #
117
+ # @return [Array]
118
+ #
119
+ # @api public
120
+ def ungroup(array, key, keys)
121
+ array.flat_map { |item| HashTransformations.split(item, key, keys) }
122
+ end
123
+
102
124
  # Combines two arrays by merging child items from right array using join keys
103
125
  #
104
126
  # @example
@@ -175,5 +197,55 @@ module Transproc
175
197
  def extract_key!(array, key)
176
198
  map_array!(array, -> v { v[key] })
177
199
  end
200
+
201
+ # Wraps every value of the array to tuple with given key
202
+ #
203
+ # The transformation partially inverses the `extract_key`.
204
+ #
205
+ # @example
206
+ # fn = t(:insert_key, 'name')
207
+ # fn.call ['Alice', 'Bob', nil]
208
+ # # => [{ 'name' => 'Alice' }, { 'name' => 'Bob' }, { 'name' => nil }]
209
+ #
210
+ # @param [Array<Hash>] array The input array of hashes
211
+ # @param [Object] key The key to extract values by
212
+ #
213
+ # @return [Array]
214
+ #
215
+ # @api public
216
+ def insert_key(array, key)
217
+ insert_key!(Array[*array], key)
218
+ end
219
+
220
+ # Same as `insert_key` but mutates the array
221
+ #
222
+ # @see ArrayTransformations.insert_key
223
+ #
224
+ # @api public
225
+ def insert_key!(array, key)
226
+ map_array!(array, -> v { { key => v } })
227
+ end
228
+
229
+ # Adds missing keys with nil value to all tuples in array
230
+ #
231
+ # @param [Array] keys
232
+ #
233
+ # @return [Array]
234
+ #
235
+ # @api public
236
+ #
237
+ def add_keys(array, keys)
238
+ add_keys!(Array[*array], keys)
239
+ end
240
+
241
+ # Same as `add_keys` but mutates the array
242
+ #
243
+ # @see ArrayTransformations.add_keys
244
+ #
245
+ # @api public
246
+ def add_keys!(array, keys)
247
+ base = keys.inject({}) { |a, e| a.merge(e => nil) }
248
+ map_array!(array, -> v { base.merge(v) })
249
+ end
178
250
  end
179
251
  end
@@ -0,0 +1,22 @@
1
+ module Transproc
2
+ # Function container extension
3
+ #
4
+ # @example
5
+ # module MyTransformations
6
+ # extend Transproc::Functions
7
+ #
8
+ # def boom!(value)
9
+ # "#{value} BOOM!"
10
+ # end
11
+ # end
12
+ #
13
+ # Transproc(:boom!)['w00t!'] # => "w00t! BOOM!"
14
+ #
15
+ # @api public
16
+ module Functions
17
+ def method_added(meth)
18
+ module_function meth
19
+ Transproc.register(meth, method(meth))
20
+ end
21
+ end
22
+ end
@@ -1,4 +1,3 @@
1
- require 'transproc/array'
2
1
  require 'transproc/coercions'
3
2
 
4
3
  module Transproc
@@ -146,15 +145,6 @@ module Transproc
146
145
  hash
147
146
  end
148
147
 
149
- # Same as `:reject_keys` but mutates the hash
150
- #
151
- # @see HashTransformations.reject_keys
152
- #
153
- # @api public
154
- def reject_keys!(hash, keys)
155
- hash.reject { |k, _| keys.include?(k) }
156
- end
157
-
158
148
  # Rejects specified keys from a hash
159
149
  #
160
150
  # @example
@@ -171,13 +161,13 @@ module Transproc
171
161
  reject_keys!(Hash[hash], keys)
172
162
  end
173
163
 
174
- # Same as `:accept_keys` but mutates the hash
164
+ # Same as `:reject_keys` but mutates the hash
175
165
  #
176
166
  # @see HashTransformations.reject_keys
177
167
  #
178
168
  # @api public
179
- def accept_keys!(hash, keys)
180
- reject_keys!(hash, hash.keys - keys)
169
+ def reject_keys!(hash, keys)
170
+ hash.reject { |k, _| keys.include?(k) }
181
171
  end
182
172
 
183
173
  # Accepts specified keys from a hash
@@ -196,6 +186,15 @@ module Transproc
196
186
  accept_keys!(Hash[hash], keys)
197
187
  end
198
188
 
189
+ # Same as `:accept_keys` but mutates the hash
190
+ #
191
+ # @see HashTransformations.accept
192
+ #
193
+ # @api public
194
+ def accept_keys!(hash, keys)
195
+ reject_keys!(hash, hash.keys - keys)
196
+ end
197
+
199
198
  # Map a key in a hash with the provided transformation function
200
199
  #
201
200
  # @example
@@ -213,7 +212,7 @@ module Transproc
213
212
 
214
213
  # Same as `:map_value` but mutates the hash
215
214
  #
216
- # @see HashTransformations.map_value!
215
+ # @see HashTransformations.map_value
217
216
  #
218
217
  # @api public
219
218
  def map_value!(hash, key, fn)
@@ -272,9 +271,10 @@ module Transproc
272
271
  # @see HashTransformations.unwrap
273
272
  #
274
273
  # @api public
275
- def unwrap!(hash, root, keys = nil)
274
+ def unwrap!(hash, root, selected = nil)
276
275
  if nested_hash = hash[root]
277
- keys ||= nested_hash.keys
276
+ keys = nested_hash.keys
277
+ keys &= selected if selected
278
278
  hash.update(Hash[keys.zip(keys.map { |key| nested_hash.delete(key) })])
279
279
  hash.delete(root) if nested_hash.empty?
280
280
  end
@@ -284,8 +284,6 @@ module Transproc
284
284
 
285
285
  # Folds array of tuples to array of values from a specified key
286
286
  #
287
- # The second argument defines the key to fold tuples by
288
- #
289
287
  # @example
290
288
  # source = {
291
289
  # name: "Jane",
@@ -296,7 +294,9 @@ module Transproc
296
294
  # Transproc(:fold, :tasks, :priority)[source]
297
295
  # # => { name: "Jane", tasks: [1, nil] }
298
296
  #
299
- # @param [Hash]
297
+ # @param [Hash] hash
298
+ # @param [Object] key The key to fold values to
299
+ # @param [Object] tuple_key The key to take folded values from
300
300
  #
301
301
  # @return [Hash]
302
302
  #
@@ -313,5 +313,46 @@ module Transproc
313
313
  def fold!(hash, key, tuple_key)
314
314
  hash.merge!(key => ArrayTransformations.extract_key(hash[key], tuple_key))
315
315
  end
316
+
317
+ # Splits hash to array by all values from a specified key
318
+ #
319
+ # The operation adds missing keys extracted from the array to regularize the output.
320
+ #
321
+ # @example
322
+ # input = {
323
+ # name: 'Joe',
324
+ # tasks: [
325
+ # { title: 'sleep well', priority: 1 },
326
+ # { title: 'be nice', priority: 2 },
327
+ # { priority: 2 },
328
+ # { title: 'be cool' }
329
+ # ]
330
+ # }
331
+ # Transproc(:split, :tasks, [:priority])
332
+ # => [
333
+ # { name: 'Joe', priority: 1, tasks: [{ title: 'sleep well' }] },
334
+ # { name: 'Joe', priority: 2, tasks: [{ title: 'be nice' }, { title: nil }] },
335
+ # { name: 'Joe', priority: nil, tasks: [{ title: 'be cool' }] }
336
+ # ]
337
+ #
338
+ # @param [Hash] hash
339
+ # @param [Object] key The key to split a hash by
340
+ # @param [Array] subkeys The list of subkeys to be extracted from key
341
+ #
342
+ # @return [Array<Hash>]
343
+ #
344
+ # @api public
345
+ def split(hash, key, keys)
346
+ list = Array(hash[key])
347
+ return [hash.reject { |k, _| k == key }] if list.empty?
348
+
349
+ existing = list.flat_map(&:keys).uniq
350
+ grouped = existing - keys
351
+ ungrouped = existing & keys
352
+
353
+ list = ArrayTransformations.group(list, key, grouped) if grouped.any?
354
+ list = list.map { |item| item.merge(reject_keys(hash, [key])) }
355
+ ArrayTransformations.add_keys(list, ungrouped)
356
+ end
316
357
  end
317
358
  end
@@ -1,3 +1,3 @@
1
1
  module Transproc
2
- VERSION = '0.2.2'.freeze
2
+ VERSION = '0.2.3'.freeze
3
3
  end
@@ -37,6 +37,80 @@ describe Transproc::ArrayTransformations do
37
37
  end
38
38
  end
39
39
 
40
+ describe '.insert_key' do
41
+ it 'wraps values to tuples with given key' do
42
+ insert_key = t(:insert_key, 'name')
43
+
44
+ original = ['Alice', 'Bob', nil]
45
+
46
+ input = original
47
+
48
+ output = [
49
+ { 'name' => 'Alice' },
50
+ { 'name' => 'Bob' },
51
+ { 'name' => nil }
52
+ ]
53
+
54
+ expect(insert_key[input]).to eql(output)
55
+ expect(input).to eql(original)
56
+ end
57
+ end
58
+
59
+ describe '.insert_key!' do
60
+ it 'wraps values to tuples with given key' do
61
+ insert_key = t(:insert_key!, 'name')
62
+
63
+ original = ['Alice', 'Bob', nil]
64
+
65
+ input = original
66
+
67
+ output = [
68
+ { 'name' => 'Alice' },
69
+ { 'name' => 'Bob' },
70
+ { 'name' => nil }
71
+ ]
72
+
73
+ expect(insert_key[input]).to eql(output)
74
+ expect(input).to eql(output)
75
+ end
76
+ end
77
+
78
+ describe '.add_keys' do
79
+ it 'returns a new array with missed keys added to tuples' do
80
+ add_keys = t(:add_keys, [:foo, :bar, :baz])
81
+
82
+ original = [{ foo: 'bar' }, { bar: 'baz' }]
83
+
84
+ input = original
85
+
86
+ output = [
87
+ { foo: 'bar', bar: nil, baz: nil },
88
+ { foo: nil, bar: 'baz', baz: nil }
89
+ ]
90
+
91
+ expect(add_keys[input]).to eql(output)
92
+ expect(input).to eql(original)
93
+ end
94
+ end
95
+
96
+ describe '.add_keys!' do
97
+ it 'adds missed keys to tuples' do
98
+ add_keys = t(:add_keys!, [:foo, :bar, :baz])
99
+
100
+ original = [{ foo: 'bar' }, { bar: 'baz' }]
101
+
102
+ input = original
103
+
104
+ output = [
105
+ { foo: 'bar', bar: nil, baz: nil },
106
+ { foo: nil, bar: 'baz', baz: nil }
107
+ ]
108
+
109
+ expect(add_keys[input]).to eql(output)
110
+ expect(input).to eql(output)
111
+ end
112
+ end
113
+
40
114
  describe '.map_array' do
41
115
  it 'applies funtions to all values' do
42
116
  map = t(:map_array, t(:symbolize_keys))
@@ -114,6 +188,31 @@ describe Transproc::ArrayTransformations do
114
188
  end
115
189
  end
116
190
 
191
+ describe '.ungroup' do
192
+ subject(:ungroup) { t(:ungroup, :tasks, [:title]) }
193
+
194
+ it 'returns a new array with ungrouped hashes' do
195
+ input = [{ name: 'Jane', tasks: [{ title: 'One' }, { title: 'Two' }] }]
196
+ output = [{ name: 'Jane', title: 'One' }, { name: 'Jane', title: 'Two' }]
197
+
198
+ expect(ungroup[input]).to eql(output)
199
+ end
200
+
201
+ it 'returns an input with empty array removed' do
202
+ input = [{ name: 'Jane', tasks: [] }]
203
+ output = [{ name: 'Jane' }]
204
+
205
+ expect(ungroup[input]).to eql(output)
206
+ end
207
+
208
+ it 'returns an input when a key is absent' do
209
+ input = [{ name: 'Jane' }]
210
+ output = [{ name: 'Jane' }]
211
+
212
+ expect(ungroup[input]).to eql(output)
213
+ end
214
+ end
215
+
117
216
  describe '.combine' do
118
217
  let(:input) do
119
218
  [
@@ -206,6 +206,17 @@ describe Transproc::HashTransformations do
206
206
 
207
207
  expect(input).to eql(output)
208
208
  end
209
+
210
+ it 'ignores unknown keys' do
211
+ unwrap = t(:unwrap!, 'wrapped', %w(one two three))
212
+
213
+ input = { 'wrapped' => { 'one' => nil, 'two' => false } }
214
+ output = { 'one' => nil, 'two' => false }
215
+
216
+ unwrap[input]
217
+
218
+ expect(input).to eql(output)
219
+ end
209
220
  end
210
221
 
211
222
  describe '.unwrap' do
@@ -354,4 +365,88 @@ describe Transproc::HashTransformations do
354
365
  expect(input).to eql output
355
366
  end
356
367
  end
368
+
369
+ describe '.split' do
370
+ let(:input) do
371
+ {
372
+ name: 'Joe',
373
+ tasks: [
374
+ { title: 'sleep well', priority: 1 },
375
+ { title: 'be nice', priority: 2 },
376
+ { priority: 2 },
377
+ { title: 'be cool' },
378
+ {}
379
+ ]
380
+ }
381
+ end
382
+
383
+ it 'splits a tuple into array partially by given keys' do
384
+ split = t(:split, :tasks, [:priority])
385
+
386
+ output = [
387
+ {
388
+ name: 'Joe', priority: 1,
389
+ tasks: [{ title: 'sleep well' }]
390
+ },
391
+ {
392
+ name: 'Joe', priority: 2,
393
+ tasks: [{ title: 'be nice' }, { title: nil }]
394
+ },
395
+ {
396
+ name: 'Joe', priority: nil,
397
+ tasks: [{ title: 'be cool' }, { title: nil }]
398
+ }
399
+ ]
400
+
401
+ expect(split[input]).to eql output
402
+ end
403
+
404
+ it 'splits a tuple into array fully by all subkeys' do
405
+ split = t(:split, :tasks, [:priority, :title])
406
+
407
+ output = [
408
+ { name: 'Joe', title: 'sleep well', priority: 1 },
409
+ { name: 'Joe', title: 'be nice', priority: 2 },
410
+ { name: 'Joe', title: nil, priority: 2 },
411
+ { name: 'Joe', title: 'be cool', priority: nil },
412
+ { name: 'Joe', title: nil, priority: nil }
413
+ ]
414
+
415
+ expect(split[input]).to eql output
416
+ end
417
+
418
+ it 'returns an array of one tuple with updated keys when there is nothing to split by' do
419
+ output = [
420
+ {
421
+ name: 'Joe',
422
+ tasks: [
423
+ { title: 'sleep well', priority: 1 },
424
+ { title: 'be nice', priority: 2 },
425
+ { title: nil, priority: 2 },
426
+ { title: 'be cool', priority: nil },
427
+ { title: nil, priority: nil }
428
+ ]
429
+ }
430
+ ]
431
+
432
+ split = t(:split, :tasks, [])
433
+ expect(split[input]).to eql output
434
+
435
+ split = t(:split, :tasks, [:absent])
436
+ expect(split[input]).to eql output
437
+ end
438
+
439
+ it 'returns an array of initial tuple when attribute is absent' do
440
+ split = t(:split, :absent, [:priority, :title])
441
+ expect(split[input]).to eql [input]
442
+ end
443
+
444
+ it 'ignores empty array' do
445
+ input = { name: 'Joe', tasks: [] }
446
+
447
+ split = t(:split, :tasks, [:title])
448
+
449
+ expect(split[input]).to eql [{ name: 'Joe' }]
450
+ end
451
+ end
357
452
  end
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: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-22 00:00:00.000000000 Z
11
+ date: 2015-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,7 @@ files:
80
80
  - lib/transproc/conditional.rb
81
81
  - lib/transproc/error.rb
82
82
  - lib/transproc/function.rb
83
+ - lib/transproc/functions.rb
83
84
  - lib/transproc/hash.rb
84
85
  - lib/transproc/recursion.rb
85
86
  - lib/transproc/version.rb