transproc 0.1.3 → 0.2.0

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.
@@ -1,29 +1,70 @@
1
+ require 'transproc/conditional'
2
+
1
3
  module Transproc
2
- register(:array_recursion) do |value, fn|
3
- result = fn[value]
4
-
5
- result.map! do |item|
6
- if item.is_a?(::Array)
7
- Transproc(:array_recursion, fn)[item]
8
- else
9
- item
10
- end
11
- end
12
- end
4
+ # Recursive transformation functions
5
+ #
6
+ # @example
7
+ # require 'transproc/recursion'
8
+ #
9
+ # include Transproc::Helper
10
+ #
11
+ # fn = t(:hash_recursion, t(:symbolize_keys))
12
+ #
13
+ # fn["name" => "Jane", "address" => { "street" => "Street 1", "zipcode" => "123" }]
14
+ # # => {:name=>"Jane", :address=>{:street=>"Street 1", :zipcode=>"123"}}
15
+ #
16
+ # @api public
17
+ module Recursion
18
+ extend Functions
19
+
20
+ IF_ARRAY = -> fn { Transproc(:is, Array, fn) }
13
21
 
14
- register(:hash_recursion) do |value, fn|
15
- result = fn[value]
22
+ IF_HASH = -> fn { Transproc(:is, Hash, fn) }
16
23
 
17
- result.keys.each do |key|
18
- item = result.delete(key)
24
+ # Recursively apply the provided transformation function to an array
25
+ #
26
+ # @example
27
+ # Transproc(:array_recursion, -> s { s.compact })[
28
+ # [['Joe', 'Jane', nil], ['Smith', 'Doe', nil]]
29
+ # ]
30
+ # # => [["Joe", "Jane"], ["Smith", "Doe"]]
31
+ #
32
+ # @param [Array]
33
+ #
34
+ # @return [Array]
35
+ #
36
+ # @api public
37
+ def array_recursion(value, fn)
38
+ result = fn[value]
39
+ guarded = IF_ARRAY[-> v { Transproc(:array_recursion, fn)[v] }]
19
40
 
20
- if item.is_a?(::Hash)
21
- result[key] = Transproc(:hash_recursion, fn)[item]
22
- else
23
- result[key] = item
41
+ result.map! do |item|
42
+ guarded[item]
24
43
  end
25
44
  end
26
45
 
27
- result
46
+ # Recursively apply the provided transformation function to a hash
47
+ #
48
+ # @example
49
+ # Transproc(:hash_recursion, Transproc(:symbolize_keys))[
50
+ # ["name" => "Jane", "address" => { "street" => "Street 1", "zipcode" => "123" }]
51
+ # ]
52
+ # # => {:name=>"Jane", :address=>{:street=>"Street 1", :zipcode=>"123"}}
53
+ #
54
+ # @param [Hash]
55
+ #
56
+ # @return [Hash]
57
+ #
58
+ # @api public
59
+ def hash_recursion(value, fn)
60
+ result = fn[value]
61
+ guarded = IF_HASH[-> v { Transproc(:hash_recursion, fn)[v] }]
62
+
63
+ result.keys.each do |key|
64
+ result[key] = guarded[result.delete(key)]
65
+ end
66
+
67
+ result
68
+ end
28
69
  end
29
70
  end
@@ -1,3 +1,3 @@
1
1
  module Transproc
2
- VERSION = '0.1.3'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
@@ -56,8 +56,8 @@ describe 'Array transformations with Transproc' do
56
56
  wrap =
57
57
  t(
58
58
  :map_array,
59
- t(:nest, :user, [:name, :title]),
60
- t(:map_key, :user, t(:nest, :task, [:title]))
59
+ t(:nest, :user, [:name, :title]) +
60
+ t(:map_value, :user, t(:nest, :task, [:title]))
61
61
  )
62
62
 
63
63
  input = [{ name: 'Jane', title: 'One' }]
@@ -7,6 +7,12 @@ describe 'Transproc / Coercions' do
7
7
  end
8
8
  end
