chemicals 0.1.2
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.
- data/.gitignore +17 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/LICENSE +22 -0
- data/README.md +36 -0
- data/Rakefile +10 -0
- data/chemicals.gemspec +24 -0
- data/lib/chemicals.rb +5 -0
- data/lib/chemicals/.DS_Store +0 -0
- data/lib/chemicals/parser.rb +97 -0
- data/lib/chemicals/renderer.rb +72 -0
- data/lib/chemicals/template.rb +94 -0
- data/lib/chemicals/version.rb +3 -0
- data/spec/chemicals/chemicals_spec.rb +201 -0
- data/spec/chemicals/chemicals_spec_helper.rb +14 -0
- data/spec/chemicals/examples.yml +517 -0
- data/spec/chemicals/parser_spec.rb +252 -0
- data/spec/chemicals/renderer_spec.rb +201 -0
- metadata +150 -0
@@ -0,0 +1,252 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/spec'
|
5
|
+
|
6
|
+
require 'mocha'
|
7
|
+
|
8
|
+
require_relative 'chemicals_spec_helper'
|
9
|
+
|
10
|
+
require 'chemicals'
|
11
|
+
|
12
|
+
describe Chemicals::Parser do
|
13
|
+
|
14
|
+
it 'should be able to reuse the document if the source is already a parsed nokogiri document' do
|
15
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_text
|
16
|
+
parsed = Nokogiri::XML(raw)
|
17
|
+
parsed.expects(:to_s).never
|
18
|
+
template.parse(parsed).must_equal 'John Doe'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should provide an option to not symbolize keys' do
|
22
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_text_alias
|
23
|
+
template = Chemicals::Template.new(template.raw.to_s, symbolize_keys: false)
|
24
|
+
template.parse(raw).must_equal \
|
25
|
+
'name' => 'John Doe'
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'parsing a text node' do
|
29
|
+
it 'parses the content as the direct data of the parent node when it is aliased as @' do
|
30
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_text
|
31
|
+
template.parse(raw).must_equal 'John Doe'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'parses the content wrapped into its alias' do
|
35
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_text_alias
|
36
|
+
template.parse(raw).must_equal \
|
37
|
+
name: 'John Doe'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'skips the node when no alias is provided' do
|
41
|
+
template, raw = ChemicalsSpecHelper.test_example :skip_text_node
|
42
|
+
template.parse(raw).must_equal \
|
43
|
+
name: { last_name: 'Doe' }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'parsing an element' do
|
48
|
+
it 'parses the content wrapped into its alias' do
|
49
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_element_alias
|
50
|
+
template.parse(raw).must_equal \
|
51
|
+
individual: 'John Doe'
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'skips the element when no alias is provided' do
|
55
|
+
template, raw = ChemicalsSpecHelper.test_example :skip_element
|
56
|
+
template.parse(raw).must_equal \
|
57
|
+
individual: 'John Doe'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'parsing a collection of elements' do
|
62
|
+
it 'should parse empty collections' do
|
63
|
+
template, raw = ChemicalsSpecHelper.test_example :empty_collection
|
64
|
+
template.parse(raw).must_equal []
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should parse each element' do
|
68
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_collection
|
69
|
+
template.parse(raw).must_equal \
|
70
|
+
emails: [
|
71
|
+
'john.doe@gmail.com',
|
72
|
+
'john@acme.com'
|
73
|
+
]
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should parse multiple collections independently' do
|
77
|
+
template, raw = ChemicalsSpecHelper.test_example :multiple_collections
|
78
|
+
template.parse(raw).must_equal \
|
79
|
+
contact: {
|
80
|
+
emails: [
|
81
|
+
'john.doe@gmail.com',
|
82
|
+
'john@acme.com'
|
83
|
+
],
|
84
|
+
phone_numbers: ['1', '2']
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should be able to collect in the presence of other elements' do
|
89
|
+
template, raw = ChemicalsSpecHelper.test_example :mixed_collection
|
90
|
+
template.parse(raw).must_equal \
|
91
|
+
contact: {
|
92
|
+
emails: [
|
93
|
+
'john.doe@gmail.com',
|
94
|
+
'john@acme.com'
|
95
|
+
],
|
96
|
+
name: 'John Doe'
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should be able to collect multiple collections in the presence of other elements' do
|
101
|
+
template, raw = ChemicalsSpecHelper.test_example :mixed_collections
|
102
|
+
template.parse(raw).must_equal \
|
103
|
+
contact: {
|
104
|
+
emails: [
|
105
|
+
{ address: 'john.doe@gmail.com', label: 'work' },
|
106
|
+
{ address:'john@acme.com' }
|
107
|
+
],
|
108
|
+
phones: ['1'],
|
109
|
+
name: 'John Doe'
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should be able to extreme collect multiple collections in the presence of other elements' do
|
114
|
+
template, raw = ChemicalsSpecHelper.test_example :mixed_collections_extreme
|
115
|
+
template.parse(raw).must_equal \
|
116
|
+
[{
|
117
|
+
emails: [
|
118
|
+
{ address: 'john.doe@gmail.com', label: 'work' },
|
119
|
+
{ address:'john@acme.com' }
|
120
|
+
],
|
121
|
+
phones: ['1'],
|
122
|
+
name: 'John Doe'
|
123
|
+
},
|
124
|
+
{
|
125
|
+
phones: ['1', '2', '3'],
|
126
|
+
addresses: [{ country: 'Belgium', country_code: 'BE',
|
127
|
+
street: 'Désiré Van Monckhovenstraat', housenumber: '123' }]
|
128
|
+
}]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'should parse mixed elements, collections and text nodes' do
|
133
|
+
template, raw = ChemicalsSpecHelper.test_example :mixed_elements_text
|
134
|
+
template.parse(raw).must_equal \
|
135
|
+
[
|
136
|
+
{
|
137
|
+
name: { given: 'John', family: 'Doe' },
|
138
|
+
emails: ['john.doe@gmail.com', 'john@acme.com'],
|
139
|
+
phones: [
|
140
|
+
{ country: 'Belgium', number: '1' },
|
141
|
+
{ country: 'USA', number: '2' }
|
142
|
+
]
|
143
|
+
},
|
144
|
+
{
|
145
|
+
name: { given: 'Jane' },
|
146
|
+
emails: [ 'jane.doe@gmail.com' ]
|
147
|
+
}
|
148
|
+
]
|
149
|
+
end
|
150
|
+
|
151
|
+
describe 'parsing attributes' do
|
152
|
+
it 'should parse attributes with aliases' do
|
153
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_attributes
|
154
|
+
template.parse(raw).must_equal \
|
155
|
+
full_name: 'John Doe'
|
156
|
+
end
|
157
|
+
|
158
|
+
# it 'should not parse attributes not mentioned in the template' do
|
159
|
+
# template, raw = ChemicalsSpecHelper.test_example :ignore_attribute
|
160
|
+
# template.parse(raw).must_equal({})
|
161
|
+
# end
|
162
|
+
|
163
|
+
it 'should mix attributes and aliased text nodes' do
|
164
|
+
template, raw = ChemicalsSpecHelper.test_example :text_attributes
|
165
|
+
template.parse(raw).must_equal \
|
166
|
+
age: '24',
|
167
|
+
name: 'John Doe'
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'should preserve empty attributes' do
|
171
|
+
template, raw = ChemicalsSpecHelper.test_example :preserve_empty_attributes
|
172
|
+
template.parse(raw).must_equal \
|
173
|
+
first_name: '',
|
174
|
+
last_name: 'Doe'
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'should parse mixed elements, collections, text nodes, attributes and ignore useless nodes' do
|
179
|
+
template, raw = ChemicalsSpecHelper.test_example :mixed_elements_text_attributes
|
180
|
+
template.parse(raw).must_equal \
|
181
|
+
[
|
182
|
+
{
|
183
|
+
name: { given: 'John', family: 'Doe' },
|
184
|
+
emails: [
|
185
|
+
{ label: 'home', address: 'john.doe@gmail.com' },
|
186
|
+
{ address: 'john@acme.com' }
|
187
|
+
],
|
188
|
+
phones: [
|
189
|
+
{ country: 'Belgium', number: '1', system: 'sap' },
|
190
|
+
{ country: 'USA', number: '2' }
|
191
|
+
]
|
192
|
+
},
|
193
|
+
{
|
194
|
+
name: { given: 'Jane' },
|
195
|
+
emails: [{ label: 'work', address: 'jane.doe@gmail.com' }]
|
196
|
+
}
|
197
|
+
]
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'should be able to parse chinese characters' do
|
201
|
+
template, raw = ChemicalsSpecHelper.test_example :chinese
|
202
|
+
template.parse(raw).must_equal '你好世界'
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'should be able to parse namespaces' do
|
206
|
+
template, raw = ChemicalsSpecHelper.test_example :namespaces
|
207
|
+
template.parse(raw).must_equal \
|
208
|
+
name: { age: '24', first_name: 'John', last_name: 'Doe' }
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should be able to deal with a root default namespace' do
|
212
|
+
template, raw = ChemicalsSpecHelper.test_example :default_namespaces
|
213
|
+
template.parse(raw).must_equal \
|
214
|
+
name: { age: '24', first_name: 'John', last_name: 'Doe', company: 'PieSync', title: 'CEO' }
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'should be able to deal with multiple default namespaces' do
|
218
|
+
template, raw = ChemicalsSpecHelper.test_example :multiple_default_namespaces
|
219
|
+
template.parse(raw).must_equal \
|
220
|
+
name: { age: '24', first_name: 'John', last_name: 'Doe', company: 'PieSync', title: 'CEO' }
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'should detect if namespace prefixes are named differently in the template' do
|
224
|
+
template, raw = ChemicalsSpecHelper.test_example :different_prefix_names
|
225
|
+
template.parse(raw).must_equal \
|
226
|
+
name: { age: '24', first_name: 'John', last_name: 'Doe' }
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'should be able to parse sudden namespaces' do
|
230
|
+
template, raw = ChemicalsSpecHelper.test_example :sudden_namespaces
|
231
|
+
template.parse(raw).must_equal \
|
232
|
+
name: { age: '24', first_name: 'John', last_name: 'Doe', gender: 'male' }
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'should parse parts without extracted data as an empty hash' do
|
236
|
+
template, raw = ChemicalsSpecHelper.test_example :no_data
|
237
|
+
template.parse(raw).must_equal name: {}
|
238
|
+
end
|
239
|
+
|
240
|
+
# it 'should be able to parse with partial templates' do
|
241
|
+
# template, raw = ChemicalsSpecHelper.test_example :partial_template
|
242
|
+
# template.parse(raw).must_equal \
|
243
|
+
# balance: { currency: 'dollar', amount: '1.000.000.000' }
|
244
|
+
# end
|
245
|
+
|
246
|
+
it 'should be reasonably fast' do
|
247
|
+
template, raw = ChemicalsSpecHelper.test_example :mixed_elements_text
|
248
|
+
1000.times do
|
249
|
+
template.parse(raw)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/spec'
|
5
|
+
|
6
|
+
require_relative 'chemicals_spec_helper'
|
7
|
+
|
8
|
+
require 'chemicals'
|
9
|
+
|
10
|
+
describe Chemicals::Renderer do
|
11
|
+
|
12
|
+
describe 'rendering a text node' do
|
13
|
+
it 'should render the element value directly in the text node when the text node is aliased as @' do
|
14
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_text
|
15
|
+
template.render('John Doe').to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should render the content unwrapped from its alias' do
|
19
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_text_alias
|
20
|
+
template.render(name: 'John Doe').to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'rendering an attribute' do
|
25
|
+
it 'should render attributes with aliases' do
|
26
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_attributes
|
27
|
+
template.render(full_name: 'John Doe').to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'rendering an element' do
|
32
|
+
it 'should unwrap contents in aliased elements' do
|
33
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_element_alias
|
34
|
+
template.render(individual: 'John Doe').to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should skip an element when no alias is provided' do
|
38
|
+
template, raw = ChemicalsSpecHelper.test_example :skip_element
|
39
|
+
template.render(individual: 'John Doe').to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'rendering a collection of elements' do
|
44
|
+
it 'should render each element' do
|
45
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_collection
|
46
|
+
template.render(emails: [
|
47
|
+
'john.doe@gmail.com',
|
48
|
+
'john@acme.com'
|
49
|
+
]).to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should render multiple collections independently' do
|
53
|
+
template, raw = ChemicalsSpecHelper.test_example :multiple_collections
|
54
|
+
template.render(
|
55
|
+
contact: {
|
56
|
+
emails: [
|
57
|
+
'john.doe@gmail.com',
|
58
|
+
'john@acme.com'
|
59
|
+
],
|
60
|
+
phone_numbers: ['1', '2']
|
61
|
+
}).to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should be able to render collections in the presence of other elements' do
|
65
|
+
template, raw = ChemicalsSpecHelper.test_example :mixed_collection
|
66
|
+
template.render( \
|
67
|
+
contact: {
|
68
|
+
emails: [
|
69
|
+
'john.doe@gmail.com',
|
70
|
+
'john@acme.com'
|
71
|
+
],
|
72
|
+
name: 'John Doe'
|
73
|
+
}).to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should be able to render multiple collections in the presence of other elements' do
|
77
|
+
template, raw = ChemicalsSpecHelper.test_example :mixed_collections
|
78
|
+
template.render(
|
79
|
+
contact: {
|
80
|
+
emails: [
|
81
|
+
{ address: 'john.doe@gmail.com', label: 'work' },
|
82
|
+
{ address: 'john@acme.com' }
|
83
|
+
],
|
84
|
+
phones: ['1'],
|
85
|
+
name: 'John Doe'
|
86
|
+
}).to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should be able to extreme parse multiple collections in the presence of other elements' do
|
90
|
+
template, raw = ChemicalsSpecHelper.test_example :mixed_collections_extreme
|
91
|
+
template.render(
|
92
|
+
[{
|
93
|
+
emails: [
|
94
|
+
{ address: 'john.doe@gmail.com', label: 'work' },
|
95
|
+
{ address:'john@acme.com' }
|
96
|
+
],
|
97
|
+
phones: ['1'],
|
98
|
+
name: 'John Doe'
|
99
|
+
},
|
100
|
+
{
|
101
|
+
phones: ['1', '2', '3'],
|
102
|
+
addresses: [{ country: 'Belgium', country_code: 'BE',
|
103
|
+
street: 'Désiré Van Monckhovenstraat', housenumber: '123' }]
|
104
|
+
}]).to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should render mixed elements, collections and text nodes' do
|
109
|
+
template, raw, raw_render = ChemicalsSpecHelper.test_example :mixed_elements_text
|
110
|
+
template.render(
|
111
|
+
[{
|
112
|
+
name: { given: 'John', family: 'Doe' },
|
113
|
+
emails: ['john.doe@gmail.com', 'john@acme.com'],
|
114
|
+
phones: [
|
115
|
+
{ country: 'Belgium', number: '1' },
|
116
|
+
{ country: 'USA', number: '2' }
|
117
|
+
]
|
118
|
+
},
|
119
|
+
{
|
120
|
+
name: { given: 'Jane' },
|
121
|
+
emails: [ 'jane.doe@gmail.com' ]
|
122
|
+
}
|
123
|
+
]).to_xml.must_equal ChemicalsSpecHelper.format(raw_render)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should render mixed elements, collections, text nodes, attributes and ignore useless nodes' do
|
127
|
+
template, raw, raw_render = ChemicalsSpecHelper.test_example :mixed_elements_text_attributes
|
128
|
+
template.render([
|
129
|
+
{
|
130
|
+
name: { given: 'John', family: 'Doe' },
|
131
|
+
emails: [
|
132
|
+
{ label: 'home', address: 'john.doe@gmail.com' },
|
133
|
+
{ address: 'john@acme.com' }
|
134
|
+
],
|
135
|
+
phones: [
|
136
|
+
{ country: 'Belgium', number: '1', system: 'sap' },
|
137
|
+
{ country: 'USA', number: '2' }
|
138
|
+
]
|
139
|
+
},
|
140
|
+
{
|
141
|
+
name: { given: 'Jane' },
|
142
|
+
emails: [{ label: 'work', address: 'jane.doe@gmail.com' }]
|
143
|
+
}
|
144
|
+
]).to_xml.must_equal ChemicalsSpecHelper.format(raw_render)
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'rendering attributes' do
|
148
|
+
it 'should render attributes with aliases' do
|
149
|
+
template, raw = ChemicalsSpecHelper.test_example :simple_attributes
|
150
|
+
template.render(full_name: 'John Doe').to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should not render attributes not mentioned in the template' do
|
155
|
+
template, raw = ChemicalsSpecHelper.test_example :ignore_attribute
|
156
|
+
template.render({}).must_equal nil
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should mix attributes and aliased text nodes' do
|
160
|
+
template, raw = ChemicalsSpecHelper.test_example :text_attributes
|
161
|
+
template.render(age: '24', name: 'John Doe').to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
162
|
+
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'should be able to render chinese characters' do
|
167
|
+
template, raw = ChemicalsSpecHelper.test_example :chinese
|
168
|
+
template.render('你好世界').to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should be able to render namespaces' do
|
172
|
+
template, raw = ChemicalsSpecHelper.test_example :namespaces
|
173
|
+
template.render(
|
174
|
+
name: { age: '24', first_name: 'John', last_name: 'Doe' }).to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
175
|
+
end
|
176
|
+
|
177
|
+
# it 'should render parts without extracted data as an empty node' do
|
178
|
+
# template, raw = ChemicalsSpecHelper.test_example :no_data
|
179
|
+
# template.render(bla: 'sdf').to_xml.must_equal ChemicalsSpecHelper.format(raw)
|
180
|
+
# end
|
181
|
+
|
182
|
+
it 'should be reasonably fast' do
|
183
|
+
template, raw = ChemicalsSpecHelper.test_example :mixed_elements_text
|
184
|
+
1000.times do
|
185
|
+
template.render(
|
186
|
+
[{
|
187
|
+
name: { given: 'John', family: 'Doe' },
|
188
|
+
emails: ['john.doe@gmail.com', 'john@acme.com'],
|
189
|
+
phones: [
|
190
|
+
{ country: 'Belgium', number: '1' },
|
191
|
+
{ country: 'USA', number: '2' }
|
192
|
+
]
|
193
|
+
},
|
194
|
+
{
|
195
|
+
name: { given: 'Jane' },
|
196
|
+
emails: [ 'jane.doe@gmail.com' ]
|
197
|
+
}
|
198
|
+
])
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|