hash_engine 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +1 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +52 -0
- data/Guardfile +24 -0
- data/README.txt +320 -0
- data/Rakefile +3 -0
- data/hash_engine.gemspec +21 -0
- data/lib/hash_engine.rb +20 -0
- data/lib/hash_engine/actions.rb +82 -0
- data/lib/hash_engine/add_error.rb +13 -0
- data/lib/hash_engine/conditionals.rb +32 -0
- data/lib/hash_engine/csv_parse.rb +49 -0
- data/lib/hash_engine/extract.rb +139 -0
- data/lib/hash_engine/fetchers.rb +27 -0
- data/lib/hash_engine/format.rb +62 -0
- data/lib/hash_engine/transform.rb +196 -0
- data/spec/hash_engine/actions_spec.rb +146 -0
- data/spec/hash_engine/conditional_spec.rb +28 -0
- data/spec/hash_engine/csv_parse_spec.rb +42 -0
- data/spec/hash_engine/csv_transform_spec.rb +90 -0
- data/spec/hash_engine/ds_spec.rb +178 -0
- data/spec/hash_engine/extract_spec.rb +144 -0
- data/spec/hash_engine/fetchers_spec.rb +30 -0
- data/spec/hash_engine/format_spec.rb +55 -0
- data/spec/hash_engine/transform_spec.rb +365 -0
- data/spec/hash_engine_spec.rb +0 -0
- data/spec/spec_helper.rb +12 -0
- metadata +82 -0
@@ -0,0 +1,146 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'hash_engine'
|
3
|
+
|
4
|
+
describe HashEngine do
|
5
|
+
describe 'valid_action?' do
|
6
|
+
it 'returns true when key exists' do
|
7
|
+
HashEngine.valid_action?('first_value').should be_true
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'returns false when key does not exist' do
|
11
|
+
HashEngine.valid_action?('foo').should be_false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'action' do
|
16
|
+
describe 'of type: proc' do
|
17
|
+
describe 'with data as an array' do
|
18
|
+
it 'returns nil when there is a nil in the data' do
|
19
|
+
HashEngine.action('proc', 'proc {|x, y| x[1..3]}', [nil, :key1]).should == nil
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'returns the result of the proc' do
|
23
|
+
my_proc = Proc.new {|x| x[0..2]}
|
24
|
+
HashEngine.action('proc', my_proc, ['foobar']).should == 'foo'
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns the result of the string evaluated to be a proc' do
|
28
|
+
HashEngine.action('proc', 'proc {|x| x[0..2]}', ['foobar']).should == 'foo'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'with data as a single value' do
|
33
|
+
it 'returns nil when there is a nil in the data' do
|
34
|
+
HashEngine.action('proc', 'proc {|x, y| x[1..3]}', nil).should == nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'returns the result of the proc' do
|
38
|
+
my_proc = Proc.new {|x| x[0..2]}
|
39
|
+
HashEngine.action('proc', my_proc, 'foobar').should == 'foo'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'returns the result of the string evaluated to be a proc' do
|
43
|
+
HashEngine.action('proc', 'proc {|x| x[0..2]}', 'foobar').should == 'foo'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'of type: unprotected_proc' do
|
49
|
+
describe 'with data as an array' do
|
50
|
+
it 'returns the result of the proc' do
|
51
|
+
my_proc = Proc.new {|x| x.nil? ? "nil" : x}
|
52
|
+
HashEngine.action('unprotected_proc', my_proc, [nil]).should == 'nil'
|
53
|
+
my_proc = Proc.new {|x, y| x.nil? ? "nil" : x}
|
54
|
+
HashEngine.action('unprotected_proc', my_proc, [nil, :key1]).should == 'nil'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns the result of the string evaluated to be a proc' do
|
58
|
+
HashEngine.action('unprotected_proc', 'proc {|x, y| x.nil? ? "nil" : x}', [nil, :key1]).should == 'nil'
|
59
|
+
HashEngine.action('proc', 'proc {|x| x[1..3]}', ['1234567']).should == '234'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'of type: lookup_map' do
|
65
|
+
it 'returns the lookup value' do
|
66
|
+
action_data = {:key1 => :value1,
|
67
|
+
:key2 => :value2}
|
68
|
+
HashEngine.action('lookup_map', action_data, :key1).should == :value1
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'returns nil on a miss' do
|
72
|
+
action_data = {:key1 => :value1,
|
73
|
+
:key2 => :value2}
|
74
|
+
HashEngine.action('lookup_map', action_data, :key3).should == nil
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns the literal default on a miss' do
|
78
|
+
action_data = {:key1 => :value1,
|
79
|
+
:key2 => :value2,
|
80
|
+
'default' => :default}
|
81
|
+
HashEngine.action('lookup_map', action_data, :key3).should == :default
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'returns the key on a miss' do
|
85
|
+
action_data = {:key1 => :value1,
|
86
|
+
:key2 => :value2,
|
87
|
+
'default_to_key' => true}
|
88
|
+
HashEngine.action('lookup_map', action_data, :key3).should == :key3
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe 'of type: first_value' do
|
93
|
+
it 'returns data if data is not an array' do
|
94
|
+
HashEngine.action('first_value', nil, '0123456789').should == '0123456789'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'returns the first non-nil value' do
|
98
|
+
HashEngine.action('first_value', nil, [nil, '0123456789']).should == '0123456789'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'of type: join' do
|
103
|
+
it 'returns data elements joined' do
|
104
|
+
HashEngine.action('join', nil, ['foo', 'bar']).should == 'foobar'
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns data elements as strings joined' do
|
108
|
+
HashEngine.action('join', nil, [:foo, :bar]).should == 'foobar'
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'returns data elements joined by specified seperator' do
|
112
|
+
HashEngine.action('join', ', ', ['foo', 'bar']).should == 'foo, bar'
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'returns data elements with an included nil joined by specified seperator' do
|
116
|
+
HashEngine.action('join', ', ', [nil, 'bar']).should == ', bar'
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'returns data if data is not an array' do
|
120
|
+
HashEngine.action('join', ', ', 'foo').should == 'foo'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe 'of type: max_length' do
|
125
|
+
it 'returns an unaltered string when less than length' do
|
126
|
+
HashEngine.action('max_length', 50, '0123456789').should == '0123456789'
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'returns a number as a string when less than length' do
|
130
|
+
HashEngine.action('max_length', 50, 123456789).should == '123456789'
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'trims the string when longer than length' do
|
134
|
+
HashEngine.action('max_length', 5, '0123456789').should == '01234'
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'trims a number when longer than length' do
|
138
|
+
HashEngine.action('max_length', 5, 123456789).should == '12345'
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'trims unicode string when longer than length' do
|
142
|
+
HashEngine.action('max_length', 3, 'ÑAlaman').should == 'ÑAl'
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'hash_engine'
|
2
|
+
|
3
|
+
describe HashEngine do
|
4
|
+
describe 'conditional operations' do
|
5
|
+
# left_op right_op operation expected
|
6
|
+
[[1, 2, 'ne', true],
|
7
|
+
[1, 1, 'ne', false],
|
8
|
+
[1, 1, 'eq', true],
|
9
|
+
[1, 2, 'eq', false],
|
10
|
+
[1, 2, 'lt', true],
|
11
|
+
[1, 1, 'lt', false],
|
12
|
+
[2, 1, 'gt', true],
|
13
|
+
[1, 1, 'gt', false],
|
14
|
+
[1, 2, 'lteq', true],
|
15
|
+
[1, 1, 'lteq', true],
|
16
|
+
[2, 1, 'lteq', false],
|
17
|
+
[2, 1, 'gteq', true],
|
18
|
+
[2, 2, 'gteq', true],
|
19
|
+
[1, 2, 'gteq', false],
|
20
|
+
[1, '', 'exist', true],
|
21
|
+
[nil, '', 'exist', false],
|
22
|
+
].each {|left_operand, right_operand, operation, expected|
|
23
|
+
it "#{left_operand.inspect} #{operation} #{right_operand.inspect} should be #{expected}" do
|
24
|
+
HashEngine.conditional(operation, left_operand, right_operand).should == expected
|
25
|
+
end
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'hash_engine'
|
2
|
+
|
3
|
+
describe HashEngine::CSVParse do
|
4
|
+
describe 'parse_line' do
|
5
|
+
context 'returns correct hash for' do
|
6
|
+
it 'simple case' do
|
7
|
+
expected = {'field1' => 'foo', 'field2' => 'bar', 'field3' => 'baz', :error => []}
|
8
|
+
string = 'foo,bar,baz'
|
9
|
+
headers = %w( field1 field2 field3 )
|
10
|
+
HashEngine.parse_line(string, headers).should == expected
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'field with quote' do
|
14
|
+
expected = {'field1' => 'foo', 'field2' => '15"', 'field3' => 'baz', :error => []}
|
15
|
+
string = 'foo,15"",baz'
|
16
|
+
headers = %w( field1 field2 field3 )
|
17
|
+
HashEngine.parse_line(string, headers).should == expected
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'quoted field case' do
|
21
|
+
expected = {'field1' => 'fubar, real bad', 'field2' => 'bar', 'field3' => 'baz', :error => []}
|
22
|
+
string = '"fubar, real bad",bar,baz'
|
23
|
+
headers = %w( field1 field2 field3 )
|
24
|
+
HashEngine.parse_line(string, headers).should == expected
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'nil case' do
|
28
|
+
expected = {'field1' => 'foo', 'field2' => nil, 'field3' => 'baz', :error => []}
|
29
|
+
string = 'foo,,baz'
|
30
|
+
headers = %w( field1 field2 field3 )
|
31
|
+
HashEngine.parse_line(string, headers).should == expected
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'alternate delimiter case' do
|
35
|
+
expected = {'field1' => 'foo', 'field2' => 'bar', 'field3' => 'baz', :error => []}
|
36
|
+
string = 'foo|bar|baz'
|
37
|
+
headers = %w( field1 field2 field3 )
|
38
|
+
HashEngine.parse_line(string, headers, '|').should == expected
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'hash_engine'
|
2
|
+
|
3
|
+
describe HashEngine do
|
4
|
+
describe 'csv transform' do
|
5
|
+
# Given String:
|
6
|
+
# ok|http://www.domain.com|1234567890
|
7
|
+
# Given Instructions:
|
8
|
+
# delimiter: '|'
|
9
|
+
# hash_keys:
|
10
|
+
# - status:
|
11
|
+
# lookup_map:
|
12
|
+
# ok: accepted
|
13
|
+
# decline: reject
|
14
|
+
# default: error
|
15
|
+
# - payload:
|
16
|
+
# - uuid:
|
17
|
+
# Return:
|
18
|
+
# status: accepted
|
19
|
+
# payload: http://www.domain.com
|
20
|
+
# uuid: 1234567890
|
21
|
+
|
22
|
+
it 'nil case' do
|
23
|
+
string = 'ok||1234567890'
|
24
|
+
instructions = {'delimiter' => '|',
|
25
|
+
'allow_nil' => true,
|
26
|
+
'suppress_nil' => false,
|
27
|
+
'header' => ['status',
|
28
|
+
'payload',
|
29
|
+
'uuid'],
|
30
|
+
'fields' => {'status' => {'input' => 'status'},
|
31
|
+
'payload' => {'input' => 'payload'},
|
32
|
+
'uuid' => {'input' => 'uuid'}} }
|
33
|
+
expected = {:error => [],
|
34
|
+
'status' => 'ok',
|
35
|
+
'payload' => nil,
|
36
|
+
'uuid' => '1234567890'}
|
37
|
+
HashEngine.csv_transform(string, instructions).should == expected
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'trivial case' do
|
41
|
+
string = 'ok|http://www.domain.com|1234567890'
|
42
|
+
instructions = {'delimiter' => '|',
|
43
|
+
'header' => ['status',
|
44
|
+
'payload',
|
45
|
+
'uuid'],
|
46
|
+
'fields' => {'status' => 'status',
|
47
|
+
'payload' => 'payload',
|
48
|
+
'uuid' => 'uuid'} }
|
49
|
+
expected = {:error => [],
|
50
|
+
'status' => 'ok',
|
51
|
+
'payload' => 'http://www.domain.com',
|
52
|
+
'uuid' => '1234567890'}
|
53
|
+
HashEngine.csv_transform(string, instructions).should == expected
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'simple formatting' do
|
57
|
+
string = 'ok|http://www.domain.com|ABCD1234'
|
58
|
+
instructions = {'delimiter' => '|',
|
59
|
+
'header' => ['status',
|
60
|
+
'payload',
|
61
|
+
'uuid'],
|
62
|
+
'fields' => {'status' => {'input' => 'status'},
|
63
|
+
'payload' => {'input' => 'payload'},
|
64
|
+
'uuid' => {'input' => 'uuid', 'format' => 'numeric'}}}
|
65
|
+
expected = {:error => [],
|
66
|
+
'status' => 'ok',
|
67
|
+
'payload' => 'http://www.domain.com',
|
68
|
+
'uuid' => '1234'}
|
69
|
+
HashEngine.csv_transform(string, instructions).should == expected
|
70
|
+
end
|
71
|
+
it 'processiong case' do
|
72
|
+
string = 'ok|http://www.domain.com|1234567890'
|
73
|
+
instructions = {'delimiter' => '|',
|
74
|
+
'header' => ['status',
|
75
|
+
'payload',
|
76
|
+
'uuid'],
|
77
|
+
'fields' => {'status' => {'input' => 'status',
|
78
|
+
'lookup_map' =>{'ok' => 'accepted',
|
79
|
+
'decline' => 'reject',
|
80
|
+
'default' => 'error'}},
|
81
|
+
'payload' => {'input' => 'payload'},
|
82
|
+
'uuid' => {'input' => 'uuid'}} }
|
83
|
+
expected = {:error => [],
|
84
|
+
'status' => 'accepted',
|
85
|
+
'payload' => 'http://www.domain.com',
|
86
|
+
'uuid' => '1234567890'}
|
87
|
+
HashEngine.csv_transform(string, instructions).should == expected
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'hash_engine'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
describe HashEngine do
|
5
|
+
let(:data) { {'first'=>'Firstname', 'last'=>'Lastname', 'set_number' => 12} }
|
6
|
+
let(:alt_data) { {'first'=>'Firstname', 'set_number' => 12} }
|
7
|
+
|
8
|
+
it 'joins first+seperator+last' do
|
9
|
+
instructions = {'fields'=>
|
10
|
+
{'name_field'=>
|
11
|
+
[{'data' => ['first',
|
12
|
+
'last']},
|
13
|
+
{'join'=> '\#' }]}}
|
14
|
+
results = HashEngine.transform(data, instructions)
|
15
|
+
results['name_field'].should == 'Firstname\#Lastname'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'joins first+seperator+first+seperator+first+seperator+last' do
|
19
|
+
instructions = {'fields'=>
|
20
|
+
{'name_field'=>
|
21
|
+
[{'data' => ['first',
|
22
|
+
'first',
|
23
|
+
'first',
|
24
|
+
'last']},
|
25
|
+
{'join'=> '\#' }]}}
|
26
|
+
results = HashEngine.transform(data, instructions)
|
27
|
+
results['name_field'].should == 'Firstname\#Firstname\#Firstname\#Lastname'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'joins last+seperator+first' do
|
31
|
+
instructions = {'fields'=>
|
32
|
+
{'name_field'=>
|
33
|
+
[{'data' => ['last',
|
34
|
+
'first']},
|
35
|
+
{'join'=> '\#' }]}}
|
36
|
+
results = HashEngine.transform(data, instructions)
|
37
|
+
results['name_field'].should == 'Lastname\#Firstname'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'joins last+seperator+last+seperator+first' do
|
41
|
+
instructions = {'fields'=>
|
42
|
+
{'name_field'=>
|
43
|
+
[{'data' => ['last',
|
44
|
+
'last',
|
45
|
+
'first']},
|
46
|
+
{'join'=> '\#' }]}}
|
47
|
+
results = HashEngine.transform(data, instructions)
|
48
|
+
results['name_field'].should == 'Lastname\#Lastname\#Firstname'
|
49
|
+
end
|
50
|
+
|
51
|
+
it '"#{first_name}#{separator}#{last_name}<Wrapper=#{wrapper_set}>"' do
|
52
|
+
yaml =<<EOYAML
|
53
|
+
fields:
|
54
|
+
name_field:
|
55
|
+
- subgroup:
|
56
|
+
data:
|
57
|
+
- first
|
58
|
+
- last
|
59
|
+
join: '\\#'
|
60
|
+
- literal: '<Wrapper='
|
61
|
+
- input: set_number
|
62
|
+
- literal: '>'
|
63
|
+
- join:
|
64
|
+
EOYAML
|
65
|
+
instructions = YAML.load yaml
|
66
|
+
results = HashEngine.transform(data, instructions)
|
67
|
+
results['name_field'].should == 'Firstname\#Lastname<Wrapper=12>'
|
68
|
+
end
|
69
|
+
|
70
|
+
it '"#{first_name}#{separator}#{last_name}#{separator}#{first_name}#{separator}#{last_name}#{separator}#{first_name}#{separator}#{last_name}#{separator}#{first_name}#{separator}#{last_name}#{separator}#{first_name}#{separator}#{last_name}"' do
|
71
|
+
instructions = {'fields'=>
|
72
|
+
{'name_field'=>
|
73
|
+
[{'data' => [ 'first','last','first','last','first','last','first','last','first','last' ]},
|
74
|
+
{'join'=> '\#' }]}}
|
75
|
+
results = HashEngine.transform(data, instructions)
|
76
|
+
results['name_field'].should == 'Firstname\#Lastname\#Firstname\#Lastname\#Firstname\#Lastname\#Firstname\#Lastname\#Firstname\#Lastname'
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'last_name.present? ? "#{first_name}#{separator}#{last_name}" : "#{first_name}#{separator}#{first_name}"' do
|
80
|
+
let(:instructions) do
|
81
|
+
{'fields'=>
|
82
|
+
{'name_field'=>
|
83
|
+
[{'input' => 'first'},
|
84
|
+
{'data' => ['last',
|
85
|
+
'first']},
|
86
|
+
{'first_value'=>nil},
|
87
|
+
{'join'=> '\#' }]}}
|
88
|
+
yaml =<<EOYAML
|
89
|
+
fields:
|
90
|
+
name_field:
|
91
|
+
- input: first
|
92
|
+
- subgroup:
|
93
|
+
data:
|
94
|
+
- last
|
95
|
+
- first
|
96
|
+
first_value:
|
97
|
+
- join: '\\#'
|
98
|
+
EOYAML
|
99
|
+
instructions = YAML.load yaml
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'last name present' do
|
103
|
+
results = HashEngine.transform(data, instructions)
|
104
|
+
results['name_field'].should == 'Firstname\#Lastname'
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'last name blank' do
|
108
|
+
results = HashEngine.transform(alt_data, instructions)
|
109
|
+
results['name_field'].should == 'Firstname\#Firstname'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'last_name.present? ? "#{last_name}" : "#{first_name}"' do
|
114
|
+
let(:instructions) do
|
115
|
+
{'fields'=>
|
116
|
+
{'name_field'=>
|
117
|
+
[{'data' => ['last',
|
118
|
+
'first']},
|
119
|
+
{'first_value'=>nil}]}}
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'last name present' do
|
123
|
+
results = HashEngine.transform(data, instructions)
|
124
|
+
results['name_field'].should == 'Lastname'
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'last name blank' do
|
128
|
+
results = HashEngine.transform(alt_data, instructions)
|
129
|
+
results['name_field'].should == 'Firstname'
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'last_name.present? ? "#{first_name}#{separator}#{last_name}" : "#{separator}#{first_name}"' do
|
134
|
+
let(:instructions) do
|
135
|
+
yaml =<<EOYAML
|
136
|
+
fields:
|
137
|
+
name_field:
|
138
|
+
- conditional_input:
|
139
|
+
input: last
|
140
|
+
test: ne
|
141
|
+
test_value:
|
142
|
+
true:
|
143
|
+
input: first
|
144
|
+
false:
|
145
|
+
literal: ''
|
146
|
+
- subgroup_input:
|
147
|
+
data:
|
148
|
+
- last
|
149
|
+
- first
|
150
|
+
first_value:
|
151
|
+
- join: '\\#'
|
152
|
+
EOYAML
|
153
|
+
YAML.load yaml
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'last name present' do
|
157
|
+
pending
|
158
|
+
results = HashEngine.transform(data, instructions)
|
159
|
+
results['name_field'].should == 'Firstname\#Lastname'
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'last name blank' do
|
163
|
+
pending
|
164
|
+
results = HashEngine.transform(alt_data, instructions)
|
165
|
+
results['name_field'].should == '\#Firstname'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it '"#{first_name} #{last_name}"' do
|
170
|
+
instructions = {'fields'=>
|
171
|
+
{'name_field'=>
|
172
|
+
[{'data' => ['first',
|
173
|
+
'last']},
|
174
|
+
{'join'=> ' ' }]}}
|
175
|
+
results = HashEngine.transform(data, instructions)
|
176
|
+
results['name_field'].should == 'Firstname Lastname'
|
177
|
+
end
|
178
|
+
end
|