9
9
 
10
+ describe 'to_symbol' do
11
+ it 'turns string into a symbol' do
12
+ expect(t(:to_symbol)['test']).to eql(:test)
13
+ end
14
+ end
15
+
10
16
  describe 'to_integer' do
11
17
  it 'turns string into an integer' do
12
18
  expect(t(:to_integer)['1']).to eql(1)
@@ -61,13 +67,13 @@ describe 'Transproc / Coercions' do
61
67
  describe 'to_boolean' do
62
68
  subject(:coercer) { t(:to_boolean) }
63
69
 
64
- Transproc::TRUE_VALUES.each do |value|
70
+ Transproc::Coercions::TRUE_VALUES.each do |value|
65
71
  it "turns #{value.inspect} to true" do
66
72
  expect(coercer[value]).to be(true)
67
73
  end
68
74
  end
69
75
 
70
- Transproc::FALSE_VALUES.each do |value|
76
+ Transproc::Coercions::FALSE_VALUES.each do |value|
71
77
  it "turns #{value.inspect} to false" do
72
78
  expect(coercer[value]).to be(false)
73
79
  end
@@ -8,7 +8,7 @@ describe Transproc::Composer do
8
8
  def fn
9
9
  compose do |fns|
10
10
  fns << t(:map_array, t(:symbolize_keys)) <<
11
- t(:map_array, t(:map_key, :age, t(:to_integer)))
11
+ t(:map_array, t(:map_value, :age, t(:to_integer)))
12
12
  end
13
13
  end
14
14
  end.new
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Conditional transformations with Transproc' do
4
+ describe 'guard' do
5
+ let(:fn) { t(:guard, ->(value) { value.is_a?(::String) }, t(:to_integer)) }
6
+
7
+ context 'when predicate returns truthy value' do
8
+ it 'applies the transformation and returns the result' do
9
+ input = '2'
10
+
11
+ expect(fn[input]).to eql(2)
12
+ end
13
+ end
14
+
15
+ context 'when predicate returns falsey value' do
16
+ it 'returns the original value' do
17
+ input = { 'foo' => 'bar' }
18
+
19
+ expect(fn[input]).to eql('foo' => 'bar')
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Transproc::Function" do
4
+ describe "#>>" do
5
+ it "composes named functions" do
6
+ f1 = t(:symbolize_keys)
7
+ f2 = t(:rename_keys, user_name: :name)
8
+
9
+ f3 = f1 >> f2
10
+
11
+ expect(f3.to_ast).to eql(
12
+ [
13
+ :symbolize_keys, [],
14
+ [
15
+ :rename_keys, [ user_name: :name ]
16
+ ]
17
+ ]
18
+ )
19
+
20
+ expect(f3['user_name' => 'Jane']).to eql(name: 'Jane')
21
+
22
+ f4 = f3 >> t(:nest, :details, [:name])
23
+
24
+ expect(f4.to_ast).to eql(
25
+ [
26
+ :symbolize_keys, [],
27
+ [
28
+ :rename_keys, [ user_name: :name ]
29
+ ],
30
+ [
31
+ :nest, [:details, [:name]]
32
+ ]
33
+ ]
34
+ )
35
+
36
+ expect(f4['user_name' => 'Jane']).to eql(details: { name: 'Jane' })
37
+ end
38
+
39
+ it "composes anonymous functions" do
40
+ # TODO: Use Transproc -> (v) { v.to_s } after release of jruby-9k
41
+ f1 = Transproc proc { |v, m| v * m }, 2
42
+ f2 = Transproc proc { |v| v.to_s }
43
+
44
+ f3 = f1 >> f2
45
+
46
+ expect(f3.to_ast).to eql(
47
+ [
48
+ f1.fn, [2],
49
+ [
50
+ f2.fn, []
51
+ ]
52
+ ]
53
+ )
54
+ end
55
+ end
56
+ end
@@ -1,6 +1,30 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Hash mapping with Transproc' do
4
+ describe 'map_keys' do
5
+ it 'returns a new hash with given proc applied to keys' do
6
+ map_keys = t(:map_keys, ->(key) { key.strip })
7
+
8
+ input = { ' foo ' => 'bar' }
9
+ output = { 'foo' => 'bar' }
10
+
11
+ expect(map_keys[input]).to eql(output)
12
+ expect(input).to eql(' foo ' => 'bar')
13
+ end
14
+ end
15
+
16
+ describe 'map_keys!' do
17
+ it 'returns updated hash with given proc applied to keys' do
18
+ map_keys = t(:map_keys!, ->(key) { key.strip })
19
+
20
+ input = { ' foo ' => 'bar' }
21
+ output = { 'foo' => 'bar' }
22
+
23
+ expect(map_keys[input]).to eql(output)
24
+ expect(input).to eql('foo' => 'bar')
25
+ end
26
+ end
27
+
4
28
  describe 'symbolize_keys' do
