transproc 0.4.2 → 1.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +132 -2
- data/lib/transproc.rb +0 -71
- data/lib/transproc/array.rb +36 -74
- data/lib/transproc/class.rb +0 -4
- data/lib/transproc/coercions.rb +0 -4
- data/lib/transproc/composer.rb +0 -26
- data/lib/transproc/conditional.rb +0 -4
- data/lib/transproc/hash.rb +43 -159
- data/lib/transproc/proc.rb +0 -4
- data/lib/transproc/recursion.rb +0 -4
- data/lib/transproc/registry.rb +35 -1
- data/lib/transproc/store.rb +22 -1
- data/lib/transproc/transformer/class_interface.rb +63 -19
- data/lib/transproc/version.rb +1 -1
- data/spec/spec_helper.rb +0 -4
- data/spec/unit/array_transformations_spec.rb +18 -90
- data/spec/unit/function_not_found_error_spec.rb +1 -9
- data/spec/unit/function_spec.rb +17 -12
- data/spec/unit/hash_transformations_spec.rb +78 -240
- data/spec/unit/recursion_spec.rb +8 -24
- data/spec/unit/registry_spec.rb +80 -0
- data/spec/unit/store_spec.rb +35 -0
- data/spec/unit/transformer_spec.rb +205 -9
- data/spec/unit/transproc_spec.rb +2 -45
- metadata +2 -3
- data/lib/transproc/rspec.rb +0 -71
data/lib/transproc/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -7,45 +7,25 @@ describe Transproc::ArrayTransformations do
|
|
7
7
|
it 'extracts values by key from all hashes' do
|
8
8
|
extract_key = described_class.t(:extract_key, 'name')
|
9
9
|
|
10
|
-
original = [
|
11
|
-
{ 'name' => 'Alice', 'role' => 'sender' },
|
12
|
-
{ 'name' => 'Bob', 'role' => 'receiver' },
|
13
|
-
{ 'role' => 'listener' }
|
14
|
-
]
|
15
|
-
|
16
|
-
input = original
|
17
|
-
|
18
|
-
output = ['Alice', 'Bob', nil]
|
19
|
-
|
20
|
-
expect(extract_key[input]).to eql(output)
|
21
|
-
expect(input).to eql(original)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe '.extract_key!' do
|
26
|
-
it 'extracts values by key from all hashes' do
|
27
|
-
extract_key = described_class.t(:extract_key!, 'name')
|
28
|
-
|
29
10
|
input = [
|
30
11
|
{ 'name' => 'Alice', 'role' => 'sender' },
|
31
12
|
{ 'name' => 'Bob', 'role' => 'receiver' },
|
32
13
|
{ 'role' => 'listener' }
|
33
|
-
]
|
14
|
+
].freeze
|
34
15
|
|
35
16
|
output = ['Alice', 'Bob', nil]
|
36
17
|
|
37
18
|
expect(extract_key[input]).to eql(output)
|
38
|
-
expect(input).to eql(output)
|
39
19
|
end
|
40
20
|
end
|
41
21
|
|
22
|
+
it { expect(described_class).not_to be_contain(:extract_key!) }
|
23
|
+
|
42
24
|
describe '.insert_key' do
|
43
25
|
it 'wraps values to tuples with given key' do
|
44
26
|
insert_key = described_class.t(:insert_key, 'name')
|
45
27
|
|
46
|
-
|
47
|
-
|
48
|
-
input = original
|
28
|
+
input = ['Alice', 'Bob', nil].freeze
|
49
29
|
|
50
30
|
output = [
|
51
31
|
{ 'name' => 'Alice' },
|
@@ -54,36 +34,16 @@ describe Transproc::ArrayTransformations do
|
|
54
34
|
]
|
55
35
|
|
56
36
|
expect(insert_key[input]).to eql(output)
|
57
|
-
expect(input).to eql(original)
|
58
37
|
end
|
59
38
|
end
|
60
39
|
|
61
|
-
|
62
|
-
it 'wraps values to tuples with given key' do
|
63
|
-
insert_key = described_class.t(:insert_key!, 'name')
|
64
|
-
|
65
|
-
original = ['Alice', 'Bob', nil]
|
66
|
-
|
67
|
-
input = original
|
68
|
-
|
69
|
-
output = [
|
70
|
-
{ 'name' => 'Alice' },
|
71
|
-
{ 'name' => 'Bob' },
|
72
|
-
{ 'name' => nil }
|
73
|
-
]
|
74
|
-
|
75
|
-
expect(insert_key[input]).to eql(output)
|
76
|
-
expect(input).to eql(output)
|
77
|
-
end
|
78
|
-
end
|
40
|
+
it { expect(described_class).not_to be_contain(:insert_key!) }
|
79
41
|
|
80
42
|
describe '.add_keys' do
|
81
43
|
it 'returns a new array with missed keys added to tuples' do
|
82
44
|
add_keys = described_class.t(:add_keys, [:foo, :bar, :baz])
|
83
45
|
|
84
|
-
|
85
|
-
|
86
|
-
input = original
|
46
|
+
input = [{ foo: 'bar' }, { bar: 'baz' }].freeze
|
87
47
|
|
88
48
|
output = [
|
89
49
|
{ foo: 'bar', bar: nil, baz: nil },
|
@@ -91,38 +51,19 @@ describe Transproc::ArrayTransformations do
|
|
91
51
|
]
|
92
52
|
|
93
53
|
expect(add_keys[input]).to eql(output)
|
94
|
-
expect(input).to eql(original)
|
95
54
|
end
|
96
55
|
end
|
97
56
|
|
98
|
-
|
99
|
-
it 'adds missed keys to tuples' do
|
100
|
-
add_keys = described_class.t(:add_keys!, [:foo, :bar, :baz])
|
101
|
-
|
102
|
-
original = [{ foo: 'bar' }, { bar: 'baz' }]
|
103
|
-
|
104
|
-
input = original
|
105
|
-
|
106
|
-
output = [
|
107
|
-
{ foo: 'bar', bar: nil, baz: nil },
|
108
|
-
{ foo: nil, bar: 'baz', baz: nil }
|
109
|
-
]
|
110
|
-
|
111
|
-
expect(add_keys[input]).to eql(output)
|
112
|
-
expect(input).to eql(output)
|
113
|
-
end
|
114
|
-
end
|
57
|
+
it { expect(described_class).not_to be_contain(:add_keys!) }
|
115
58
|
|
116
59
|
describe '.map_array' do
|
117
60
|
it 'applies funtions to all values' do
|
118
61
|
map = described_class.t(:map_array, hashes[:symbolize_keys])
|
119
62
|
|
120
|
-
|
121
|
-
{ 'name' => 'Jane', 'title' => 'One' },
|
122
|
-
{ 'name' => 'Jane', 'title' => 'Two' }
|
123
|
-
]
|
124
|
-
|
125
|
-
input = original
|
63
|
+
input = [
|
64
|
+
{ 'name' => 'Jane', 'title' => 'One' }.freeze,
|
65
|
+
{ 'name' => 'Jane', 'title' => 'Two' }.freeze
|
66
|
+
].freeze
|
126
67
|
|
127
68
|
output = [
|
128
69
|
{ name: 'Jane', title: 'One' },
|
@@ -130,38 +71,25 @@ describe Transproc::ArrayTransformations do
|
|
130
71
|
]
|
131
72
|
|
132
73
|
expect(map[input]).to eql(output)
|
133
|
-
expect(input).to eql(original)
|
134
74
|
end
|
135
75
|
|
136
76
|
it 'handles huge arrays' do
|
137
77
|
map = described_class.t(:map_array, hashes[:symbolize_keys])
|
138
78
|
|
139
|
-
input =
|
79
|
+
input = Array.new(138_706) { |i| { 'key' => i } }
|
140
80
|
|
141
|
-
expect { map[input] }.to_not raise_error
|
81
|
+
expect { map[input] }.to_not raise_error
|
142
82
|
end
|
143
|
-
end
|
144
|
-
|
145
|
-
describe '.map_array!' do
|
146
|
-
it 'updates array with the result of the function applied to each value' do
|
147
|
-
map = described_class.t(:map_array!, hashes[:symbolize_keys])
|
148
|
-
|
149
|
-
input = [
|
150
|
-
{ 'name' => 'Jane', 'title' => 'One' },
|
151
|
-
{ 'name' => 'Jane', 'title' => 'Two' }
|
152
|
-
]
|
153
83
|
|
154
|
-
|
155
|
-
|
156
|
-
{ name: 'Jane', title: 'Two' }
|
157
|
-
]
|
158
|
-
|
159
|
-
map[input]
|
84
|
+
it 'handles flat value arrays' do
|
85
|
+
map = described_class.t(:map_array, :upcase.to_proc)
|
160
86
|
|
161
|
-
expect(
|
87
|
+
expect(map['foo']).to eql(%w(FOO))
|
162
88
|
end
|
163
89
|
end
|
164
90
|
|
91
|
+
it { expect(described_class).not_to be_contain(:map_array!) }
|
92
|
+
|
165
93
|
describe '.wrap' do
|
166
94
|
it 'returns a new array with wrapped hashes' do
|
167
95
|
wrap = described_class.t(:wrap, :task, [:title])
|
@@ -1,15 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
describe Transproc::FunctionNotFoundError do
|
4
|
-
it 'complains that the function not registered
|
5
|
-
expect { Transproc(:foo) }.to raise_error do |error|
|
6
|
-
expect(error).to be_kind_of described_class
|
7
|
-
expect(error.message['foo']).not_to be_nil
|
8
|
-
expect(error.message['global']).not_to be_nil
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'complains that the function not registered locally' do
|
4
|
+
it 'complains that the function not registered' do
|
13
5
|
Foo = Module.new { extend Transproc::Registry }
|
14
6
|
|
15
7
|
expect { Foo[:foo] }.to raise_error do |error|
|
data/spec/unit/function_spec.rb
CHANGED
@@ -1,13 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Transproc::Function do
|
4
|
-
let(:
|
4
|
+
let(:container) do
|
5
|
+
Module.new do
|
6
|
+
extend Transproc::Registry
|
7
|
+
|
8
|
+
import Transproc::HashTransformations
|
9
|
+
end
|
10
|
+
end
|
5
11
|
|
6
12
|
describe '#name' do
|
7
13
|
let(:block) { proc { |v| v } }
|
8
14
|
|
9
15
|
it 'returns the name of the module function' do
|
10
|
-
expect(
|
16
|
+
expect(container[:symbolize_keys].name).to eql :symbolize_keys
|
11
17
|
end
|
12
18
|
|
13
19
|
it 'returns the explicitly assigned name' do
|
@@ -21,8 +27,8 @@ describe Transproc::Function do
|
|
21
27
|
|
22
28
|
describe '#>>' do
|
23
29
|
it 'composes named functions' do
|
24
|
-
f1 =
|
25
|
-
f2 =
|
30
|
+
f1 = container[:symbolize_keys]
|
31
|
+
f2 = container[:rename_keys, user_name: :name]
|
26
32
|
|
27
33
|
f3 = f1 >> f2
|
28
34
|
|
@@ -37,7 +43,7 @@ describe Transproc::Function do
|
|
37
43
|
|
38
44
|
expect(f3['user_name' => 'Jane']).to eql(name: 'Jane')
|
39
45
|
|
40
|
-
f4 = f3 >>
|
46
|
+
f4 = f3 >> container[:nest, :details, [:name]]
|
41
47
|
|
42
48
|
expect(f4.to_ast).to eql(
|
43
49
|
[
|
@@ -55,9 +61,8 @@ describe Transproc::Function do
|
|
55
61
|
end
|
56
62
|
|
57
63
|
it 'composes anonymous functions' do
|
58
|
-
|
59
|
-
|
60
|
-
f2 = Transproc proc(&:to_s)
|
64
|
+
f1 = container[->(v, m) { v * m }, 2]
|
65
|
+
f2 = container[:to_s.to_proc]
|
61
66
|
|
62
67
|
f3 = f1 >> f2
|
63
68
|
|
@@ -72,8 +77,8 @@ describe Transproc::Function do
|
|
72
77
|
end
|
73
78
|
|
74
79
|
it 'plays well with registered compositions' do
|
75
|
-
|
76
|
-
f =
|
80
|
+
container.register(:user_names, container[:symbolize_keys] + container[:rename_keys, user_name: :name])
|
81
|
+
f = container[:user_names]
|
77
82
|
|
78
83
|
expect(f['user_name' => 'Jane']).to eql(name: 'Jane')
|
79
84
|
expect(f.to_ast).to eql(
|
@@ -87,8 +92,8 @@ describe Transproc::Function do
|
|
87
92
|
end
|
88
93
|
|
89
94
|
it 'plays well with registered functions' do
|
90
|
-
|
91
|
-
fn = t(:
|
95
|
+
container.register(:to_string, Transproc::Coercions.t(:to_string))
|
96
|
+
fn = container.t(:to_string)
|
92
97
|
|
93
98
|
expect(fn[:ok]).to eql('ok')
|
94
99
|
expect(fn.to_ast).to eql([:to_string, []])
|
@@ -1,40 +1,27 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'transproc/rspec'
|
3
2
|
|
4
3
|
describe Transproc::HashTransformations do
|
5
4
|
describe '.map_keys' do
|
6
5
|
it 'returns a new hash with given proc applied to keys' do
|
7
6
|
map_keys = described_class.t(:map_keys, ->(key) { key.strip })
|
8
7
|
|
9
|
-
input = { ' foo ' => 'bar' }
|
8
|
+
input = { ' foo ' => 'bar' }.freeze
|
10
9
|
output = { 'foo' => 'bar' }
|
11
10
|
|
12
11
|
expect(map_keys[input]).to eql(output)
|
13
|
-
expect(input).to eql(' foo ' => 'bar')
|
14
12
|
end
|
15
13
|
end
|
16
14
|
|
17
|
-
|
18
|
-
it 'returns updated hash with given proc applied to keys' do
|
19
|
-
map_keys = described_class.t(:map_keys!, ->(key) { key.strip })
|
20
|
-
|
21
|
-
input = { ' foo ' => 'bar' }
|
22
|
-
output = { 'foo' => 'bar' }
|
23
|
-
|
24
|
-
expect(map_keys[input]).to eql(output)
|
25
|
-
expect(input).to eql('foo' => 'bar')
|
26
|
-
end
|
27
|
-
end
|
15
|
+
it { expect(described_class).not_to be_contain(:map_keys!) }
|
28
16
|
|
29
17
|
describe '.symbolize_keys' do
|
30
18
|
it 'returns a new hash with symbolized keys' do
|
31
19
|
symbolize_keys = described_class.t(:symbolize_keys)
|
32
20
|
|
33
|
-
input = { 1 => 'bar' }
|
21
|
+
input = { 1 => 'bar' }.freeze
|
34
22
|
output = { '1'.to_sym => 'bar' }
|
35
23
|
|
36
24
|
expect(symbolize_keys[input]).to eql(output)
|
37
|
-
expect { symbolize_keys[input] }.not_to change { input }
|
38
25
|
end
|
39
26
|
end
|
40
27
|
|
@@ -50,111 +37,65 @@ describe Transproc::HashTransformations do
|
|
50
37
|
end
|
51
38
|
end
|
52
39
|
|
53
|
-
|
54
|
-
it 'returns updated hash with symbolized keys' do
|
55
|
-
symbolize_keys = described_class.t(:symbolize_keys!)
|
56
|
-
|
57
|
-
input = { 'foo' => 'bar' }
|
58
|
-
output = { foo: 'bar' }
|
59
|
-
|
60
|
-
symbolize_keys[input]
|
61
|
-
|
62
|
-
expect(input).to eql(output)
|
63
|
-
end
|
64
|
-
end
|
40
|
+
it { expect(described_class).not_to be_contain(:symbolize_keys!) }
|
65
41
|
|
66
42
|
describe '.stringify_keys' do
|
67
43
|
it 'returns a new hash with stringified keys' do
|
68
44
|
stringify_keys = described_class.t(:stringify_keys)
|
69
45
|
|
70
|
-
input = { foo: 'bar' }
|
46
|
+
input = { foo: 'bar' }.freeze
|
71
47
|
output = { 'foo' => 'bar' }
|
72
48
|
|
73
49
|
expect(stringify_keys[input]).to eql(output)
|
74
|
-
expect(input).to eql(foo: 'bar')
|
75
50
|
end
|
76
51
|
end
|
77
52
|
|
78
|
-
|
79
|
-
it 'returns a new hash with stringified keys' do
|
80
|
-
stringify_keys = described_class.t(:stringify_keys!)
|
81
|
-
|
82
|
-
input = { foo: 'bar' }
|
83
|
-
output = { 'foo' => 'bar' }
|
84
|
-
|
85
|
-
expect(stringify_keys[input]).to eql(output)
|
86
|
-
expect(input).to eql('foo' => 'bar')
|
87
|
-
end
|
88
|
-
end
|
53
|
+
it { expect(described_class).not_to be_contain(:stringify_keys!) }
|
89
54
|
|
90
55
|
describe '.map_values' do
|
91
56
|
it 'returns a new hash with given proc applied to values' do
|
92
57
|
map_values = described_class.t(:map_values, ->(value) { value.strip })
|
93
58
|
|
94
|
-
input = { 'foo' => ' bar ' }
|
59
|
+
input = { 'foo' => ' bar ' }.freeze
|
95
60
|
output = { 'foo' => 'bar' }
|
96
61
|
|
97
62
|
expect(map_values[input]).to eql(output)
|
98
|
-
expect(input).to eql('foo' => ' bar ')
|
99
63
|
end
|
100
64
|
end
|
101
65
|
|
102
|
-
|
103
|
-
it 'returns updated hash with given proc applied to values' do
|
104
|
-
map_values = described_class.t(:map_values!, ->(value) { value.strip })
|
105
|
-
|
106
|
-
input = { 'foo' => ' bar ' }
|
107
|
-
output = { 'foo' => 'bar' }
|
108
|
-
|
109
|
-
expect(map_values[input]).to eql(output)
|
110
|
-
expect(input).to eql('foo' => 'bar')
|
111
|
-
end
|
112
|
-
end
|
66
|
+
it { expect(described_class).not_to be_contain(:map_values!) }
|
113
67
|
|
114
68
|
describe '.rename_keys' do
|
115
69
|
it 'returns a new hash with applied functions' do
|
116
70
|
map = described_class.t(:rename_keys, 'foo' => :foo)
|
117
71
|
|
118
|
-
input = { 'foo' => 'bar', :bar => 'baz' }
|
72
|
+
input = { 'foo' => 'bar', :bar => 'baz' }.freeze
|
119
73
|
output = { foo: 'bar', bar: 'baz' }
|
120
74
|
|
121
75
|
expect(map[input]).to eql(output)
|
122
|
-
expect(input).to eql('foo' => 'bar', :bar => 'baz')
|
123
76
|
end
|
124
77
|
|
125
|
-
it
|
78
|
+
it 'only renames keys and never creates new ones' do
|
126
79
|
map = described_class.t(:rename_keys, 'foo' => :foo, 'bar' => :bar)
|
127
80
|
|
128
|
-
input = { 'bar' => 'baz' }
|
81
|
+
input = { 'bar' => 'baz' }.freeze
|
129
82
|
output = { bar: 'baz' }
|
130
83
|
|
131
84
|
expect(map[input]).to eql(output)
|
132
|
-
expect(input).to eql('bar' => 'baz')
|
133
85
|
end
|
134
86
|
end
|
135
87
|
|
136
|
-
|
137
|
-
it 'returns updated hash with applied functions' do
|
138
|
-
map = described_class.t(:rename_keys!, 'foo' => :foo)
|
88
|
+
it { expect(described_class).not_to be_contain(:rename_keys!) }
|
139
89
|
|
140
|
-
input = { 'foo' => 'bar', :bar => 'baz' }
|
141
|
-
output = { foo: 'bar', bar: 'baz' }
|
142
|
-
|
143
|
-
map[input]
|
144
|
-
|
145
|
-
expect(input).to eql(output)
|
146
|
-
end
|
147
|
-
end
|
148
90
|
describe '.copy_keys' do
|
149
91
|
context 'with single destination key' do
|
150
92
|
it 'returns a new hash with applied functions' do
|
151
93
|
map = described_class.t(:copy_keys, 'foo' => :foo)
|
152
94
|
|
153
|
-
input = { 'foo' => 'bar', :bar => 'baz' }
|
95
|
+
input = { 'foo' => 'bar', :bar => 'baz' }.freeze
|
154
96
|
output = { 'foo' => 'bar', foo: 'bar', bar: 'baz' }
|
155
97
|
|
156
98
|
expect(map[input]).to eql(output)
|
157
|
-
expect(input).to eql('foo' => 'bar', :bar => 'baz')
|
158
99
|
end
|
159
100
|
end
|
160
101
|
|
@@ -162,202 +103,127 @@ describe Transproc::HashTransformations do
|
|
162
103
|
it 'returns a new hash with applied functions' do
|
163
104
|
map = described_class.t(:copy_keys, 'foo' => [:foo, :baz])
|
164
105
|
|
165
|
-
input = { 'foo' => 'bar', :bar => 'baz' }
|
106
|
+
input = { 'foo' => 'bar', :bar => 'baz' }.freeze
|
166
107
|
output = { 'foo' => 'bar', foo: 'bar', baz: 'bar', bar: 'baz' }
|
167
108
|
|
168
109
|
expect(map[input]).to eql(output)
|
169
|
-
expect(input).to eql('foo' => 'bar', :bar => 'baz')
|
170
110
|
end
|
171
111
|
end
|
172
112
|
end
|
173
113
|
|
174
|
-
|
175
|
-
context 'with single destination key' do
|
176
|
-
it 'returns updated hash with applied functions' do
|
177
|
-
map = described_class.t(:copy_keys!, 'foo' => :foo)
|
178
|
-
|
179
|
-
input = { 'foo' => 'bar', :bar => 'baz' }
|
180
|
-
output = { 'foo' => 'bar', foo: 'bar', bar: 'baz' }
|
181
|
-
|
182
|
-
map[input]
|
183
|
-
|
184
|
-
expect(input).to eql(output)
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
context 'with multiple destination keys' do
|
189
|
-
it 'returns updated hash with applied functions' do
|
190
|
-
map = described_class.t(:copy_keys!, 'foo' => [:foo, :baz])
|
191
|
-
|
192
|
-
input = { 'foo' => 'bar', :bar => 'baz' }
|
193
|
-
output = { 'foo' => 'bar', foo: 'bar', baz: 'bar', bar: 'baz' }
|
194
|
-
|
195
|
-
map[input]
|
196
|
-
|
197
|
-
expect(input).to eql(output)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
114
|
+
it { expect(described_class).not_to be_contain(:copy_keys!) }
|
201
115
|
|
202
116
|
describe '.map_value' do
|
203
117
|
it 'applies function to value under specified key' do
|
204
118
|
transformation =
|
205
119
|
described_class.t(:map_value, :user, described_class.t(:symbolize_keys))
|
206
120
|
|
207
|
-
input = { user: { 'name' => 'Jane' } }
|
121
|
+
input = { user: { 'name' => 'Jane' }.freeze }.freeze
|
208
122
|
output = { user: { name: 'Jane' } }
|
209
123
|
|
210
124
|
expect(transformation[input]).to eql(output)
|
211
|
-
expect(input).to eql(user: { 'name' => 'Jane' })
|
212
125
|
end
|
213
126
|
end
|
214
127
|
|
215
|
-
|
216
|
-
it 'applies function to value under specified key' do
|
217
|
-
transformation =
|
218
|
-
described_class
|
219
|
-
.t(:map_value!, :user, described_class.t(:symbolize_keys))
|
220
|
-
|
221
|
-
input = { user: { 'name' => 'Jane' } }
|
222
|
-
output = { user: { name: 'Jane' } }
|
223
|
-
|
224
|
-
transformation[input]
|
225
|
-
|
226
|
-
expect(input).to eql(output)
|
227
|
-
end
|
228
|
-
end
|
128
|
+
it { expect(described_class).not_to be_contain(:map_value!) }
|
229
129
|
|
230
130
|
describe '.nest' do
|
231
131
|
it 'returns new hash with keys nested under a new key' do
|
232
132
|
nest = described_class.t(:nest, :baz, ['foo'])
|
233
133
|
|
234
|
-
input = { 'foo' => 'bar' }
|
134
|
+
input = { 'foo' => 'bar' }.freeze
|
235
135
|
output = { baz: { 'foo' => 'bar' } }
|
236
136
|
|
237
137
|
expect(nest[input]).to eql(output)
|
238
|
-
expect(input).to eql('foo' => 'bar')
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
describe '.nest!' do
|
243
|
-
it 'returns new hash with keys nested under a new key' do
|
244
|
-
nest = described_class.t(:nest!, :baz, %w(one two not-here))
|
245
|
-
|
246
|
-
input = { 'foo' => 'bar', 'one' => nil, 'two' => false }
|
247
|
-
output = { 'foo' => 'bar', baz: { 'one' => nil, 'two' => false } }
|
248
|
-
|
249
|
-
nest[input]
|
250
|
-
|
251
|
-
expect(input).to eql(output)
|
252
138
|
end
|
253
139
|
|
254
140
|
it 'returns new hash with keys nested under the existing key' do
|
255
|
-
nest = described_class.t(:nest
|
141
|
+
nest = described_class.t(:nest, :baz, ['two'])
|
256
142
|
|
257
|
-
input
|
258
|
-
|
143
|
+
input = {
|
144
|
+
'foo' => 'bar',
|
145
|
+
baz: { 'one' => nil }.freeze,
|
146
|
+
'two' => false
|
147
|
+
}.freeze
|
259
148
|
|
260
|
-
|
149
|
+
output = { 'foo' => 'bar', baz: { 'one' => nil, 'two' => false } }
|
261
150
|
|
262
|
-
expect(input).to eql(output)
|
151
|
+
expect(nest[input]).to eql(output)
|
263
152
|
end
|
264
153
|
|
265
154
|
it 'rewrites the existing key if its value is not a hash' do
|
266
|
-
nest = described_class.t(:nest
|
155
|
+
nest = described_class.t(:nest, :baz, ['two'])
|
267
156
|
|
268
|
-
input = { 'foo' => 'bar', baz: 'one', 'two' => false }
|
157
|
+
input = { 'foo' => 'bar', baz: 'one', 'two' => false }.freeze
|
269
158
|
output = { 'foo' => 'bar', baz: { 'two' => false } }
|
270
159
|
|
271
|
-
nest[input]
|
272
|
-
|
273
|
-
expect(input).to eql(output)
|
160
|
+
expect(nest[input]).to eql(output)
|
274
161
|
end
|
275
162
|
|
276
163
|
it 'returns new hash with an empty hash under a new key when nest-keys are missing' do
|
277
|
-
nest = described_class.t(:nest
|
164
|
+
nest = described_class.t(:nest, :baz, ['foo'])
|
278
165
|
|
279
|
-
input = { 'bar' => 'foo' }
|
166
|
+
input = { 'bar' => 'foo' }.freeze
|
280
167
|
output = { 'bar' => 'foo', baz: {} }
|
281
168
|
|
282
|
-
nest[input]
|
283
|
-
|
284
|
-
expect(input).to eql(output)
|
169
|
+
expect(nest[input]).to eql(output)
|
285
170
|
end
|
286
171
|
end
|
287
172
|
|
288
|
-
|
289
|
-
it 'returns updated hash with nested keys lifted to the root' do
|
290
|
-
unwrap = described_class.t(:unwrap!, 'wrapped', %w(one))
|
173
|
+
it { expect(described_class).not_to be_contain(:nest!) }
|
291
174
|
|
292
|
-
|
293
|
-
|
175
|
+
describe '.unwrap' do
|
176
|
+
it 'returns new hash with nested keys lifted to the root' do
|
177
|
+
unwrap = described_class.t(:unwrap, 'wrapped', %w(one))
|
178
|
+
|
179
|
+
input = {
|
180
|
+
'foo' => 'bar',
|
181
|
+
'wrapped' => { 'one' => nil, 'two' => false }.freeze
|
182
|
+
}.freeze
|
294
183
|
|
295
|
-
|
184
|
+
output = { 'foo' => 'bar', 'one' => nil, 'wrapped' => { 'two' => false } }
|
296
185
|
|
297
|
-
expect(input).to eql(output)
|
186
|
+
expect(unwrap[input]).to eql(output)
|
298
187
|
end
|
299
188
|
|
300
189
|
it 'lifts all keys if none are passed' do
|
301
|
-
unwrap = described_class.t(:unwrap
|
190
|
+
unwrap = described_class.t(:unwrap, 'wrapped')
|
302
191
|
|
303
|
-
input = { 'wrapped' => { 'one' => nil, 'two' => false } }
|
192
|
+
input = { 'wrapped' => { 'one' => nil, 'two' => false }.freeze }.freeze
|
304
193
|
output = { 'one' => nil, 'two' => false }
|
305
194
|
|
306
|
-
unwrap[input]
|
307
|
-
|
308
|
-
expect(input).to eql(output)
|
195
|
+
expect(unwrap[input]).to eql(output)
|
309
196
|
end
|
310
197
|
|
311
198
|
it 'ignores unknown keys' do
|
312
|
-
unwrap = described_class.t(:unwrap
|
199
|
+
unwrap = described_class.t(:unwrap, 'wrapped', %w(one two three))
|
313
200
|
|
314
|
-
input = { 'wrapped' => { 'one' => nil, 'two' => false } }
|
201
|
+
input = { 'wrapped' => { 'one' => nil, 'two' => false }.freeze }.freeze
|
315
202
|
output = { 'one' => nil, 'two' => false }
|
316
203
|
|
317
|
-
unwrap[input]
|
318
|
-
|
319
|
-
expect(input).to eql(output)
|
204
|
+
expect(unwrap[input]).to eql(output)
|
320
205
|
end
|
321
206
|
|
322
207
|
it 'prefixes unwrapped keys and retains root string type if prefix option is truthy' do
|
323
|
-
unwrap = described_class.t(:unwrap
|
208
|
+
unwrap = described_class.t(:unwrap, 'wrapped', prefix: true)
|
324
209
|
|
325
|
-
input = { 'wrapped' => { one: nil, two: false } }
|
210
|
+
input = { 'wrapped' => { one: nil, two: false }.freeze }.freeze
|
326
211
|
output = { 'wrapped_one' => nil, 'wrapped_two' => false }
|
327
212
|
|
328
|
-
unwrap[input]
|
329
|
-
|
330
|
-
expect(input).to eql(output)
|
213
|
+
expect(unwrap[input]).to eql(output)
|
331
214
|
end
|
332
215
|
|
333
216
|
it 'prefixes unwrapped keys and retains root type if prefix option is truthy' do
|
334
|
-
unwrap = described_class.t(:unwrap
|
217
|
+
unwrap = described_class.t(:unwrap, :wrapped, prefix: true)
|
335
218
|
|
336
|
-
input = { wrapped: { 'one' => nil, 'two' => false } }
|
219
|
+
input = { wrapped: { 'one' => nil, 'two' => false }.freeze }.freeze
|
337
220
|
output = { wrapped_one: nil, wrapped_two: false }
|
338
221
|
|
339
|
-
unwrap[input]
|
340
|
-
|
341
|
-
expect(input).to eql(output)
|
222
|
+
expect(unwrap[input]).to eql(output)
|
342
223
|
end
|
343
224
|
end
|
344
225
|
|
345
|
-
|
346
|
-
it 'returns new hash with nested keys lifted to the root' do
|
347
|
-
unwrap = described_class.t(:unwrap, 'wrapped')
|
348
|
-
|
349
|
-
input = {
|
350
|
-
'foo' => 'bar',
|
351
|
-
'wrapped' => { 'one' => nil, 'two' => false }
|
352
|
-
}.freeze
|
353
|
-
|
354
|
-
expect(unwrap[input]).to eql(
|
355
|
-
'foo' => 'bar',
|
356
|
-
'one' => nil,
|
357
|
-
'two' => false
|
358
|
-
)
|
359
|
-
end
|
360
|
-
end
|
226
|
+
it { expect(described_class).not_to be_contain(:unwrap!) }
|
361
227
|
|
362
228
|
describe 'nested transform' do
|
363
229
|
it 'applies functions to nested hashes' do
|
@@ -389,90 +255,62 @@ describe Transproc::HashTransformations do
|
|
389
255
|
end
|
390
256
|
end
|
391
257
|
|
392
|
-
describe '.reject_keys!' do
|
393
|
-
it 'returns an updated hash with rejected keys' do
|
394
|
-
reject_keys = described_class.t(:reject_keys, [:name, :age])
|
395
|
-
|
396
|
-
input = { name: 'Jane', email: 'jane@doe.org', age: 21 }
|
397
|
-
output = { email: 'jane@doe.org' }
|
398
|
-
|
399
|
-
expect(reject_keys[input]).to eql(output)
|
400
|
-
end
|
401
|
-
end
|
402
|
-
|
403
258
|
describe '.reject_keys' do
|
404
259
|
it 'returns a new hash with rejected keys' do
|
405
260
|
reject_keys = described_class.t(:reject_keys, [:name, :age])
|
406
261
|
|
407
|
-
input = { name: 'Jane', email: 'jane@doe.org', age: 21 }
|
262
|
+
input = { name: 'Jane', email: 'jane@doe.org', age: 21 }.freeze
|
408
263
|
output = { email: 'jane@doe.org' }
|
409
264
|
|
410
265
|
expect(reject_keys[input]).to eql(output)
|
411
|
-
expect(input).to eql(name: 'Jane', email: 'jane@doe.org', age: 21)
|
412
266
|
end
|
413
267
|
end
|
414
268
|
|
415
|
-
|
416
|
-
it 'returns an updated hash with accepted keys' do
|
417
|
-
accept_keys = described_class.t(:accept_keys, [:age])
|
418
|
-
|
419
|
-
input = { name: 'Jane', email: 'jane@doe.org', age: 21 }
|
420
|
-
output = { age: 21 }
|
421
|
-
|
422
|
-
expect(accept_keys[input]).to eql(output)
|
423
|
-
end
|
424
|
-
end
|
269
|
+
it { expect(described_class).not_to be_contain(:reject_keys!) }
|
425
270
|
|
426
|
-
describe '.
|
271
|
+
describe '.accept_keys' do
|
427
272
|
it 'returns a new hash with rejected keys' do
|
428
273
|
accept_keys = described_class.t(:accept_keys, [:age])
|
429
274
|
|
430
|
-
input = { name: 'Jane', email: 'jane@doe.org', age: 21 }
|
275
|
+
input = { name: 'Jane', email: 'jane@doe.org', age: 21 }.freeze
|
431
276
|
output = { age: 21 }
|
432
277
|
|
433
278
|
expect(accept_keys[input]).to eql(output)
|
434
|
-
expect(input).to eql(name: 'Jane', email: 'jane@doe.org', age: 21)
|
435
279
|
end
|
436
280
|
end
|
437
281
|
|
282
|
+
it { expect(described_class).not_to be_contain(:accept_keys!) }
|
283
|
+
|
438
284
|
describe '.fold' do
|
439
285
|
let(:input) do
|
440
286
|
{
|
441
287
|
name: 'Jane',
|
442
|
-
tasks: [
|
443
|
-
|
288
|
+
tasks: [
|
289
|
+
{ title: 'be nice', priority: 1 }.freeze,
|
290
|
+
{ title: 'sleep well' }.freeze
|
291
|
+
].freeze
|
292
|
+
}.freeze
|
444
293
|
end
|
445
294
|
|
446
|
-
|
447
|
-
|
448
|
-
let(:output) { { name: 'Jane', tasks: ['be nice', 'sleep well'] } }
|
449
|
-
end
|
295
|
+
it 'returns a new hash with folded values' do
|
296
|
+
fold = described_class.t(:fold, :tasks, :title)
|
450
297
|
|
451
|
-
|
452
|
-
let(:arguments) { [:fold, :tasks, :priority] }
|
453
|
-
let(:output) { { name: 'Jane', tasks: [1, nil] } }
|
454
|
-
end
|
455
|
-
end
|
298
|
+
output = { name: 'Jane', tasks: ['be nice', 'sleep well'] }
|
456
299
|
|
457
|
-
|
458
|
-
let(:input) do
|
459
|
-
{
|
460
|
-
name: 'Jane',
|
461
|
-
tasks: [{ title: 'be nice', priority: 1 }, { title: 'sleep well' }]
|
462
|
-
}
|
300
|
+
expect(fold[input]).to eql(output)
|
463
301
|
end
|
464
302
|
|
465
|
-
|
466
|
-
|
467
|
-
let(:output) { { name: 'Jane', tasks: ['be nice', 'sleep well'] } }
|
468
|
-
end
|
303
|
+
it 'uses nil if there was not such attribute' do
|
304
|
+
fold = described_class.t(:fold, :tasks, :priority)
|
469
305
|
|
470
|
-
|
471
|
-
|
472
|
-
|
306
|
+
output = { name: 'Jane', tasks: [1, nil] }
|
307
|
+
|
308
|
+
expect(fold[input]).to eql(output)
|
473
309
|
end
|
474
310
|
end
|
475
311
|
|
312
|
+
it { expect(described_class).not_to be_contain(:fold!) }
|
313
|
+
|
476
314
|
describe '.split' do
|
477
315
|
let(:input) do
|
478
316
|
{
|