transproc 0.3.0 → 0.3.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 +13 -1
- data/README.md +17 -10
- data/lib/transproc/coercions.rb +18 -3
- data/lib/transproc/composer.rb +0 -9
- data/lib/transproc/conditional.rb +17 -0
- data/lib/transproc/function.rb +8 -0
- data/lib/transproc/hash.rb +26 -0
- data/lib/transproc/registry.rb +21 -35
- data/lib/transproc/rspec.rb +26 -21
- data/lib/transproc/store.rb +37 -27
- data/lib/transproc/version.rb +1 -1
- data/spec/unit/coercions_spec.rb +16 -0
- data/spec/unit/conditional_spec.rb +23 -0
- data/spec/unit/function_spec.rb +41 -0
- data/spec/unit/hash_transformations_spec.rb +43 -3
- data/spec/unit/registry_spec.rb +11 -0
- data/spec/unit/store_spec.rb +15 -1
- data/spec/unit/transproc_spec.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03da4ea0974d24e43c94ab16d920532aa9703e9d
|
4
|
+
data.tar.gz: 5d0065ee097e3574e069062388f810ed0b81b108
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd79715c818c4161a4dbb574f8c2e359326a75739395f6ee1207dac1ffb40a138062090e2a1e94e6784ebc59dd46b8c1e036a149847ba5665ebf2635d7a53181
|
7
|
+
data.tar.gz: 915a231c2730edd26900c1ec7db8cacd5b0d7a1abc557f2e096334cf5e2092951b41b1c21239b173f257403ee42c03ffba2083dc59a31eaf5c2f9c3bddf0ee92
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## v0.3.1 2015-08-06
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* `:deep_merge` in `HashTransformations` (saturnflyer)
|
6
|
+
* `Transproc::Function#to_proc` method (nepalez)
|
7
|
+
* `to_boolean` coercion turns `nil` into `false` (c0)
|
8
|
+
* Support symbolizing non-string values by `Coercions[:to_symbol]` and `HashTransformations[:symbolize_keys]` (nepalez)
|
9
|
+
* Support for importing several functions at once `import :foo, :bar, from: Foo` (nepalez)
|
10
|
+
|
11
|
+
[Compare v0.3.0...v0.3.1](https://github.com/solnic/transproc/compare/v0.3.0...v0.3.1)
|
12
|
+
|
1
13
|
## v0.3.0 2015-07-12
|
2
14
|
|
3
15
|
This release deprecates a couple of APIs and changes the way functions can be
|
@@ -26,7 +38,7 @@ in 1.0.0.
|
|
26
38
|
* `Transproc()` has been deprecated (solnic)
|
27
39
|
* `Transproc::Helper` has been deprecated (solnic)
|
28
40
|
|
29
|
-
[Compare v0.2.4...
|
41
|
+
[Compare v0.2.4...v0.3.0](https://github.com/solnic/transproc/compare/v0.2.4...v0.3.0)
|
30
42
|
|
31
43
|
## v0.2.4 2015-06-20
|
32
44
|
|
data/README.md
CHANGED
@@ -14,8 +14,9 @@
|
|
14
14
|
[![Test Coverage](https://codeclimate.com/github/solnic/transproc/badges/coverage.svg)][codeclimate]
|
15
15
|
[![Inline docs](http://inch-ci.org/github/solnic/transproc.svg?branch=master)][inchpages]
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
Transproc is a small library that allows you to compose methods into a functional pipeline using left-to-right function composition. It works like `|>` in Elixir or `>>` in F#.
|
18
|
+
|
19
|
+
It's currently used as the data mapping backend in [Ruby Object Mapper](http://rom-rb.org).
|
19
20
|
|
20
21
|
## Installation
|
21
22
|
|
@@ -47,23 +48,27 @@ end
|
|
47
48
|
|
48
49
|
# import necessary functions from external modules
|
49
50
|
module Functions
|
50
|
-
# ...
|
51
|
-
|
52
51
|
# all transformations available in the imported module
|
53
|
-
import Transproc::
|
52
|
+
import Transproc::HashTransformations
|
54
53
|
import Transproc::ArrayTransformations
|
55
54
|
|
56
55
|
# only specific transformation (renamed into the desired local name)
|
57
56
|
import :camelize, from: Inflecto, as: :camel_case
|
58
57
|
end
|
59
58
|
|
59
|
+
def t(*args)
|
60
|
+
Functions[*args]
|
61
|
+
end
|
62
|
+
|
60
63
|
# use imported transformation
|
61
|
-
transformation =
|
64
|
+
transformation = t(:camel_case)
|
65
|
+
|
62
66
|
transformation.call 'i_am_a_camel'
|
63
67
|
# => "IAmACamel"
|
64
68
|
|
65
|
-
transformation =
|
66
|
-
transformation >>=
|
69
|
+
transformation = t(:map_array, t(:symbolize_keys) >> t(:rename_keys, user_name: :user))
|
70
|
+
transformation >>= t(:wrap, :address, [:city, :street, :zipcode])
|
71
|
+
|
67
72
|
transformation.call(
|
68
73
|
[
|
69
74
|
{ 'user_name' => 'Jane',
|
@@ -75,7 +80,8 @@ transformation.call(
|
|
75
80
|
# => [{:user=>"Jane", :address=>{:city=>"NYC", :street=>"Street 1", :zipcode=>"123"}}]
|
76
81
|
|
77
82
|
# define your own composable transformation easily
|
78
|
-
transformation =
|
83
|
+
transformation = t(-> v { JSON.dump(v) })
|
84
|
+
|
79
85
|
transformation.call(name: 'Jane')
|
80
86
|
# => "{\"name\":\"Jane\"}"
|
81
87
|
|
@@ -88,7 +94,8 @@ module Functions
|
|
88
94
|
end
|
89
95
|
end
|
90
96
|
|
91
|
-
transformation =
|
97
|
+
transformation = t(:load_json) >> t(:map_array, t(:symbolize_keys))
|
98
|
+
|
92
99
|
transformation.call('[{"name":"Jane"}]')
|
93
100
|
# => [{ :name => "Jane" }]
|
94
101
|
```
|
data/lib/transproc/coercions.rb
CHANGED
@@ -11,12 +11,27 @@ module Transproc
|
|
11
11
|
extend Registry
|
12
12
|
|
13
13
|
TRUE_VALUES = [true, 1, '1', 'on', 't', 'true', 'y', 'yes'].freeze
|
14
|
-
FALSE_VALUES = [false, 0, '0', 'off', 'f', 'false', 'n', 'no'].freeze
|
14
|
+
FALSE_VALUES = [false, 0, '0', 'off', 'f', 'false', 'n', 'no', nil].freeze
|
15
15
|
|
16
16
|
BOOLEAN_MAP = Hash[
|
17
17
|
TRUE_VALUES.product([true]) + FALSE_VALUES.product([false])
|
18
18
|
].freeze
|
19
19
|
|
20
|
+
# Does nothing and returns a value
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# fn = Coercions[:identity]
|
24
|
+
# fn[:foo] # => :foo
|
25
|
+
#
|
26
|
+
# @param [Object] value
|
27
|
+
#
|
28
|
+
# @return [Object]
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
def self.identity(value = nil)
|
32
|
+
value
|
33
|
+
end
|
34
|
+
|
20
35
|
# Coerce value into a string
|
21
36
|
#
|
22
37
|
# @example
|
@@ -38,13 +53,13 @@ module Transproc
|
|
38
53
|
# Transproc(:to_symbol)['foo']
|
39
54
|
# # => :foo
|
40
55
|
#
|
41
|
-
# @param [
|
56
|
+
# @param [#to_s] value The input value
|
42
57
|
#
|
43
58
|
# @return [Symbol]
|
44
59
|
#
|
45
60
|
# @api public
|
46
61
|
def self.to_symbol(value)
|
47
|
-
value.to_sym
|
62
|
+
value.to_s.to_sym
|
48
63
|
end
|
49
64
|
|
50
65
|
# Coerce value into a integer
|
data/lib/transproc/composer.rb
CHANGED
@@ -19,15 +19,6 @@ module Transproc
|
|
19
19
|
super
|
20
20
|
end
|
21
21
|
|
22
|
-
# @api private
|
23
|
-
def self.included(*)
|
24
|
-
Transproc::Deprecations.announce(
|
25
|
-
'Transproc::Helper',
|
26
|
-
'Define your own function registry using Transproc::Registry extension'
|
27
|
-
)
|
28
|
-
super
|
29
|
-
end
|
30
|
-
|
31
22
|
# @see Transproc
|
32
23
|
#
|
33
24
|
# @api public
|
@@ -15,6 +15,23 @@ module Transproc
|
|
15
15
|
module Conditional
|
16
16
|
extend Registry
|
17
17
|
|
18
|
+
# Negates the result of transformation
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# fn = Conditional[:not, -> value { value.is_a? ::String }]
|
22
|
+
# fn[:foo] # => true
|
23
|
+
# fn["foo"] # => false
|
24
|
+
#
|
25
|
+
# @param [Object] value
|
26
|
+
# @param [Proc] fn
|
27
|
+
#
|
28
|
+
# @return [Boolean]
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
def self.not(value, fn)
|
32
|
+
!fn[value]
|
33
|
+
end
|
34
|
+
|
18
35
|
# Apply the transformation function to subject if the predicate returns true, or return un-modified
|
19
36
|
#
|
20
37
|
# @example
|
data/lib/transproc/function.rb
CHANGED
data/lib/transproc/hash.rb
CHANGED
@@ -429,6 +429,32 @@ module Transproc
|
|
429
429
|
end
|
430
430
|
end
|
431
431
|
|
432
|
+
# Merge a hash recursively
|
433
|
+
#
|
434
|
+
# @example
|
435
|
+
#
|
436
|
+
# input = { 'foo' => 'bar', 'baz' => { 'one' => 1 } }
|
437
|
+
# other = { 'foo' => 'buz', 'baz' => { :one => 'one', :two => 2 } }
|
438
|
+
#
|
439
|
+
# t(:deep_merge)[input, other]
|
440
|
+
# # => { 'foo' => "buz", :baz => { :one => 'one', 'one' => 1, :two => 2 } }
|
441
|
+
#
|
442
|
+
# @param [Hash]
|
443
|
+
# @param [Hash]
|
444
|
+
#
|
445
|
+
# @return [Hash]
|
446
|
+
#
|
447
|
+
# @api public
|
448
|
+
def self.deep_merge(hash, other)
|
449
|
+
Hash[hash].merge(other) do |key, original_value, new_value|
|
450
|
+
if original_value.respond_to?(:to_hash) && new_value.respond_to?(:to_hash)
|
451
|
+
deep_merge(Hash[original_value], Hash[new_value])
|
452
|
+
else
|
453
|
+
new_value
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
432
458
|
# @deprecated Register methods globally
|
433
459
|
(methods - Registry.instance_methods - Registry.methods)
|
434
460
|
.each { |name| Transproc.register name, t(name) }
|
data/lib/transproc/registry.rb
CHANGED
@@ -54,46 +54,32 @@ module Transproc
|
|
54
54
|
#
|
55
55
|
# If the external module is a registry, looks for its imports too.
|
56
56
|
#
|
57
|
-
# @
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
# import :foo, from: Foo, as: :baz
|
78
|
-
# import :bar, from: Foo
|
79
|
-
# import Qux
|
80
|
-
# end
|
81
|
-
#
|
82
|
-
# Bar[:baz]['Qux'] # => 'QUX'
|
83
|
-
# Bar[:bar]['Qux'] # => 'qux'
|
84
|
-
# Bar[:qux]['Qux'] # => 'xuQ'
|
85
|
-
#
|
86
|
-
# @param [Module, #to_sym] name
|
87
|
-
# @option [Module] :from The module to take the method from
|
88
|
-
# @option [#to_sym] :as
|
89
|
-
# The name of imported transproc inside the current module
|
57
|
+
# @overload import(source)
|
58
|
+
# Loads all methods from the source object
|
59
|
+
#
|
60
|
+
# @param [Object] source
|
61
|
+
#
|
62
|
+
# @overload import(*names, **options)
|
63
|
+
# Loads selected methods from the source object
|
64
|
+
#
|
65
|
+
# @param [Array<Symbol>] names
|
66
|
+
# @param [Hash] options
|
67
|
+
# @options options [Object] :from The source object
|
68
|
+
#
|
69
|
+
# @overload import(name, **options)
|
70
|
+
# Loads selected methods from the source object
|
71
|
+
#
|
72
|
+
# @param [Symbol] name
|
73
|
+
# @param [Hash] options
|
74
|
+
# @options options [Object] :from The source object
|
75
|
+
# @options options [Object] :as The new name for the transformation
|
90
76
|
#
|
91
77
|
# @return [itself] self
|
92
78
|
#
|
93
79
|
# @alias :import
|
94
80
|
#
|
95
|
-
def import(
|
96
|
-
@store = store.import(
|
81
|
+
def import(*args)
|
82
|
+
@store = store.import(*args)
|
97
83
|
self
|
98
84
|
end
|
99
85
|
alias_method :uses, :import
|
data/lib/transproc/rspec.rb
CHANGED
@@ -5,21 +5,23 @@
|
|
5
5
|
# ==============================================================================
|
6
6
|
|
7
7
|
shared_context :call_transproc do
|
8
|
-
let!(:
|
9
|
-
let!(:
|
10
|
-
|
8
|
+
let!(:__initial__) { input.dup rescue input }
|
9
|
+
let!(:__fn__) { described_class[*arguments] }
|
10
|
+
subject { __fn__[input] }
|
11
11
|
end
|
12
12
|
|
13
13
|
shared_examples :transforming_data do
|
14
|
+
include_context :call_transproc
|
15
|
+
|
14
16
|
it '[returns the expected output]' do
|
15
|
-
expect(
|
17
|
+
expect(subject).to eql(output), <<-REPORT.gsub(/.+\|/, "")
|
16
18
|
|
|
17
19
|
|fn = #{described_class}#{Array[*arguments]}
|
18
20
|
|
|
19
21
|
|fn[#{input}]
|
20
22
|
|
|
21
23
|
| expected: #{output}
|
22
|
-
| got: #{
|
24
|
+
| got: #{subject}
|
23
25
|
REPORT
|
24
26
|
end
|
25
27
|
end
|
@@ -30,13 +32,14 @@ shared_examples :transforming_immutable_data do
|
|
30
32
|
it_behaves_like :transforming_data
|
31
33
|
|
32
34
|
it '[keeps input unchanged]' do
|
33
|
-
expect
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
expect { subject }
|
36
|
+
.not_to change { input }, <<-REPORT.gsub(/.+\|/, "")
|
37
|
+
|
|
38
|
+
|fn = #{described_class}#{Array[*arguments]}
|
39
|
+
|
|
40
|
+
|expected: not to change #{__initial__}
|
41
|
+
| got: changed it to #{input}
|
42
|
+
REPORT
|
40
43
|
end
|
41
44
|
end
|
42
45
|
|
@@ -46,14 +49,16 @@ shared_examples :mutating_input_data do
|
|
46
49
|
it_behaves_like :transforming_data
|
47
50
|
|
48
51
|
it '[changes input]' do
|
49
|
-
expect
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
52
|
+
expect { subject }
|
53
|
+
.to change { input }
|
54
|
+
.to(output), <<-REPORT.gsub(/.+\|/, "")
|
55
|
+
|
|
56
|
+
|fn = #{described_class}#{Array[*arguments]}
|
57
|
+
|
|
58
|
+
|fn[#{input}]
|
59
|
+
|
|
60
|
+
|expected: to change input to #{output}
|
61
|
+
| got: #{input}
|
62
|
+
REPORT
|
58
63
|
end
|
59
64
|
end
|
data/lib/transproc/store.rb
CHANGED
@@ -38,17 +38,18 @@ module Transproc
|
|
38
38
|
|
39
39
|
# Imports proc(s) to the collection from another module
|
40
40
|
#
|
41
|
-
# @
|
42
|
-
# @param (see #import_methods)
|
43
|
-
# @return (see #import_methods)
|
44
|
-
#
|
45
|
-
# @overload add(source, options)
|
46
|
-
# @param (see #import_method)
|
47
|
-
# @return (see #import_method)
|
41
|
+
# @private
|
48
42
|
#
|
49
|
-
def import(
|
50
|
-
|
51
|
-
|
43
|
+
def import(*args)
|
44
|
+
first = args.first
|
45
|
+
return import_all(first) if first.instance_of?(Module)
|
46
|
+
|
47
|
+
opts = args.pop
|
48
|
+
source = opts.fetch(:from)
|
49
|
+
rename = opts.fetch(:as) { first.to_sym }
|
50
|
+
|
51
|
+
return import_methods(source, args) if args.count > 1
|
52
|
+
import_method(source, first, rename)
|
52
53
|
end
|
53
54
|
|
54
55
|
protected
|
@@ -57,22 +58,31 @@ module Transproc
|
|
57
58
|
# updated with either the module's singleton method,
|
58
59
|
# or the proc having been imported from another module.
|
59
60
|
#
|
60
|
-
# @param [
|
61
|
-
# @param [
|
62
|
-
# @
|
63
|
-
# The module whose method or imported proc should be added
|
64
|
-
# @option options [Symbol] :as
|
65
|
-
# The key for the proc in the current collection
|
61
|
+
# @param [Module] source
|
62
|
+
# @param [Symbol] name
|
63
|
+
# @param [Symbol] new_name
|
66
64
|
#
|
67
65
|
# @return [Transproc::Store]
|
68
66
|
#
|
69
|
-
def import_method(source,
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
fn
|
67
|
+
def import_method(source, name, new_name = name)
|
68
|
+
from = name.to_sym
|
69
|
+
to = new_name.to_sym
|
70
|
+
|
71
|
+
fn = source.is_a?(Registry) ? source.fetch(from) : source.method(from)
|
72
|
+
self.class.new(methods.merge(to => fn))
|
73
|
+
end
|
74
74
|
|
75
|
-
|
75
|
+
# Creates new immutable collection from the current one,
|
76
|
+
# updated with either the module's singleton methods,
|
77
|
+
# or the procs having been imported from another module.
|
78
|
+
#
|
79
|
+
# @param [Module] source
|
80
|
+
# @param [Array<Symbol>] names
|
81
|
+
#
|
82
|
+
# @return [Transproc::Store]
|
83
|
+
#
|
84
|
+
def import_methods(source, names)
|
85
|
+
names.inject(self) { |a, e| a.import_method(source, e) }
|
76
86
|
end
|
77
87
|
|
78
88
|
# Creates new immutable collection from the current one,
|
@@ -83,12 +93,12 @@ module Transproc
|
|
83
93
|
#
|
84
94
|
# @return [Transproc::Store]
|
85
95
|
#
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
96
|
+
def import_all(source)
|
97
|
+
names = source.public_methods - Registry.instance_methods - Module.methods
|
98
|
+
names -= [:initialize] # for compatibility with Rubinius
|
99
|
+
names += source.store.methods.keys if source.is_a? Registry
|
90
100
|
|
91
|
-
|
101
|
+
import_methods(source, names)
|
92
102
|
end
|
93
103
|
end # class Store
|
94
104
|
end # module Transproc
|
data/lib/transproc/version.rb
CHANGED
data/spec/unit/coercions_spec.rb
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Transproc::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
|
+
|
4
16
|
describe '.to_string' do
|
5
17
|
it 'turns integer into a string' do
|
6
18
|
expect(described_class.t(:to_string)[1]).to eql('1')
|
@@ -11,6 +23,10 @@ describe Transproc::Coercions do
|
|
11
23
|
it 'turns string into a symbol' do
|
12
24
|
expect(described_class.t(:to_symbol)['test']).to eql(:test)
|
13
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
|
14
30
|
end
|
15
31
|
|
16
32
|
describe '.to_integer' do
|
@@ -1,6 +1,29 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Transproc::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
|
+
|
4
27
|
describe '.guard' do
|
5
28
|
let(:fn) { described_class.t(:guard, condition, operation) }
|
6
29
|
let(:condition) { ->(value) { value.is_a?(::String) } }
|
data/spec/unit/function_spec.rb
CHANGED
@@ -117,4 +117,45 @@ describe Transproc::Function do
|
|
117
117
|
expect(left == right).to be(false)
|
118
118
|
end
|
119
119
|
end
|
120
|
+
|
121
|
+
describe '#to_proc' do
|
122
|
+
shared_examples :providing_a_proc do
|
123
|
+
let(:fn) { described_class.new(source) }
|
124
|
+
subject { fn.to_proc }
|
125
|
+
|
126
|
+
it 'returns a proc' do
|
127
|
+
expect(subject).to be_instance_of Proc
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'works fine' do
|
131
|
+
expect(subject.call :foo).to eql('foo')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'from a method' do
|
136
|
+
let(:source) do
|
137
|
+
mod = Module.new do
|
138
|
+
def self.get(x)
|
139
|
+
x.to_s
|
140
|
+
end
|
141
|
+
end
|
142
|
+
mod.method(:get)
|
143
|
+
end
|
144
|
+
it_behaves_like :providing_a_proc
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'from a proc' do
|
148
|
+
let(:source) { -> value { value.to_s } }
|
149
|
+
it_behaves_like :providing_a_proc
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'from a transproc' do
|
153
|
+
let(:source) { Transproc::Function.new -> value { value.to_s } }
|
154
|
+
it_behaves_like :providing_a_proc
|
155
|
+
|
156
|
+
it 'can be applied to collection' do
|
157
|
+
expect([:foo, :bar].map(&source)).to eql(%w(foo bar))
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
120
161
|
end
|
@@ -30,11 +30,11 @@ describe Transproc::HashTransformations do
|
|
30
30
|
it 'returns a new hash with symbolized keys' do
|
31
31
|
symbolize_keys = described_class.t(:symbolize_keys)
|
32
32
|
|
33
|
-
input = {
|
34
|
-
output = {
|
33
|
+
input = { 1 => 'bar' }
|
34
|
+
output = { :'1' => 'bar' }
|
35
35
|
|
36
36
|
expect(symbolize_keys[input]).to eql(output)
|
37
|
-
expect
|
37
|
+
expect { symbolize_keys[input] }.not_to change { input }
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -509,4 +509,44 @@ describe Transproc::HashTransformations do
|
|
509
509
|
expect(result[:hash]).to eql(one: 1)
|
510
510
|
end
|
511
511
|
end
|
512
|
+
|
513
|
+
describe '.deep_merge' do
|
514
|
+
let(:hash){
|
515
|
+
{
|
516
|
+
name: 'Jane',
|
517
|
+
email: 'jane@doe.org',
|
518
|
+
favorites:
|
519
|
+
{
|
520
|
+
food: 'stroopwafel'
|
521
|
+
}
|
522
|
+
}
|
523
|
+
}
|
524
|
+
|
525
|
+
let(:update){
|
526
|
+
{
|
527
|
+
email: 'jane@example.org',
|
528
|
+
favorites:
|
529
|
+
{
|
530
|
+
color: 'orange'
|
531
|
+
}
|
532
|
+
}
|
533
|
+
}
|
534
|
+
|
535
|
+
it 'recursively merges hash values' do
|
536
|
+
deep_merge = described_class.t(:deep_merge)
|
537
|
+
output = { name: 'Jane', email: 'jane@example.org', favorites: { food: 'stroopwafel', color: 'orange' } }
|
538
|
+
|
539
|
+
expect(deep_merge[hash, update]).to eql(output)
|
540
|
+
end
|
541
|
+
|
542
|
+
it 'does not alter the provided arguments' do
|
543
|
+
original_hash = hash.dup
|
544
|
+
original_update = update.dup
|
545
|
+
|
546
|
+
described_class.t(:deep_merge)[hash, update]
|
547
|
+
|
548
|
+
expect(hash).to eql(original_hash)
|
549
|
+
expect(update).to eql(original_update)
|
550
|
+
end
|
551
|
+
end
|
512
552
|
end
|
data/spec/unit/registry_spec.rb
CHANGED
@@ -77,6 +77,17 @@ describe Transproc::Registry do
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
+
context 'a list of methods' do
|
81
|
+
before { bar.import :prefix, from: foo }
|
82
|
+
before { bar.import :prefix, from: foo, as: :affix }
|
83
|
+
before { baz.import :prefix, :affix, from: bar }
|
84
|
+
|
85
|
+
it 'registers a transproc' do
|
86
|
+
expect(baz[:prefix, 'bar']['baz']).to eql 'bar_baz'
|
87
|
+
expect(baz[:affix, 'bar']['baz']).to eql 'bar_baz'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
80
91
|
context 'a renamed method' do
|
81
92
|
before { bar.import :prefix, from: foo, as: :affix }
|
82
93
|
|
data/spec/unit/store_spec.rb
CHANGED
@@ -38,7 +38,7 @@ describe Transproc::Store do
|
|
38
38
|
end
|
39
39
|
end # describe #fetch
|
40
40
|
|
41
|
-
describe '#import' do
|
41
|
+
describe '#import', :focus do
|
42
42
|
before do
|
43
43
|
module Bar
|
44
44
|
def self.bar
|
@@ -91,6 +91,20 @@ describe Transproc::Store do
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
+
context 'named methods' do
|
95
|
+
subject { store.import 'qux', 'bar', from: Qux }
|
96
|
+
|
97
|
+
it_behaves_like :importing_method do
|
98
|
+
let(:key) { :qux }
|
99
|
+
let(:value) { :qux }
|
100
|
+
end
|
101
|
+
|
102
|
+
it_behaves_like :importing_method do
|
103
|
+
let(:key) { :bar }
|
104
|
+
let(:value) { :bar }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
94
108
|
context 'renamed method' do
|
95
109
|
subject { store.import 'qux', from: Qux, as: 'quxx' }
|
96
110
|
|
data/spec/unit/transproc_spec.rb
CHANGED
@@ -17,11 +17,11 @@ describe Transproc do
|
|
17
17
|
|
18
18
|
describe '.register' do
|
19
19
|
it 'allows registering functions by name' do
|
20
|
-
Transproc.register(:
|
20
|
+
Transproc.register(:id, -> value { value })
|
21
21
|
|
22
22
|
value = 'hello world'
|
23
23
|
|
24
|
-
result = t(:
|
24
|
+
result = t(:id)[value]
|
25
25
|
|
26
26
|
expect(result).to be(value)
|
27
27
|
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.3.
|
4
|
+
version: 0.3.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: 2015-
|
11
|
+
date: 2015-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|