5
29
  it 'returns a new hash with symbolized keys' do
6
30
  symbolize_keys = t(:symbolize_keys)
@@ -26,6 +50,104 @@ describe 'Hash mapping with Transproc' do
26
50
  end
27
51
  end
28
52
 
53
+ describe 'stringify_keys' do
54
+ it 'returns a new hash with stringified keys' do
55
+ stringify_keys = t(:stringify_keys)
56
+
57
+ input = { foo: 'bar' }
58
+ output = { 'foo' => 'bar' }
59
+
60
+ expect(stringify_keys[input]).to eql(output)
61
+ expect(input).to eql(foo: 'bar')
62
+ end
63
+ end
64
+
65
+ describe 'stringify_keys!' do
66
+ it 'returns a new hash with stringified keys' do
67
+ stringify_keys = t(:stringify_keys!)
68
+
69
+ input = { foo: 'bar' }
70
+ output = { 'foo' => 'bar' }
71
+
72
+ expect(stringify_keys[input]).to eql(output)
73
+ expect(input).to eql('foo' => 'bar')
74
+ end
75
+ end
76
+
77
+ describe 'map_values' do
78
+ it 'returns a new hash with given proc applied to values' do
79
+ map_values = t(:map_values, ->(value) { value.strip })
80
+
81
+ input = { 'foo' => ' bar ' }
82
+ output = { 'foo' => 'bar' }
83
+
84
+ expect(map_values[input]).to eql(output)
85
+ expect(input).to eql('foo' => ' bar ')
86
+ end
87
+ end
88
+
89
+ describe 'map_values!' do
90
+ it 'returns updated hash with given proc applied to values' do
91
+ map_values = t(:map_values!, ->(value) { value.strip })
92
+
93
+ input = { 'foo' => ' bar ' }
94
+ output = { 'foo' => 'bar' }
95
+
96
+ expect(map_values[input]).to eql(output)
97
+ expect(input).to eql('foo' => 'bar')
98
+ end
99
+ end
100
+
101
+ describe 'rename_keys' do
102
+ it 'returns a new hash with applied functions' do
103
+ map = t(:rename_keys, 'foo' => :foo)
104
+
105
+ input = { 'foo' => 'bar', :bar => 'baz' }
106
+ output = { foo: 'bar', bar: 'baz' }
107
+
108
+ expect(map[input]).to eql(output)
109
+ expect(input).to eql('foo' => 'bar', :bar => 'baz')
110
+ end
111
+ end
112
+
113
+ describe 'rename_keys!' do
114
+ it 'returns updated hash with applied functions' do
115
+ map = t(:rename_keys!, 'foo' => :foo)
116
+
117
+ input = { 'foo' => 'bar', :bar => 'baz' }
118
+ output = { foo: 'bar', bar: 'baz' }
119
+
120
+ map[input]
121
+
122
+ expect(input).to eql(output)
123
+ end
124
+ end
125
+
126
+ describe 'map_value' do
127
+ it 'applies function to value under specified key' do
128
+ transformation = t(:map_value, :user, t(:symbolize_keys))
129
+
130
+ input = { user: { 'name' => 'Jane' } }
131
+ output = { user: { name: 'Jane' } }
132
+
133
+ expect(transformation[input]).to eql(output)
134
+ expect(input).to eql(user: { 'name' => 'Jane' })
135
+ end
136
+ end
137
+
138
+ describe 'map_value!' do
139
+ it 'applies function to value under specified key' do
140
+ transformation = t(:map_value!, :user, t(:symbolize_keys))
141
+
142
+ input = { user: { 'name' => 'Jane' } }
143
+ output = { user: { name: 'Jane' } }
144
+
145
+ transformation[input]
146
+
147
+ expect(input).to eql(output)
148
+ end
149
+ end
150
+
29
151
  describe 'nest' do
