chef-gyoku 1.4.1
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 +7 -0
- data/.github/workflows/ci.yml +62 -0
- data/.gitignore +11 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +154 -0
- data/Gemfile +6 -0
- data/MIT-LICENSE +20 -0
- data/README.md +313 -0
- data/Rakefile +12 -0
- data/gyoku.gemspec +27 -0
- data/lib/gyoku/array.rb +96 -0
- data/lib/gyoku/hash.rb +105 -0
- data/lib/gyoku/prettifier.rb +29 -0
- data/lib/gyoku/version.rb +3 -0
- data/lib/gyoku/xml_key.rb +67 -0
- data/lib/gyoku/xml_value.rb +41 -0
- data/lib/gyoku.rb +14 -0
- data/spec/gyoku/array_spec.rb +121 -0
- data/spec/gyoku/hash_spec.rb +431 -0
- data/spec/gyoku/prettifier_spec.rb +39 -0
- data/spec/gyoku/xml_key_spec.rb +76 -0
- data/spec/gyoku/xml_value_spec.rb +61 -0
- data/spec/gyoku_spec.rb +82 -0
- data/spec/spec_helper.rb +15 -0
- metadata +132 -0
@@ -0,0 +1,431 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Gyoku::Hash do
|
4
|
+
describe ".to_xml" do
|
5
|
+
describe "returns SOAP request compatible XML" do
|
6
|
+
it "for a simple Hash" do
|
7
|
+
expect(to_xml(some: "user")).to eq("<some>user</some>")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "for a nested Hash" do
|
11
|
+
expect(to_xml(some: {new: "user"})).to eq("<some><new>user</new></some>")
|
12
|
+
end
|
13
|
+
|
14
|
+
context "with key_converter" do
|
15
|
+
it "expect all keys change" do
|
16
|
+
expect(to_xml({some: {new: "user"}}, {key_converter: :camelcase})).to eq("<Some><New>user</New></Some>")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "and key_to_convert option should change only key" do
|
20
|
+
hash = {some: {new: "user", age: 20}}
|
21
|
+
options = {key_converter: :camelcase, key_to_convert: "some"}
|
22
|
+
result = "<Some><new>user</new><age>20</age></Some>"
|
23
|
+
expect(to_xml(hash, options)).to eq(result)
|
24
|
+
|
25
|
+
hash = {some: {new: "user", age: 20}}
|
26
|
+
options = {key_converter: :camelcase, key_to_convert: "new"}
|
27
|
+
result = "<some><New>user</New><age>20</age></some>"
|
28
|
+
expect(to_xml(hash, options)).to eq(result)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "with except option, dont convert this key" do
|
32
|
+
hash = {some: {new: "user", age: 20}}
|
33
|
+
options = {key_converter: :camelcase, except: "some"}
|
34
|
+
result = "<some><New>user</New><Age>20</Age></some>"
|
35
|
+
expect(to_xml(hash, options)).to eq(result)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "for a Hash with multiple keys" do
|
40
|
+
expect(to_xml(all: "users", before: "whatever")).to include(
|
41
|
+
"<all>users</all>",
|
42
|
+
"<before>whatever</before>"
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "for a Hash containing an Array" do
|
47
|
+
expect(to_xml(some: ["user", "gorilla"])).to eq("<some>user</some><some>gorilla</some>")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "for a Hash containing an Array of Hashes" do
|
51
|
+
expect(to_xml(some: [{new: "user"}, {old: "gorilla"}]))
|
52
|
+
.to eq("<some><new>user</new></some><some><old>gorilla</old></some>")
|
53
|
+
end
|
54
|
+
|
55
|
+
context "when :pretty_print option is set to true" do
|
56
|
+
it "returns prettified xml" do
|
57
|
+
hash = {some: {user: {name: "John", groups: ["admin", "editor"]}}}
|
58
|
+
options = {pretty_print: true}
|
59
|
+
result = "<some>\n <user>\n <name>John</name>\n <groups>admin</groups>\n <groups>editor</groups>\n </user>\n</some>"
|
60
|
+
expect(to_xml(hash, options)).to eq(result)
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when :indent option is specified" do
|
64
|
+
it "returns prettified xml with specified indent" do
|
65
|
+
hash = {some: {user: {name: "John"}}}
|
66
|
+
options = {pretty_print: true, indent: 4}
|
67
|
+
result = "<some>\n <user>\n <name>John</name>\n </user>\n</some>"
|
68
|
+
expect(to_xml(hash, options)).to eq(result)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when :compact option is specified" do
|
73
|
+
it "returns prettified xml with specified compact mode" do
|
74
|
+
hash = {some: {user: {name: "John"}}}
|
75
|
+
options = {pretty_print: true, compact: false}
|
76
|
+
result = "<some>\n <user>\n <name>\n John\n </name>\n </user>\n</some>"
|
77
|
+
expect(to_xml(hash, options)).to eq(result)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it "converts Hash key Symbols to lowerCamelCase" do
|
84
|
+
expect(to_xml(find_or_create: "user")).to eq("<findOrCreate>user</findOrCreate>")
|
85
|
+
end
|
86
|
+
|
87
|
+
it "does not convert Hash key Strings" do
|
88
|
+
expect(to_xml("find_or_create" => "user")).to eq("<find_or_create>user</find_or_create>")
|
89
|
+
end
|
90
|
+
|
91
|
+
it "converts DateTime objects to xs:dateTime compliant Strings" do
|
92
|
+
expect(to_xml(before: DateTime.new(2012, 0o3, 22, 16, 22, 33)))
|
93
|
+
.to eq("<before>2012-03-22T16:22:33+00:00</before>")
|
94
|
+
end
|
95
|
+
|
96
|
+
it "converts Objects responding to to_datetime to xs:dateTime compliant Strings" do
|
97
|
+
singleton = Object.new
|
98
|
+
def singleton.to_datetime
|
99
|
+
DateTime.new(2012, 0o3, 22, 16, 22, 33)
|
100
|
+
end
|
101
|
+
|
102
|
+
expect(to_xml(before: singleton)).to eq("<before>2012-03-22T16:22:33+00:00</before>")
|
103
|
+
end
|
104
|
+
|
105
|
+
it "calls to_s on Strings even if they respond to to_datetime" do
|
106
|
+
singleton = "gorilla"
|
107
|
+
def singleton.to_datetime
|
108
|
+
DateTime.new(2012, 0o3, 22, 16, 22, 33)
|
109
|
+
end
|
110
|
+
|
111
|
+
expect(to_xml(name: singleton)).to eq("<name>gorilla</name>")
|
112
|
+
end
|
113
|
+
|
114
|
+
it "properly serializes nil values" do
|
115
|
+
expect(to_xml(some: nil)).to eq('<some xsi:nil="true"/>')
|
116
|
+
end
|
117
|
+
|
118
|
+
it "creates self-closing tags for Hash keys ending with a forward slash" do
|
119
|
+
expect(to_xml("self-closing/" => nil)).to eq("<self-closing/>")
|
120
|
+
end
|
121
|
+
|
122
|
+
it "calls to_s on any other Object" do
|
123
|
+
[666, true, false].each do |object|
|
124
|
+
expect(to_xml(some: object)).to eq("<some>#{object}</some>")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
it "defaults to escape special characters" do
|
129
|
+
result = to_xml(some: {nested: "<tag />"}, tag: "<tag />")
|
130
|
+
expect(result).to include("<tag><tag /></tag>")
|
131
|
+
expect(result).to include("<some><nested><tag /></nested></some>")
|
132
|
+
end
|
133
|
+
|
134
|
+
it "does not escape special characters for keys marked with an exclamation mark" do
|
135
|
+
result = to_xml(some: {nested!: "<tag />"}, tag!: "<tag />")
|
136
|
+
expect(result).to include("<tag><tag /></tag>")
|
137
|
+
expect(result).to include("<some><nested><tag /></nested></some>")
|
138
|
+
end
|
139
|
+
|
140
|
+
it "preserves the order of Hash keys and values specified through :order!" do
|
141
|
+
hash = {find_user: {name: "Lucy", id: 666, order!: [:id, :name]}}
|
142
|
+
result = "<findUser><id>666</id><name>Lucy</name></findUser>"
|
143
|
+
expect(to_xml(hash)).to eq(result)
|
144
|
+
|
145
|
+
hash = {find_user: {mname: "in the", lname: "Sky", fname: "Lucy", order!: [:fname, :mname, :lname]}}
|
146
|
+
result = "<findUser><fname>Lucy</fname><mname>in the</mname><lname>Sky</lname></findUser>"
|
147
|
+
expect(to_xml(hash)).to eq(result)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "preserves the order of Hash keys and values specified through 'order!' (as a string key)" do
|
151
|
+
hash = {find_user: {:name => "Lucy", :id => 666, "order!" => [:id, :name]}}
|
152
|
+
result = "<findUser><id>666</id><name>Lucy</name></findUser>"
|
153
|
+
expect(to_xml(hash)).to eq(result)
|
154
|
+
|
155
|
+
hash = {find_user: {:mname => "in the", :lname => "Sky", :fname => "Lucy", "order!" => [:fname, :mname, :lname]}}
|
156
|
+
result = "<findUser><fname>Lucy</fname><mname>in the</mname><lname>Sky</lname></findUser>"
|
157
|
+
expect(to_xml(hash)).to eq(result)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "uses :order! symbol values for ordering but leaves the string key 'order!' if both are present" do
|
161
|
+
hash = {find_user: {:name => "Lucy", :id => 666, "order!" => "value", :order! => [:id, :name, "order!"]}}
|
162
|
+
result = "<findUser><id>666</id><name>Lucy</name><order>value</order></findUser>"
|
163
|
+
expect(to_xml(hash)).to eq(result)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "raises if the :order! Array is missing Hash keys" do
|
167
|
+
hash = {name: "Lucy", id: 666, order!: [:name]}
|
168
|
+
expect { to_xml(hash) }.to raise_error(ArgumentError, "Missing elements in :order! [:id]")
|
169
|
+
end
|
170
|
+
|
171
|
+
it "raises if the :order! Array contains missing Hash keys" do
|
172
|
+
hash = {by_name: {first_name: "Lucy", last_name: "Sky", order!: [:first_name, :middle_name, :last_name]}}
|
173
|
+
expect { to_xml(hash) }.to raise_error(ArgumentError, "Spurious elements in :order! [:middle_name]")
|
174
|
+
end
|
175
|
+
|
176
|
+
it "adds attributes to Hash keys specified through :attributes!" do
|
177
|
+
hash = {find_user: {person: "Lucy", attributes!: {person: {id: 666}}}}
|
178
|
+
result = '<findUser><person id="666">Lucy</person></findUser>'
|
179
|
+
expect(to_xml(hash)).to eq(result)
|
180
|
+
|
181
|
+
hash = {find_user: {person: "Lucy", attributes!: {person: {id: 666, city: "Hamburg"}}}}
|
182
|
+
expect(to_xml(hash)).to include('id="666"', 'city="Hamburg"')
|
183
|
+
end
|
184
|
+
|
185
|
+
it "adds attributes to duplicate Hash keys specified through :attributes!" do
|
186
|
+
hash = {find_user: {person: ["Lucy", "Anna"], attributes!: {person: {id: [1, 3]}}}}
|
187
|
+
result = '<findUser><person id="1">Lucy</person><person id="3">Anna</person></findUser>'
|
188
|
+
expect(to_xml(hash)).to eq(result)
|
189
|
+
|
190
|
+
hash = {find_user: {person: ["Lucy", "Anna"], attributes!: {person: {active: "true"}}}}
|
191
|
+
result = '<findUser><person active="true">Lucy</person><person active="true">Anna</person></findUser>'
|
192
|
+
expect(to_xml(hash)).to eq(result)
|
193
|
+
end
|
194
|
+
|
195
|
+
it "skips attribute for element without attributes if there are fewer attributes than elements" do
|
196
|
+
hash = {find_user: {person: ["Lucy", "Anna", "Beth"], attributes!: {person: {id: [1, 3]}}}}
|
197
|
+
result = '<findUser><person id="1">Lucy</person><person id="3">Anna</person><person>Beth</person></findUser>'
|
198
|
+
expect(to_xml(hash)).to eq(result)
|
199
|
+
end
|
200
|
+
|
201
|
+
it "adds attributes to self-closing tags" do
|
202
|
+
hash = {
|
203
|
+
"category/" => "",
|
204
|
+
:attributes! => {"category/" => {id: 1}}
|
205
|
+
}
|
206
|
+
|
207
|
+
expect(to_xml(hash)).to eq('<category id="1"/>')
|
208
|
+
end
|
209
|
+
|
210
|
+
it "recognizes @attribute => value along :attributes!" do
|
211
|
+
hash = {
|
212
|
+
"category" => {
|
213
|
+
:content! => "users",
|
214
|
+
:@id => 1
|
215
|
+
}
|
216
|
+
}
|
217
|
+
expect(to_xml(hash)).to eq('<category id="1">users</category>')
|
218
|
+
end
|
219
|
+
|
220
|
+
it "recognizes @attribute => value along :attributes! in selfclosed tags" do
|
221
|
+
hash = {
|
222
|
+
"category/" => {
|
223
|
+
:@id => 1
|
224
|
+
}
|
225
|
+
}
|
226
|
+
expect(to_xml(hash)).to eq('<category id="1"/>')
|
227
|
+
end
|
228
|
+
|
229
|
+
it ":@attribute => value takes over :attributes!" do
|
230
|
+
hash = {
|
231
|
+
"category/" => {
|
232
|
+
:@id => 1
|
233
|
+
},
|
234
|
+
:attributes! => {
|
235
|
+
"category/" => {
|
236
|
+
"id" => 2, # will be ignored
|
237
|
+
"type" => "admins"
|
238
|
+
}
|
239
|
+
}
|
240
|
+
}
|
241
|
+
# attribute order is undefined
|
242
|
+
expect(['<category id="1" type="admins"/>', '<category type="admins" id="1"/>']).to include to_xml(hash)
|
243
|
+
|
244
|
+
# with symbols
|
245
|
+
hash = {
|
246
|
+
"category/" => {
|
247
|
+
:@id => 1
|
248
|
+
},
|
249
|
+
:attributes! => {
|
250
|
+
"category/" => {
|
251
|
+
id: 2, # will be ignored
|
252
|
+
type: "admins"
|
253
|
+
}
|
254
|
+
}
|
255
|
+
}
|
256
|
+
expect(['<category id="1" type="admins"/>', '<category type="admins" id="1"/>']).to include to_xml(hash)
|
257
|
+
end
|
258
|
+
|
259
|
+
it "recognizes :content! => value as tag content" do
|
260
|
+
hash = {
|
261
|
+
"category" => {
|
262
|
+
content!: "users"
|
263
|
+
}
|
264
|
+
}
|
265
|
+
expect(to_xml(hash)).to eq("<category>users</category>")
|
266
|
+
end
|
267
|
+
|
268
|
+
it "recognizes :content! => value as tag content with value Fixnum" do
|
269
|
+
hash = {
|
270
|
+
"category" => {
|
271
|
+
content!: 666
|
272
|
+
}
|
273
|
+
}
|
274
|
+
expect(to_xml(hash)).to eq("<category>666</category>")
|
275
|
+
end
|
276
|
+
|
277
|
+
it "recognizes :content! => value as tag content with value true" do
|
278
|
+
hash = {
|
279
|
+
"category" => {
|
280
|
+
content!: true
|
281
|
+
}
|
282
|
+
}
|
283
|
+
expect(to_xml(hash)).to eq("<category>true</category>")
|
284
|
+
end
|
285
|
+
|
286
|
+
it "recognizes :content! => value as tag content with value false" do
|
287
|
+
hash = {
|
288
|
+
"category" => {
|
289
|
+
content!: false
|
290
|
+
}
|
291
|
+
}
|
292
|
+
expect(to_xml(hash)).to eq("<category>false</category>")
|
293
|
+
end
|
294
|
+
|
295
|
+
it "recognizes :content! => value as tag content with value DateTime" do
|
296
|
+
hash = {
|
297
|
+
"before" => {
|
298
|
+
content!: DateTime.new(2012, 0o3, 22, 16, 22, 33)
|
299
|
+
}
|
300
|
+
}
|
301
|
+
expect(to_xml(hash)).to eq("<before>2012-03-22T16:22:33+00:00</before>")
|
302
|
+
end
|
303
|
+
|
304
|
+
it "ignores :content! if self-closing mark present" do
|
305
|
+
hash = {
|
306
|
+
"category/" => {
|
307
|
+
content!: "users"
|
308
|
+
}
|
309
|
+
}
|
310
|
+
expect(to_xml(hash)).to eq("<category/>")
|
311
|
+
end
|
312
|
+
|
313
|
+
it "recognizes array of attributes" do
|
314
|
+
hash = {
|
315
|
+
"category" => [{:@name => "one"}, {:@name => "two"}]
|
316
|
+
}
|
317
|
+
expect(to_xml(hash)).to eq('<category name="one"></category><category name="two"></category>')
|
318
|
+
|
319
|
+
# issue #31.
|
320
|
+
hash = {
|
321
|
+
:order! => ["foo", "bar"],
|
322
|
+
"foo" => {:@foo => "foo"},
|
323
|
+
"bar" => {:@bar => "bar", "baz" => {}}
|
324
|
+
}
|
325
|
+
expect(to_xml(hash)).to eq('<foo foo="foo"></foo><bar bar="bar"><baz></baz></bar>')
|
326
|
+
end
|
327
|
+
|
328
|
+
it "recognizes array of attributes with content in each" do
|
329
|
+
hash = {
|
330
|
+
"foo" => [{:@name => "bar", :content! => "gyoku"}, {:@name => "baz", :@some => "attr", :content! => "rocks!"}]
|
331
|
+
}
|
332
|
+
|
333
|
+
expect([
|
334
|
+
'<foo name="bar">gyoku</foo><foo name="baz" some="attr">rocks!</foo>',
|
335
|
+
'<foo name="bar">gyoku</foo><foo some="attr" name="baz">rocks!</foo>'
|
336
|
+
]).to include to_xml(hash)
|
337
|
+
end
|
338
|
+
|
339
|
+
it "recognizes array of attributes but ignores content in each if selfclosing" do
|
340
|
+
hash = {
|
341
|
+
"foo/" => [{:@name => "bar", :content! => "gyoku"}, {:@name => "baz", :@some => "attr", :content! => "rocks!"}]
|
342
|
+
}
|
343
|
+
|
344
|
+
expect([
|
345
|
+
'<foo name="bar"/><foo name="baz" some="attr"/>',
|
346
|
+
'<foo name="bar"/><foo some="attr" name="baz"/>'
|
347
|
+
]).to include to_xml(hash)
|
348
|
+
end
|
349
|
+
|
350
|
+
it "recognizes array of attributes with selfclosing tag" do
|
351
|
+
hash = {
|
352
|
+
"category/" => [{:@name => "one"}, {:@name => "two"}]
|
353
|
+
}
|
354
|
+
expect(to_xml(hash)).to eq('<category name="one"/><category name="two"/>')
|
355
|
+
end
|
356
|
+
|
357
|
+
context "with :element_form_default set to :qualified and a :namespace" do
|
358
|
+
it "adds the given :namespace to every element" do
|
359
|
+
hash = {:first => {"first_name" => "Lucy"}, ":second" => {":first_name": "Anna"}, "v2:third" => {"v2:firstName" => "Danie"}}
|
360
|
+
result = to_xml hash, element_form_default: :qualified, namespace: :v1
|
361
|
+
|
362
|
+
expect(result).to include(
|
363
|
+
"<v1:first><v1:first_name>Lucy</v1:first_name></v1:first>",
|
364
|
+
"<second><firstName>Anna</firstName></second>",
|
365
|
+
"<v2:third><v2:firstName>Danie</v2:firstName></v2:third>"
|
366
|
+
)
|
367
|
+
end
|
368
|
+
|
369
|
+
it "adds given :namespace to every element in an array" do
|
370
|
+
hash = {array: [first: "Lucy", second: "Anna"]}
|
371
|
+
result = to_xml hash, element_form_default: :qualified, namespace: :v1
|
372
|
+
|
373
|
+
expect(result).to include("<v1:array>", "<v1:first>Lucy</v1:first>", "<v1:second>Anna</v1:second>")
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
it "does not remove special keys from the original Hash" do
|
378
|
+
hash = {
|
379
|
+
persons: {
|
380
|
+
first: "Lucy",
|
381
|
+
second: "Anna",
|
382
|
+
order!: [:second, :first],
|
383
|
+
attributes!: {first: {first: true}}
|
384
|
+
},
|
385
|
+
countries: [:de, :us],
|
386
|
+
order!: [:countries, :persons],
|
387
|
+
attributes!: {countries: {array: true}}
|
388
|
+
}
|
389
|
+
|
390
|
+
to_xml(hash)
|
391
|
+
|
392
|
+
expect(hash).to eq({
|
393
|
+
persons: {
|
394
|
+
first: "Lucy",
|
395
|
+
second: "Anna",
|
396
|
+
order!: [:second, :first],
|
397
|
+
attributes!: {first: {first: true}}
|
398
|
+
},
|
399
|
+
countries: [:de, :us],
|
400
|
+
order!: [:countries, :persons],
|
401
|
+
attributes!: {countries: {array: true}}
|
402
|
+
})
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
it "doesn't modify original hash parameter by deleting its attribute keys" do
|
407
|
+
hash = {person: {name: "Johnny", surname: "Bravo", "@xsi:type": "People"}}
|
408
|
+
to_xml(hash)
|
409
|
+
expect(hash).to eq({person: {name: "Johnny", surname: "Bravo", "@xsi:type": "People"}})
|
410
|
+
end
|
411
|
+
|
412
|
+
describe ".explicit_attribute?" do
|
413
|
+
subject { described_class.explicit_attribute?(key) }
|
414
|
+
|
415
|
+
context "when key starts with an @" do
|
416
|
+
let(:key) { "@" }
|
417
|
+
|
418
|
+
it { is_expected.to eq(true) }
|
419
|
+
end
|
420
|
+
|
421
|
+
context "when key does not start with an @" do
|
422
|
+
let(:key) { "NOT@" }
|
423
|
+
|
424
|
+
it { is_expected.to eq(false) }
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
def to_xml(hash, options = {})
|
429
|
+
Gyoku::Hash.to_xml hash, options
|
430
|
+
end
|
431
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Gyoku::Prettifier do
|
4
|
+
describe "#prettify" do
|
5
|
+
context "when xml is valid" do
|
6
|
+
let!(:xml) { Gyoku::Hash.build_xml(test: {pretty: "xml"}) }
|
7
|
+
|
8
|
+
it "returns prettified xml" do
|
9
|
+
expect(subject.prettify(xml)).to eql("<test>\n <pretty>xml</pretty>\n</test>")
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when indent option is specified" do
|
13
|
+
it "returns prettified xml with indent" do
|
14
|
+
options = {indent: 3}
|
15
|
+
subject = Gyoku::Prettifier.new(options)
|
16
|
+
expect(subject.prettify(xml)).to eql("<test>\n <pretty>xml</pretty>\n</test>")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when compact option is specified" do
|
21
|
+
it "returns prettified xml with indent" do
|
22
|
+
options = {compact: false}
|
23
|
+
subject = Gyoku::Prettifier.new(options)
|
24
|
+
expect(subject.prettify(xml)).to eql("<test>\n <pretty>\n xml\n </pretty>\n</test>")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when xml is not valid" do
|
30
|
+
let!(:xml) do
|
31
|
+
Gyoku::Array.build_xml(["one", "two"], "test")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "raises an error" do
|
35
|
+
expect { subject.prettify(xml) }.to raise_error REXML::ParseException
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Gyoku::XMLKey do
|
4
|
+
describe ".create" do
|
5
|
+
it "removes exclamation marks from the end of a String" do
|
6
|
+
expect(create("value!")).to eq("value")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "removes forward slashes from the end of a String" do
|
10
|
+
expect(create("self-closing/")).to eq("self-closing")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "does not convert snake_case Strings" do
|
14
|
+
expect(create("lower_camel_case")).to eq("lower_camel_case")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "converts snake_case Symbols to lowerCamelCase Strings" do
|
18
|
+
expect(create(:lower_camel_case)).to eq("lowerCamelCase")
|
19
|
+
expect(create(:lower_camel_case!)).to eq("lowerCamelCase")
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when the converter option is set to camelcase" do
|
23
|
+
it "should replace / with ::, and turn snake case into camel case" do
|
24
|
+
input = :"hello_world_bob/how_are_you|there:foo^bar"
|
25
|
+
expected_output = "HelloWorldBob::HowAreYou|there:foo^bar"
|
26
|
+
expect(create(input, {key_converter: :camelcase})).to eq(expected_output)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "with key_converter" do
|
31
|
+
it "accepts lambda converters" do
|
32
|
+
expect(create(:some_text, {key_converter: lambda { |k| k.reverse }})).to eq("txet_emos")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "convert symbol to the specified type" do
|
36
|
+
expect(create(:some_text, {key_converter: :camelcase})).to eq("SomeText")
|
37
|
+
expect(create(:some_text, {key_converter: :upcase})).to eq("SOME_TEXT")
|
38
|
+
expect(create(:some_text, {key_converter: :none})).to eq("some_text")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "when key_to_convert is defined, convert only this key" do
|
42
|
+
options = {key_converter: :camelcase, key_to_convert: "somekey"}
|
43
|
+
expect(create(:some_key, options)).to eq("someKey")
|
44
|
+
|
45
|
+
options = {key_converter: :camelcase, key_to_convert: "some_key"}
|
46
|
+
expect(create(:some_key, options)).to eq("SomeKey")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "when except is defined, dont convert this key" do
|
50
|
+
options = {key_converter: :camelcase, except: "some_key"}
|
51
|
+
expect(create(:some_key, options)).to eq("someKey")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "with :element_form_default set to :qualified and a :namespace" do
|
56
|
+
it "adds the given namespace" do
|
57
|
+
key = create :qualify, element_form_default: :qualified, namespace: :v1
|
58
|
+
expect(key).to eq("v1:qualify")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "does not add the given namespace if the key starts with a colon" do
|
62
|
+
key = create ":qualify", element_form_default: :qualified, namespace: :v1
|
63
|
+
expect(key).to eq("qualify")
|
64
|
+
end
|
65
|
+
|
66
|
+
it "adds a given :namespace after converting the key" do
|
67
|
+
key = create :username, element_form_default: :qualified, namespace: :v1, key_converter: :camelcase
|
68
|
+
expect(key).to eq("v1:Username")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def create(key, options = {})
|
74
|
+
Gyoku::XMLKey.create(key, options)
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Gyoku::XMLValue do
|
4
|
+
describe ".create" do
|
5
|
+
context "for DateTime objects" do
|
6
|
+
it "returns an xs:dateTime compliant String" do
|
7
|
+
expect(create(DateTime.new(2012, 3, 22, 16, 22, 33))).to eq("2012-03-22T16:22:33+00:00")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "for Date objects" do
|
12
|
+
it "returns an xs:date compliant String" do
|
13
|
+
expect(create(Date.new(2012, 3, 22))).to eq("2012-03-22")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "for Time objects" do
|
18
|
+
it "returns an xs:time compliant String" do
|
19
|
+
expect(create(Time.local(2012, 3, 22, 16, 22, 33))).to eq("16:22:33")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns the String value and escapes special characters" do
|
24
|
+
expect(create("string")).to eq("string")
|
25
|
+
expect(create("<tag>")).to eq("<tag>")
|
26
|
+
expect(create("at&t")).to eq("at&t")
|
27
|
+
expect(create('"quotes"')).to eq(""quotes"")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns the String value without escaping special characters" do
|
31
|
+
expect(create("<tag>", false)).to eq("<tag>")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns an xs:dateTime compliant String for Objects responding to #to_datetime" do
|
35
|
+
singleton = Object.new
|
36
|
+
def singleton.to_datetime
|
37
|
+
DateTime.new 2012, 3, 22, 16, 22, 33
|
38
|
+
end
|
39
|
+
|
40
|
+
expect(create(singleton)).to eq("2012-03-22T16:22:33+00:00")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "calls Proc objects and converts their return value" do
|
44
|
+
object = lambda { DateTime.new 2012, 3, 22, 16, 22, 33 }
|
45
|
+
expect(create(object)).to eq("2012-03-22T16:22:33+00:00")
|
46
|
+
end
|
47
|
+
|
48
|
+
it "hash objects get converted to xml" do
|
49
|
+
object = {document!: {"@version" => "2.0", :content! => {key!: "value", other_key: {"@attribute" => "value", :content! => {key: "value"}}}}}
|
50
|
+
expect(create(object)).to eq("<document version=\"2.0\"><key>value</key><otherKey attribute=\"value\"><key>value</key></otherKey></document>")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "calls #to_s unless the Object responds to #to_datetime" do
|
54
|
+
expect(create("value")).to eq("value")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def create(object, escape_xml = true)
|
59
|
+
Gyoku::XMLValue.create object, escape_xml
|
60
|
+
end
|
61
|
+
end
|
data/spec/gyoku_spec.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Gyoku do
|
4
|
+
describe ".xml_tag" do
|
5
|
+
it "translates Symbols to lowerCamelCase by default" do
|
6
|
+
tag = Gyoku.xml_tag(:user_name)
|
7
|
+
expect(tag).to eq("userName")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "does not translate Strings" do
|
11
|
+
tag = Gyoku.xml_tag("user_name")
|
12
|
+
expect(tag).to eq("user_name")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "translates Symbols by a given key_converter" do
|
16
|
+
tag = Gyoku.xml_tag(:user_name, key_converter: :upcase)
|
17
|
+
expect(tag).to eq("USER_NAME")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "does not translates Strings with a given key_converter" do
|
21
|
+
tag = Gyoku.xml_tag("user_name", key_converter: :upcase)
|
22
|
+
expect(tag).to eq("user_name")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe ".xml" do
|
27
|
+
it "translates a given Hash to XML" do
|
28
|
+
hash = {id: 1}
|
29
|
+
xml = Gyoku.xml(hash, element_form_default: :qualified)
|
30
|
+
|
31
|
+
expect(xml).to eq("<id>1</id>")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "accepts a key_converter for the Hash keys" do
|
35
|
+
hash = {user_name: "finn", pass_word: "secret"}
|
36
|
+
xml = Gyoku.xml(hash, {key_converter: :upcase})
|
37
|
+
|
38
|
+
expect(xml).to include("<USER_NAME>finn</USER_NAME>")
|
39
|
+
expect(xml).to include("<PASS_WORD>secret</PASS_WORD>")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "don't converts Strings keys" do
|
43
|
+
hash = {:user_name => "finn", "pass_word" => "secret"}
|
44
|
+
xml = Gyoku.xml(hash, {key_converter: :upcase})
|
45
|
+
|
46
|
+
expect(xml).to include("<USER_NAME>finn</USER_NAME>")
|
47
|
+
expect(xml).to include("<pass_word>secret</pass_word>")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "when defined key_to_convert only convert this key" do
|
51
|
+
hash = {user_name: "finn", pass_word: "secret"}
|
52
|
+
options = {key_converter: :upcase, key_to_convert: "user_name"}
|
53
|
+
xml = Gyoku.xml(hash, options)
|
54
|
+
|
55
|
+
expect(xml).to include("<USER_NAME>finn</USER_NAME>")
|
56
|
+
expect(xml).to include("<passWord>secret</passWord>")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "accepts key_converter for nested hash" do
|
60
|
+
hash = {user: {user_name: "finn", pass_word: "secret"}}
|
61
|
+
xml = Gyoku.xml(hash, {key_converter: :upcase})
|
62
|
+
|
63
|
+
expect(xml).to include("<USER><USER_NAME>finn</USER_NAME>")
|
64
|
+
expect(xml).to include("<PASS_WORD>secret</PASS_WORD></USER>")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "does not modify the original Hash" do
|
68
|
+
hash = {
|
69
|
+
person: {
|
70
|
+
first_name: "Lucy",
|
71
|
+
last_name: "Sky",
|
72
|
+
order!: [:first_name, :last_name]
|
73
|
+
},
|
74
|
+
attributes!: {person: {id: "666"}}
|
75
|
+
}
|
76
|
+
original_hash = hash.dup
|
77
|
+
|
78
|
+
Gyoku.xml(hash)
|
79
|
+
expect(original_hash).to eq(hash)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|