30
152
  it 'returns new hash with keys nested under a new key' do
31
153
  nest = t(:nest, :baz, ['foo'])
@@ -101,60 +223,10 @@ describe 'Hash mapping with Transproc' do
101
223
  end
102
224
  end
103
225
 
104
- describe 'map_hash' do
105
- it 'returns a new hash with applied functions' do
106
- map = t(:map_hash, 'foo' => :foo)
107
-
108
- input = { 'foo' => 'bar', :bar => 'baz' }
109
- output = { foo: 'bar', bar: 'baz' }
110
-
111
- expect(map[input]).to eql(output)
112
- expect(input).to eql('foo' => 'bar', :bar => 'baz')
113
- end
114
- end
115
-
116
- describe 'map_hash!' do
117
- it 'returns updated hash with applied functions' do
118
- map = t(:map_hash!, 'foo' => :foo)
119
-
120
- input = { 'foo' => 'bar', :bar => 'baz' }
121
- output = { foo: 'bar', bar: 'baz' }
122
-
123
- map[input]
124
-
125
- expect(input).to eql(output)
126
- end
127
- end
128
-
129
- describe 'map_key' do
130
- it 'applies function to value under specified key' do
131
- transformation = t(:map_key, :user, t(:symbolize_keys))
132
-
133
- input = { user: { 'name' => 'Jane' } }
134
- output = { user: { name: 'Jane' } }
135
-
136
- expect(transformation[input]).to eql(output)
137
- expect(input).to eql(user: { 'name' => 'Jane' })
138
- end
139
- end
140
-
141
- describe 'map_key!' do
142
- it 'applies function to value under specified key' do
143
- transformation = t(:map_key!, :user, t(:symbolize_keys))
144
-
145
- input = { user: { 'name' => 'Jane' } }
146
- output = { user: { name: 'Jane' } }
147
-
148
- transformation[input]
149
-
150
- expect(input).to eql(output)
151
- end
152
- end
153
-
154
226
  describe 'nested transform' do
155
227
  it 'applies functions to nested hashes' do
156
228
  symbolize_keys = t(:symbolize_keys)
157
- map_user_key = t(:map_key, :user, symbolize_keys)
229
+ map_user_key = t(:map_value, :user, symbolize_keys)
158
230
 
159
231
  transformation = symbolize_keys >> map_user_key
160
232
 
@@ -168,7 +240,7 @@ describe 'Hash mapping with Transproc' do
168
240
  describe 'combining transformations' do
169
241
  it 'applies functions to the hash' do
170
242
  symbolize_keys = t(:symbolize_keys)
171
- map = t(:map_hash, user_name: :name, user_email: :email)
243
+ map = t(:rename_keys, user_name: :name, user_email: :email)
172
244
 
173
245
  transformation = symbolize_keys >> map
174
246
 
data/transproc.gemspec CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Transproc::VERSION.dup
9
9
  spec.authors = ["Piotr Solnica"]
10
10
  spec.email = ["piotr.solnica@gmail.com"]
11
- spec.summary = %q{Experimental functional transformations for Ruby}
11
+ spec.summary = %q{Transform Ruby objects in functional style}
12
12
  spec.description = spec.summary
13
- spec.homepage = ""
13
+ spec.homepage = "http://solnic.github.io/transproc/"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")