xml-fu 0.1.9 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +82 -16
- data/lib/xml-fu.rb +48 -54
- data/lib/xml-fu/array.rb +8 -30
- data/lib/xml-fu/configuration.rb +58 -0
- data/lib/xml-fu/hash.rb +46 -40
- data/lib/xml-fu/node.rb +14 -36
- data/lib/xml-fu/open_struct.rb +17 -0
- data/lib/xml-fu/version.rb +1 -1
- data/spec/lib/configuration_spec.rb +24 -0
- data/spec/lib/open_struct_spec.rb +37 -0
- data/spec/lib/xml-fu_spec.rb +6 -7
- data/spec/xmlfu_spec.rb +159 -76
- metadata +12 -6
data/README.md
CHANGED
@@ -25,6 +25,23 @@ Or install it yourself as:
|
|
25
25
|
|
26
26
|
$ gem install xml-fu
|
27
27
|
|
28
|
+
## BREAKING CHANGES in 0.2.0
|
29
|
+
|
30
|
+
Configuration was reworked to be more flexible and provide a centralized object for configuration. As such,
|
31
|
+
the configuration options have been moved off of the XmlFu module into the XmlFu.config object. The XmlFu.configure
|
32
|
+
method still works the same for setting configurations, but for reading configuration variables, you need to go
|
33
|
+
through the XmlFu.config object.
|
34
|
+
|
35
|
+
* ADDED
|
36
|
+
* support for OpenStruct conversion
|
37
|
+
* REMOVED
|
38
|
+
* infer_simple_value_nodes configuration option
|
39
|
+
* XmlFu::Array.infer_node
|
40
|
+
* XmlFu.parse()
|
41
|
+
* XmlFu is for generation of XML, not parsing.
|
42
|
+
* MOVED
|
43
|
+
* configuration options moved to XmlFu.config
|
44
|
+
|
28
45
|
|
29
46
|
## Hash Keys
|
30
47
|
|
@@ -34,15 +51,16 @@ Hash keys are translated into XML nodes (whether it be a document node or attrib
|
|
34
51
|
### Key Translation
|
35
52
|
|
36
53
|
With Ruby, a hash key may be a string or a symbol. **Strings will be preserved** as they may
|
37
|
-
contain node namespacing ("foo:Bar" would need preserved rather than converted).
|
38
|
-
|
39
|
-
|
40
|
-
|
54
|
+
contain node namespacing ("foo:Bar" would need preserved rather than converted). There are some
|
55
|
+
exceptions to this rule (especially with special key syntax discussed in *Types of Nodes* and the
|
56
|
+
like). Symbols will be converted into an XML safe name by lower camel-casing them. So :foo\_bar
|
57
|
+
will become "fooBar". You may change the conversion algorithm to your liking by setting the
|
58
|
+
XmlFu.config.symbol_conversion_algorithm to a lambda or proc of your liking.
|
41
59
|
|
42
60
|
|
43
61
|
#### Built-In Algorithms
|
44
62
|
|
45
|
-
For a complete list, reference XmlFu::
|
63
|
+
For a complete list, reference XmlFu::Configuration::ALGORITHMS
|
46
64
|
|
47
65
|
* :camelcase
|
48
66
|
* :downcase
|
@@ -57,27 +75,27 @@ XmlFu.xml( :foo_bar => "bang" ) #=> "<fooBar>bang</fooBar>"
|
|
57
75
|
|
58
76
|
|
59
77
|
# Built-in Algorithms (:camelcase)
|
60
|
-
XmlFu.symbol_conversion_algorithm = :camelcase
|
78
|
+
XmlFu.config.symbol_conversion_algorithm = :camelcase
|
61
79
|
XmlFu.xml( :Foo_Bar => "bang" ) #=> "<FooBar>bang</FooBar>"
|
62
80
|
XmlFu.xml( :foo_bar => "bang" ) #=> "<FooBar>bang</FooBar>"
|
63
81
|
|
64
82
|
|
65
83
|
# Built-in Algorithms (:downcase)
|
66
|
-
XmlFu.symbol_conversion_algorithm = :downcase
|
84
|
+
XmlFu.config.symbol_conversion_algorithm = :downcase
|
67
85
|
XmlFu.xml( :foo_bar => "bang" ) #=> "<foo_bar>bang</foo_bar>"
|
68
86
|
XmlFu.xml( :Foo_Bar => "bang" ) #=> "<foo_bar>bang</foo_bar>"
|
69
87
|
XmlFu.xml( :FOO => "bar" ) #=> "<foo>bar</foo>"
|
70
88
|
|
71
89
|
|
72
90
|
# Built-in Algorithms (:upcase)
|
73
|
-
XmlFu.symbol_conversion_algorithm = :upcase
|
91
|
+
XmlFu.config.symbol_conversion_algorithm = :upcase
|
74
92
|
XmlFu.xml( :foo_bar => "bang" ) #=> "<FOO_BAR>bang</FOO_BAR>"
|
75
93
|
XmlFu.xml( :Foo_Bar => "bang" ) #=> "<FOO_BAR>bang</FOO_BAR>"
|
76
94
|
XmlFu.xml( :foo => "bar" ) #=> "<FOO>bar</FOO>"
|
77
95
|
|
78
96
|
|
79
97
|
# Custom Algorithm
|
80
|
-
XmlFu.symbol_conversion_algorithm = lambda {|sym| sym.do_something_special }
|
98
|
+
XmlFu.config.symbol_conversion_algorithm = lambda {|sym| sym.do_something_special }
|
81
99
|
```
|
82
100
|
|
83
101
|
### Types of Nodes
|
@@ -119,6 +137,11 @@ XmlFu.xml("foo!" => "<bar/>") #=> "<foo><bar/></foo>"
|
|
119
137
|
Yes, the attributes of an XML node are nodes themselves, so we need a way of defining them. Since XPath syntax
|
120
138
|
uses @ to denote an attribute, so does XmlFu.
|
121
139
|
|
140
|
+
**Note**: Keep in mind, because of the way that XML::Builder accepts an attributes hash and the way that
|
141
|
+
Ruby stores and retrieves values from a Hash, that attributes won't always be generated in the same
|
142
|
+
order. We can only guarantee that the attributes will be present, not in any specific order.
|
143
|
+
|
144
|
+
|
122
145
|
``` ruby
|
123
146
|
XmlFu.xml(:agent => {
|
124
147
|
"@id" => "007",
|
@@ -190,6 +213,14 @@ XmlFu.xml("foo/" => {"@id" => "123", "=" => "You can't see me."})
|
|
190
213
|
```
|
191
214
|
|
192
215
|
|
216
|
+
### OpenStructs
|
217
|
+
|
218
|
+
Since version 0.2.0, support has been added for converting an OpenStruct object. OpenStruct objects behave
|
219
|
+
similar to Hashes, but they do not allow the flexibility that Hashes provide when naming keys/methods. As such,
|
220
|
+
the advanced naming capabilities are not available with OpenStruct objects and key conversion will go through
|
221
|
+
XmlFu.config.symbol_conversion_algorithm.
|
222
|
+
|
223
|
+
|
193
224
|
### Arrays
|
194
225
|
|
195
226
|
Since the value in a key/value pair is (for the most part) used as the contents of a key/node, there are some
|
@@ -271,20 +302,55 @@ are currently ignored in arrays and only Hashes are translated.
|
|
271
302
|
```ruby
|
272
303
|
"foo" => [
|
273
304
|
{:bar => "biz"},
|
274
|
-
nil,
|
275
|
-
true,
|
276
|
-
false,
|
277
|
-
42,
|
278
|
-
3.14,
|
279
|
-
"simple string",
|
305
|
+
nil, # ignored
|
306
|
+
true, # ignored
|
307
|
+
false, # ignored
|
308
|
+
42, # ignored
|
309
|
+
3.14, # ignored
|
310
|
+
"simple string", # ignored
|
280
311
|
['another','array','of','values'] # ignored
|
281
312
|
]
|
282
313
|
#=> "<foo><bar>biz</bar></foo>"
|
283
314
|
```
|
284
315
|
|
285
316
|
## Options
|
317
|
+
|
318
|
+
The following options are available to pass to XmlFu.xml(obj, options).
|
319
|
+
|
286
320
|
* **:instruct** => true
|
287
|
-
* Adds <
|
321
|
+
* Adds <?xml version="1.0" encoding="UTF-8"?> to generated XML
|
322
|
+
* This will be overridden by XmlFu.config.include_xml_declaration
|
323
|
+
|
324
|
+
|
325
|
+
## Configuration
|
326
|
+
```
|
327
|
+
XmlFu.configure do |config|
|
328
|
+
config.symbol_conversion_algorithm = :default # (:lower_camelcase)
|
329
|
+
config.fail_on_invalid_construct = false # (false)
|
330
|
+
config.include_xml_declaration = nil # (nil)
|
331
|
+
end
|
332
|
+
```
|
333
|
+
|
334
|
+
### symbol_conversion_algorithm
|
335
|
+
|
336
|
+
This is used to convert symbol keys in a Hash to Strings.
|
337
|
+
|
338
|
+
|
339
|
+
### fail_on_invalid_construct
|
340
|
+
|
341
|
+
When an unsupported object is passed to XmlFu.xml(), the default action is to return nil as
|
342
|
+
the result. When fail_on_invalid_construct is enabled, XmlFu.xml() will raise an ArgumentError
|
343
|
+
to denote that the passed object is not supported rather than fail silently.
|
344
|
+
|
345
|
+
### include_xml_declaration
|
346
|
+
|
347
|
+
Deals with adding/excluding <?xml version="1.0" encoding="UTF-8"?> to generated XML
|
348
|
+
|
349
|
+
* When enabled, ALWAYS adds declaration to XML
|
350
|
+
* When disabled, NEVER adds declaration to XML
|
351
|
+
* When nil, control given to XmlFu.xml :instruct option (default)
|
352
|
+
|
353
|
+
|
288
354
|
|
289
355
|
|
290
356
|
## Cheat Sheet
|
data/lib/xml-fu.rb
CHANGED
@@ -1,75 +1,69 @@
|
|
1
1
|
#require "xml-fu/version"
|
2
2
|
require "xml-fu/hash"
|
3
|
+
require "xml-fu/open_struct"
|
3
4
|
require "xml-fu/array"
|
4
5
|
require "xml-fu/markup"
|
6
|
+
require "xml-fu/configuration"
|
5
7
|
|
6
8
|
module XmlFu
|
7
|
-
class << self
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
case construct
|
12
|
-
when ::Hash then Hash.to_xml( construct.dup, options )
|
13
|
-
when ::Array then Array.to_xml( construct.dup, options )
|
14
|
-
else nil
|
15
|
-
end
|
16
|
-
end#convert
|
17
|
-
|
18
|
-
# @todo Add Nori-like parsing capability to convert XML back into XmlFu-compatible Hash/Array
|
19
|
-
# Parse XML into array of hashes. If XML used as input contains only sibling nodes, output
|
20
|
-
# will be array of hashes corresponding to those sibling nodes.
|
21
|
-
#
|
22
|
-
# <foo/><bar/> => [{"foo/" => ""}, {"bar/" => ""}]
|
23
|
-
#
|
24
|
-
# If XML used as input contains a full document with root node, output will be
|
25
|
-
# an array of one hash (the root node hash)
|
26
|
-
#
|
27
|
-
# <foo><bar/><baz/></foo> => [{"foo" => [{"bar/" => ""},{"baz/" => ""}] }]
|
28
|
-
def parse(xml=nil, options={})
|
29
|
-
parsed_xml = xml
|
10
|
+
# Convert construct into XML
|
11
|
+
def self.xml(construct, options={})
|
30
12
|
|
31
|
-
|
13
|
+
# Override options for xml_declaration if config is present
|
14
|
+
unless self.config.include_xml_declaration.nil?
|
15
|
+
options[:instruct] = self.config.include_xml_declaration
|
32
16
|
end
|
33
17
|
|
34
|
-
|
35
|
-
|
18
|
+
case construct
|
19
|
+
when ::OpenStruct then
|
20
|
+
OpenStruct.to_xml( construct.dup, options )
|
21
|
+
when ::Hash then
|
22
|
+
Hash.to_xml( construct.dup, options )
|
23
|
+
when ::Array then
|
24
|
+
Array.to_xml( construct.dup, options )
|
25
|
+
else
|
26
|
+
if construct.respond_to?(:to_xml)
|
27
|
+
construct.to_xml
|
28
|
+
else
|
29
|
+
# Options have been exhausted
|
30
|
+
if self.config.fail_on_invalid_construct
|
31
|
+
raise ArgumentError, "Invalid construct"
|
32
|
+
else
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
36
36
|
end
|
37
|
+
end#self.xml
|
37
38
|
|
38
|
-
################################################################################
|
39
|
-
## CONFIGURATIONS
|
40
|
-
################################################################################
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
40
|
+
# Used to determine if the top-level #xml method recognizes the passed object
|
41
|
+
def self.recognized_object?(obj)
|
42
|
+
case obj
|
43
|
+
when ::Hash then return true
|
44
|
+
when ::Array then return true
|
45
|
+
when ::OpenStruct then return true
|
46
|
+
else
|
47
|
+
return true if obj.respond_to?(:to_xml)
|
48
|
+
return false
|
47
49
|
end
|
50
|
+
end#self.recognized_object?
|
48
51
|
|
49
|
-
# Configuration option to be used with future releases
|
50
|
-
# This option should allow for the inferrance of parent node names of simple value types
|
51
|
-
#
|
52
|
-
# Example:
|
53
|
-
# 1 => <Integer>1</Integer>
|
54
|
-
# true => <Boolean>true</Boolean>
|
55
|
-
#
|
56
|
-
# This is disabled by default as it is conflicting with working logic.
|
57
|
-
def infer_simple_value_nodes
|
58
|
-
return @@infer_simple_value_nodes
|
59
|
-
end
|
60
52
|
|
53
|
+
################################################################################
|
54
|
+
## CONFIGURATIONS
|
55
|
+
################################################################################
|
56
|
+
|
57
|
+
# Modify configuration for library
|
58
|
+
# @yield [Configuration]
|
59
|
+
def self.configure
|
60
|
+
yield self.config if block_given?
|
61
|
+
end#configure
|
61
62
|
|
62
|
-
# @param formula_enum Formula Enumeration
|
63
|
-
# @return [lambda]
|
64
|
-
def symbol_conversion_algorithm=( formula_enum=nil, &block )
|
65
|
-
XmlFu::Node.symbol_conversion_algorithm = (formula_enum ? formula_enum : block)
|
66
|
-
end#symbol_conversion_algorithm
|
67
63
|
|
64
|
+
def self.config
|
65
|
+
@@config ||= Configuration.new
|
66
|
+
end#self.config
|
68
67
|
|
69
|
-
# @return [lambda]
|
70
|
-
def symbol_conversion_algorithm
|
71
|
-
XmlFu::Node.symbol_conversion_algorithm
|
72
|
-
end#symbol_conversion_algorithm
|
73
68
|
|
74
|
-
end#class<<self
|
75
69
|
end#XmlFu
|
data/lib/xml-fu/array.rb
CHANGED
@@ -22,46 +22,24 @@ module XmlFu
|
|
22
22
|
case options[:content_type].to_s
|
23
23
|
when "collection"
|
24
24
|
raise(MissingKeyException, "Key name missing for collection") if key.empty?
|
25
|
-
|
26
|
-
case
|
27
|
-
when ::Array
|
25
|
+
|
26
|
+
case item
|
27
|
+
when ::Array then
|
28
28
|
xml << Array.to_xml(item.flatten,options)
|
29
29
|
else
|
30
30
|
xml << Node.new(key, item, attributes).to_xml
|
31
31
|
end
|
32
32
|
else
|
33
33
|
# Array is content of node rather than collection of node elements
|
34
|
-
|
35
|
-
|
36
|
-
xml << Hash.to_xml(item, options)
|
37
|
-
when ::Array === item
|
38
|
-
xml << Array.to_xml(item, options)
|
39
|
-
when XmlFu.infer_simple_value_nodes == true
|
40
|
-
xml << infer_node(item, attributes)
|
41
|
-
when item.respond_to?(:to_xml)
|
42
|
-
xml << item.to_xml
|
34
|
+
if XmlFu.recognized_object?(item)
|
35
|
+
xml << XmlFu.xml(item, options)
|
43
36
|
else
|
44
|
-
# unknown xml
|
37
|
+
# unknown xml transformation
|
45
38
|
end
|
46
39
|
end
|
47
40
|
end
|
48
41
|
end#self.to_xml
|
49
42
|
|
50
|
-
# Future Functionality - VERY ALPHA STAGE!!!
|
51
|
-
# @todo Add node inferrance functionality
|
52
|
-
# @note Do not use if you want stable functionality
|
53
|
-
# @param item Simple Value
|
54
|
-
# @param [Hash] attributes Hash of attributes to assign to inferred node.
|
55
|
-
def self.infer_node(item, attributes={})
|
56
|
-
node_name = case item.class
|
57
|
-
when "TrueClass"
|
58
|
-
when "FalseClass"
|
59
|
-
"Boolean"
|
60
|
-
else
|
61
|
-
item.class
|
62
|
-
end
|
63
|
-
Node.new(node_name, item, attributes).to_xml
|
64
|
-
end#self.infer_node
|
65
43
|
|
66
44
|
# Convenience function to iterate over array items as well as
|
67
45
|
# providing a single location for logic
|
@@ -74,7 +52,7 @@ module XmlFu
|
|
74
52
|
key = opts.fetch(:key, "")
|
75
53
|
item_content = item
|
76
54
|
|
77
|
-
# Attributes reuires duplicate or child elements will
|
55
|
+
# Attributes reuires duplicate or child elements will
|
78
56
|
# contain attributes of their siblings.
|
79
57
|
attributes = (opts[:attributes] ? opts[:attributes].dup : {})
|
80
58
|
|
@@ -84,7 +62,7 @@ module XmlFu
|
|
84
62
|
end
|
85
63
|
|
86
64
|
item_name = ( Symbol === key ?
|
87
|
-
XmlFu
|
65
|
+
XmlFu.config.symbol_conversion_algorithm.call(key) :
|
88
66
|
key.to_s )
|
89
67
|
|
90
68
|
yield xml, item_name, item_content, attributes
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module XmlFu
|
2
|
+
class Configuration
|
3
|
+
# @attr [lambda] symbol_conversion_algorithm (:lower_camelcase)
|
4
|
+
# symbol-to-string conversion algorithm
|
5
|
+
attr_reader :symbol_conversion_algorithm # define my own writer
|
6
|
+
|
7
|
+
# @attr [Boolean] fail_on_invalid_construct (false)
|
8
|
+
# By default, XmlFu works for converting Hash, Array, and OpenStruct objects. Any other
|
9
|
+
# type of object will be ignored and the result would return an empty string. With this option
|
10
|
+
# enabled, XmlFu will raise an exception if an unsupported object is attempted to be
|
11
|
+
# converted.
|
12
|
+
attr_accessor :fail_on_invalid_construct
|
13
|
+
|
14
|
+
# @attr [Boolean, nil] include_xml_declaration (nil)
|
15
|
+
# If set, will override XmlFu.xml :istruct option for toggling the XML declaration for
|
16
|
+
# the generated output.
|
17
|
+
attr_accessor :include_xml_declaration
|
18
|
+
|
19
|
+
|
20
|
+
ALGORITHMS = {
|
21
|
+
:camelcase => lambda { |sym| sym.to_s.camelcase },
|
22
|
+
:downcase => lambda { |sym| sym.to_s.downcase },
|
23
|
+
:lower_camelcase => lambda { |sym| sym.to_s.lower_camelcase }, # DEFAULT
|
24
|
+
:none => lambda { |sym| sym.to_s },
|
25
|
+
:upcase => lambda { |sym| sym.to_s.upcase }
|
26
|
+
}
|
27
|
+
|
28
|
+
|
29
|
+
# Set default values
|
30
|
+
def initialize
|
31
|
+
@symbol_conversion_algorithm = ALGORITHMS[:lower_camelcase]
|
32
|
+
@fail_on_invalid_construct = false
|
33
|
+
@include_xml_declaration = nil
|
34
|
+
end#initialize
|
35
|
+
|
36
|
+
|
37
|
+
# Method for setting global Symbol-to-string conversion algorithm
|
38
|
+
# @param [symbol, lambda] algorithm
|
39
|
+
# Can be symbol corresponding to predefined algorithm or a lambda that accepts a symbol
|
40
|
+
# as an argument and returns a string
|
41
|
+
def symbol_conversion_algorithm=(algorithm)
|
42
|
+
raise(ArgumentError, "Missing symbol conversion algorithm") unless algorithm
|
43
|
+
|
44
|
+
if algorithm.respond_to?(:call)
|
45
|
+
@symbol_conversion_algorithm = algorithm
|
46
|
+
else
|
47
|
+
if algorithm == :default
|
48
|
+
@symbol_conversion_algorithm = ALGORITHMS[:lower_camelcase]
|
49
|
+
elsif ALGORITHMS.keys.include?(algorithm)
|
50
|
+
@symbol_conversion_algorithm = ALGORITHMS[algorithm]
|
51
|
+
else
|
52
|
+
raise(ArgumentError, "Invalid symbol conversion algorithm")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end#symbol_conversion_algorithm
|
56
|
+
|
57
|
+
end#class
|
58
|
+
end#module
|
data/lib/xml-fu/hash.rb
CHANGED
@@ -9,61 +9,67 @@ module XmlFu
|
|
9
9
|
# If order is of concern, use Array.to_xml
|
10
10
|
class Hash
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
# Convert Hash to XML String
|
13
|
+
def self.to_xml(hash, options={})
|
14
|
+
each_with_xml hash, options do |xml, name, value, attributes|
|
15
|
+
case value
|
16
|
+
when ::OpenStruct then
|
17
|
+
node = Node.new( name, OpenStruct.to_xml(value, options) )
|
18
|
+
# We want the value returned from OpenStruct.to_xml NOT to be escaped
|
19
|
+
node.escape_xml = false
|
20
|
+
|
21
|
+
xml << node.to_xml
|
22
|
+
else
|
17
23
|
xml << Node.new(name, value, attributes).to_xml
|
18
24
|
end
|
19
|
-
end
|
25
|
+
end
|
26
|
+
end#self.to_xml
|
20
27
|
|
21
28
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
29
|
+
# Class method to filter out attributes and content
|
30
|
+
# from a given hash
|
31
|
+
def self.filter(hash)
|
32
|
+
attribs = {}
|
33
|
+
content = hash.dup
|
27
34
|
|
28
|
-
|
29
|
-
|
30
|
-
|
35
|
+
content.keys.select{|k| k =~ /^@/ }.each do |k|
|
36
|
+
attribs[k[1..-1]] = content.delete(k)
|
37
|
+
end
|
31
38
|
|
32
|
-
|
33
|
-
|
39
|
+
# Use _content value if defined
|
40
|
+
content = content.delete("=") || content
|
34
41
|
|
35
|
-
|
36
|
-
|
42
|
+
return [content, attribs]
|
43
|
+
end#self.filter
|
37
44
|
|
38
|
-
|
45
|
+
private
|
39
46
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
47
|
+
# Provides a convenience function to iterate over the hash
|
48
|
+
# Logic will filter out attribute and content keys from hash values
|
49
|
+
def self.each_with_xml(hash, opts={})
|
50
|
+
xml = XmlFu::Markup.new(opts)
|
44
51
|
|
45
|
-
|
46
|
-
|
47
|
-
|
52
|
+
hash.each do |key,value|
|
53
|
+
node_value = value
|
54
|
+
node_attrs = {}
|
48
55
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
# yank the attribute keys into their own hash
|
57
|
+
if value.respond_to?(:keys)
|
58
|
+
filtered = Hash.filter(value)
|
59
|
+
node_value, node_attrs = filtered.first, filtered.last
|
60
|
+
end
|
54
61
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
62
|
+
# Use symbol conversion algorithm to set tag name
|
63
|
+
node_name = ( Symbol === key ?
|
64
|
+
XmlFu.config.symbol_conversion_algorithm.call(key) :
|
65
|
+
key.to_s )
|
59
66
|
|
60
|
-
|
61
|
-
|
67
|
+
yield xml, node_name, node_value, node_attrs
|
68
|
+
end
|
62
69
|
|
63
|
-
|
64
|
-
|
70
|
+
xml.target!
|
71
|
+
end#self.each_with_xml
|
65
72
|
|
66
|
-
end#class << self
|
67
73
|
|
68
74
|
end#Hash
|
69
75
|
|
data/lib/xml-fu/node.rb
CHANGED
@@ -15,35 +15,6 @@ module XmlFu
|
|
15
15
|
# xs:dateTime format.
|
16
16
|
XS_DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
17
17
|
|
18
|
-
# default set of algorithms to choose from
|
19
|
-
ALGORITHMS = {
|
20
|
-
:camelcase => lambda { |sym| sym.to_s.camelcase },
|
21
|
-
:downcase => lambda { |sym| sym.to_s.downcase },
|
22
|
-
:lower_camelcase => lambda { |sym| sym.to_s.lower_camelcase }, # DEFAULT
|
23
|
-
:none => lambda { |sym| sym.to_s },
|
24
|
-
:upcase => lambda { |sym| sym.to_s.upcase }
|
25
|
-
}
|
26
|
-
|
27
|
-
# Class method for retrieving global Symbol-to-string conversion algorithm
|
28
|
-
# @return [lambda]
|
29
|
-
def self.symbol_conversion_algorithm
|
30
|
-
@symbol_conversion_algorithm ||= ALGORITHMS[:lower_camelcase]
|
31
|
-
end#self.symbol_conversion_algorithm
|
32
|
-
|
33
|
-
# Class method for setting global Symbol-to-string conversion algorithm
|
34
|
-
# @param [symbol, lambda] algorithm
|
35
|
-
# Can be symbol corresponding to predefined algorithm or a lambda that accepts a symbol
|
36
|
-
# as an argument and returns a string
|
37
|
-
def self.symbol_conversion_algorithm=(algorithm)
|
38
|
-
if algorithm == :default
|
39
|
-
algorithm = ALGORITHMS[:lower_camelcase]
|
40
|
-
else
|
41
|
-
algorithm = ALGORITHMS[algorithm] unless algorithm.respond_to?(:call)
|
42
|
-
end
|
43
|
-
raise(ArgumentError, "Invalid symbol conversion algorithm") unless algorithm
|
44
|
-
@symbol_conversion_algorithm = algorithm
|
45
|
-
end#self.symbol_conversion_algorithm=
|
46
|
-
|
47
18
|
attr_accessor :escape_xml
|
48
19
|
attr_accessor :self_closing
|
49
20
|
attr_accessor :content_type
|
@@ -61,6 +32,7 @@ module XmlFu
|
|
61
32
|
self.name = name
|
62
33
|
end#initialize
|
63
34
|
|
35
|
+
|
64
36
|
attr_reader :attributes
|
65
37
|
def attributes=(val)
|
66
38
|
if ::Hash === val
|
@@ -70,6 +42,7 @@ module XmlFu
|
|
70
42
|
end
|
71
43
|
end
|
72
44
|
|
45
|
+
|
73
46
|
attr_reader :name
|
74
47
|
def name=(val)
|
75
48
|
use_name = val.dup
|
@@ -80,13 +53,14 @@ module XmlFu
|
|
80
53
|
use_name = use_name[1..-1] if use_name[0,1] == ":"
|
81
54
|
|
82
55
|
if Symbol === val
|
83
|
-
use_name =
|
56
|
+
use_name = XmlFu.config.symbol_conversion_algorithm.call(use_name)
|
84
57
|
end
|
85
58
|
|
86
59
|
# Set name to remaining value
|
87
60
|
@name = "#{use_name}"
|
88
61
|
end#name=
|
89
62
|
|
63
|
+
|
90
64
|
# Converts name into proper XML node name
|
91
65
|
# @param [String, Symbol] val Raw name
|
92
66
|
def name_parse_special_characters(val)
|
@@ -116,15 +90,17 @@ module XmlFu
|
|
116
90
|
return use_this
|
117
91
|
end#name_parse_special_characters
|
118
92
|
|
93
|
+
|
119
94
|
# Custom Setter for @value instance method
|
120
95
|
def value=(val)
|
121
96
|
case val
|
122
|
-
when ::String
|
123
|
-
when ::Hash
|
124
|
-
when ::Array
|
125
|
-
when ::
|
126
|
-
when ::
|
127
|
-
when ::
|
97
|
+
when ::String then @value = val.to_s
|
98
|
+
when ::Hash then @value = val
|
99
|
+
when ::Array then @value = val
|
100
|
+
when ::OpenStruct then @value = val
|
101
|
+
when ::DateTime then @value = val.strftime XS_DATETIME_FORMAT
|
102
|
+
when ::Time then @value = val.strftime XS_DATETIME_FORMAT
|
103
|
+
when ::Date then @value = val.strftime XS_DATETIME_FORMAT
|
128
104
|
else
|
129
105
|
if val.respond_to?(:to_datetime)
|
130
106
|
@value = val.to_datetime
|
@@ -140,6 +116,7 @@ module XmlFu
|
|
140
116
|
@value = val.to_s
|
141
117
|
end#value=
|
142
118
|
|
119
|
+
|
143
120
|
# @return [String, nil]
|
144
121
|
# Value can be nil, else it should return a String value.
|
145
122
|
def value
|
@@ -147,6 +124,7 @@ module XmlFu
|
|
147
124
|
return @value
|
148
125
|
end#value
|
149
126
|
|
127
|
+
|
150
128
|
# Create XML String from XmlFu::Node object
|
151
129
|
def to_xml
|
152
130
|
xml = Builder::XmlMarkup.new
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'builder'
|
3
|
+
require 'xml-fu/node'
|
4
|
+
|
5
|
+
module XmlFu
|
6
|
+
# An OpenStruct object behaves similar to a Hash in that it has key/value pairs,
|
7
|
+
# but is more restrictive with key names. As such, it is near impossible to set "attribute"
|
8
|
+
# keys on an OpenStruct object.
|
9
|
+
class OpenStruct
|
10
|
+
|
11
|
+
def self.to_xml(obj, options={})
|
12
|
+
Hash.to_xml(obj.marshal_dump, options)
|
13
|
+
end#self.to_xml
|
14
|
+
|
15
|
+
end#class
|
16
|
+
|
17
|
+
end#module
|
data/lib/xml-fu/version.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe XmlFu::Configuration do
|
4
|
+
subject { XmlFu::Configuration }
|
5
|
+
|
6
|
+
it "should have ::ALGORITHMS" do
|
7
|
+
lambda { subject::ALGORITHMS }.should_not raise_exception
|
8
|
+
subject::ALGORITHMS.should_not be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "instance" do
|
12
|
+
subject { XmlFu::Configuration.new }
|
13
|
+
|
14
|
+
[ :symbol_conversion_algorithm,
|
15
|
+
:symbol_conversion_algorithm=,
|
16
|
+
:fail_on_invalid_construct,
|
17
|
+
:include_xml_declaration
|
18
|
+
].each do |m|
|
19
|
+
it "should respond_to '#{m}'" do
|
20
|
+
subject.should respond_to(m)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end#instance
|
24
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe XmlFu::OpenStruct do
|
5
|
+
let(:klass) { XmlFu::OpenStruct }
|
6
|
+
|
7
|
+
describe ".to_xml" do
|
8
|
+
subject { OpenStruct.new({:foo => "bar"}) }
|
9
|
+
|
10
|
+
it "should result in correct output" do
|
11
|
+
klass.to_xml(subject).should == "<foo>bar</foo>"
|
12
|
+
end
|
13
|
+
|
14
|
+
context "with complex nesting" do
|
15
|
+
subject do
|
16
|
+
OpenStruct.new({
|
17
|
+
:foo => [
|
18
|
+
OpenStruct.new({ :bar => "bang" }),
|
19
|
+
{ :bang => :biz },
|
20
|
+
{ "number*" => [
|
21
|
+
{ "@name" => "pi", "=" => 3.14159 }
|
22
|
+
]}
|
23
|
+
]
|
24
|
+
})
|
25
|
+
end
|
26
|
+
|
27
|
+
# NOTE: (TL;DR) Cannot guarantee attribute order, can only guarantee attribute presence
|
28
|
+
#
|
29
|
+
# Due to the way XML::Builder iterates over attributes, the order of the attributes
|
30
|
+
# cannot be guaranteed. This is because of the way that ruby stores and iterates
|
31
|
+
# over a Hash, and it is different depending on the version of Ruby being used.
|
32
|
+
it "should result in correct output" do
|
33
|
+
klass.to_xml(subject).should == '<foo><bar>bang</bar><bang>biz</bang><number name="pi">3.14159</number></foo>'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end#.to_xml
|
37
|
+
end
|
data/spec/lib/xml-fu_spec.rb
CHANGED
@@ -2,12 +2,12 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe XmlFu do
|
4
4
|
after(:each) do
|
5
|
-
XmlFu.symbol_conversion_algorithm = :default
|
5
|
+
XmlFu.config.symbol_conversion_algorithm = :default
|
6
6
|
end
|
7
7
|
|
8
8
|
describe "with default symbol conversion algorithm" do
|
9
9
|
before(:each) do
|
10
|
-
XmlFu.symbol_conversion_algorithm = :default
|
10
|
+
XmlFu.config.symbol_conversion_algorithm = :default
|
11
11
|
end
|
12
12
|
|
13
13
|
{
|
@@ -24,7 +24,7 @@ describe XmlFu do
|
|
24
24
|
|
25
25
|
describe "with built-in :camelcase algorithm" do
|
26
26
|
before(:each) do
|
27
|
-
XmlFu.symbol_conversion_algorithm = :camelcase
|
27
|
+
XmlFu.config.symbol_conversion_algorithm = :camelcase
|
28
28
|
end
|
29
29
|
|
30
30
|
{
|
@@ -41,7 +41,7 @@ describe XmlFu do
|
|
41
41
|
|
42
42
|
describe "with built-in :downcase algorithm" do
|
43
43
|
before(:each) do
|
44
|
-
XmlFu.symbol_conversion_algorithm = :downcase
|
44
|
+
XmlFu.config.symbol_conversion_algorithm = :downcase
|
45
45
|
end
|
46
46
|
|
47
47
|
{
|
@@ -58,7 +58,7 @@ describe XmlFu do
|
|
58
58
|
|
59
59
|
describe "with built-in :upcase algorithm" do
|
60
60
|
before(:each) do
|
61
|
-
XmlFu.symbol_conversion_algorithm = :upcase
|
61
|
+
XmlFu.config.symbol_conversion_algorithm = :upcase
|
62
62
|
end
|
63
63
|
|
64
64
|
{
|
@@ -71,5 +71,4 @@ describe XmlFu do
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end#:upcase
|
74
|
-
|
75
|
-
end
|
74
|
+
end#XmlFu
|
data/spec/xmlfu_spec.rb
CHANGED
@@ -2,97 +2,180 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe XmlFu do
|
4
4
|
describe ".xml" do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
context "(default configuration)" do
|
6
|
+
context "with an unsupported construct as argument" do
|
7
|
+
it "should return nil" do
|
8
|
+
XmlFu.xml(1).should == nil
|
9
|
+
XmlFu.xml(nil).should == nil
|
10
|
+
XmlFu.xml(Object.new).should == nil
|
11
|
+
end
|
12
|
+
end
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
+
it "translates a given Hash to XML" do
|
15
|
+
XmlFu.xml({:id => 1}).should == "<id>1</id>"
|
16
|
+
end
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
it "doesn't modify the input hash" do
|
19
|
+
the_hash = {
|
20
|
+
:person => {
|
21
|
+
"@id" => "007",
|
22
|
+
:first_name => "James",
|
23
|
+
:last_name => "Bond"
|
24
|
+
}
|
21
25
|
}
|
22
|
-
|
23
|
-
original_hash = the_hash.dup
|
26
|
+
original_hash = the_hash.dup
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
+
XmlFu.xml(the_hash)
|
29
|
+
original_hash.should == the_hash
|
30
|
+
end
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
it "should return correct value based on nested array of hashes" do
|
33
|
+
hash = {
|
34
|
+
"SecretAgents" => [
|
35
|
+
{"agent/" => {"@name"=>"Alec Trevelyan"}},
|
36
|
+
{"agent/" => {"@name"=>"James Bond"}}
|
37
|
+
]
|
38
|
+
}
|
39
|
+
expected = '<SecretAgents><agent name="Alec Trevelyan"/><agent name="James Bond"/></SecretAgents>'
|
40
|
+
XmlFu.xml(hash).should == expected
|
41
|
+
end
|
39
42
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
43
|
+
it "should return correct value for nested collection of hashes" do
|
44
|
+
hash = {
|
45
|
+
"foo*" => [
|
46
|
+
{"@bar" => "biz"},
|
47
|
+
{"@biz" => "bang"}
|
48
|
+
]
|
49
|
+
}
|
50
|
+
XmlFu.xml(hash).should == '<foo bar="biz"></foo><foo biz="bang"></foo>'
|
51
|
+
end
|
49
52
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
53
|
+
it "should return list of self-closing nodes" do
|
54
|
+
hash = {
|
55
|
+
"foo/*" => [
|
56
|
+
{"@bar" => "biz"},
|
57
|
+
{"@biz" => "bang"}
|
58
|
+
]
|
59
|
+
}
|
60
|
+
XmlFu.xml(hash).should == '<foo bar="biz"/><foo biz="bang"/>'
|
61
|
+
end
|
59
62
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
63
|
+
it "should ignore nested values for content array" do
|
64
|
+
output = XmlFu.xml("foo/" => [{:bar => "biz"}, {:bar => "biz"}])
|
65
|
+
output.should == "<foo/>"
|
66
|
+
end
|
64
67
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
+
it "should ignore nested keys if they aren't attributes" do
|
69
|
+
output = XmlFu.xml("foo/" => {"bar" => "biz"})
|
70
|
+
output.should == "<foo/>"
|
68
71
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
72
|
+
output = XmlFu.xml("foo/" => {"@id" => "0"})
|
73
|
+
output.should == '<foo id="0"/>'
|
74
|
+
end
|
75
|
+
end#default configuration
|
73
76
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
77
|
+
context "with 'fail_on_invalid_construct' enabled" do
|
78
|
+
before(:each) do
|
79
|
+
XmlFu.configure do |config|
|
80
|
+
config.fail_on_invalid_construct = true
|
81
|
+
end
|
78
82
|
end
|
79
|
-
end
|
80
83
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
84
|
+
context "with an unsupported construct as argument" do
|
85
|
+
it "should raise an ArgumentError exception" do
|
86
|
+
lambda { XmlFu.xml(1) }.should raise_exception
|
87
|
+
lambda { XmlFu.xml(nil) }.should raise_exception
|
88
|
+
lambda { XmlFu.xml(Object.new) }.should raise_exception
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end#fail_on_invalid_construct enabled
|
92
|
+
|
93
|
+
context "with 'include_xml_declaration" do
|
94
|
+
context "set TRUE" do
|
95
|
+
before(:each) do
|
96
|
+
XmlFu.configure do |config|
|
97
|
+
config.include_xml_declaration = true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should ALWAYS output the xml declaration" do
|
102
|
+
XmlFu.xml({:foo => "bar"}).should == '<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>'
|
103
|
+
XmlFu.xml({:foo => "bar"}, {:instruct => false}).should == '<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>'
|
104
|
+
XmlFu.xml({:foo => "bar"}, {:instruct => true}).should == '<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>'
|
105
|
+
end
|
106
|
+
end#enabled
|
107
|
+
|
108
|
+
context "set FALSE" do
|
109
|
+
before(:each) do
|
110
|
+
XmlFu.configure do |config|
|
111
|
+
config.include_xml_declaration = false
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should NEVER output the xml declaration" do
|
116
|
+
XmlFu.xml({:foo => "bar"}).should == '<foo>bar</foo>'
|
117
|
+
XmlFu.xml({:foo => "bar"}, {:instruct => false}).should == '<foo>bar</foo>'
|
118
|
+
XmlFu.xml({:foo => "bar"}, {:instruct => true}).should == '<foo>bar</foo>'
|
119
|
+
end
|
120
|
+
end#enabled
|
121
|
+
|
122
|
+
context "set NIL" do
|
123
|
+
before(:each) do
|
124
|
+
XmlFu.configure do |config|
|
125
|
+
config.include_xml_declaration = nil
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should output if option says so" do
|
130
|
+
XmlFu.xml({:foo => "bar"}).should == '<foo>bar</foo>'
|
131
|
+
XmlFu.xml({:foo => "bar"}, {:instruct => false}).should == '<foo>bar</foo>'
|
132
|
+
XmlFu.xml({:foo => "bar"}, {:instruct => true}).should == '<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>'
|
133
|
+
end
|
134
|
+
end
|
87
135
|
end
|
88
|
-
end
|
136
|
+
end#.xml
|
137
|
+
|
138
|
+
describe ".recognized_object?" do
|
139
|
+
describe "should be true" do
|
140
|
+
it { XmlFu.recognized_object?(Hash.new).should be_true }
|
141
|
+
it { XmlFu.recognized_object?(Array.new).should be_true }
|
142
|
+
it { XmlFu.recognized_object?(OpenStruct.new).should be_true }
|
143
|
+
|
144
|
+
context "if object responds to :to_xml" do
|
145
|
+
subject do
|
146
|
+
obj = Object.new
|
147
|
+
def obj.to_xml; end
|
148
|
+
obj
|
149
|
+
end
|
150
|
+
it { XmlFu.recognized_object?(subject).should be_true }
|
151
|
+
end
|
152
|
+
end#should be true
|
153
|
+
|
154
|
+
describe "should be false" do
|
155
|
+
it { XmlFu.recognized_object?(1).should_not be_true }
|
156
|
+
it { XmlFu.recognized_object?("foobar").should_not be_true }
|
157
|
+
it { XmlFu.recognized_object?(1.23).should_not be_true }
|
158
|
+
context "if object does not respond to :to_xml" do
|
159
|
+
it { XmlFu.recognized_object?(Object.new).should_not be_true }
|
160
|
+
end
|
161
|
+
end#should be false
|
162
|
+
end#.recognized_object?
|
163
|
+
|
164
|
+
describe ".configure" do
|
165
|
+
context "yielded value" do
|
166
|
+
it "should be the same object as .config()" do
|
167
|
+
yielded = nil
|
168
|
+
XmlFu.configure { |c| yielded = c }
|
169
|
+
yielded.should == XmlFu.config
|
170
|
+
end
|
171
|
+
end#yielded value
|
172
|
+
end#.configure
|
89
173
|
|
90
|
-
describe ".
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
::Array === XmlFu.parse("foo", {:bar => true})
|
174
|
+
describe ".config" do
|
175
|
+
subject { XmlFu.config }
|
176
|
+
it "should be a XmlFu::Configuration object" do
|
177
|
+
subject.should be_a_kind_of(XmlFu::Configuration)
|
95
178
|
end
|
96
|
-
end
|
179
|
+
end#.config
|
97
180
|
|
98
181
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xml-fu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ryan Johnson
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2013-
|
18
|
+
date: 2013-09-24 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: builder
|
@@ -83,14 +83,18 @@ files:
|
|
83
83
|
- Rakefile
|
84
84
|
- lib/xml-fu.rb
|
85
85
|
- lib/xml-fu/array.rb
|
86
|
+
- lib/xml-fu/configuration.rb
|
86
87
|
- lib/xml-fu/core_ext/string.rb
|
87
88
|
- lib/xml-fu/hash.rb
|
88
89
|
- lib/xml-fu/markup.rb
|
89
90
|
- lib/xml-fu/node.rb
|
91
|
+
- lib/xml-fu/open_struct.rb
|
90
92
|
- lib/xml-fu/version.rb
|
91
93
|
- spec/lib/array_spec.rb
|
94
|
+
- spec/lib/configuration_spec.rb
|
92
95
|
- spec/lib/hash_spec.rb
|
93
96
|
- spec/lib/node_spec.rb
|
97
|
+
- spec/lib/open_struct_spec.rb
|
94
98
|
- spec/lib/xml-fu_spec.rb
|
95
99
|
- spec/lib/xml_spec.rb
|
96
100
|
- spec/spec_helper.rb
|
@@ -125,14 +129,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
129
|
requirements: []
|
126
130
|
|
127
131
|
rubyforge_project: xml-fu
|
128
|
-
rubygems_version: 1.8.
|
132
|
+
rubygems_version: 1.8.26
|
129
133
|
signing_key:
|
130
134
|
specification_version: 3
|
131
135
|
summary: Simple Hash/Array to XML generation
|
132
136
|
test_files:
|
133
137
|
- spec/lib/array_spec.rb
|
138
|
+
- spec/lib/configuration_spec.rb
|
134
139
|
- spec/lib/hash_spec.rb
|
135
140
|
- spec/lib/node_spec.rb
|
141
|
+
- spec/lib/open_struct_spec.rb
|
136
142
|
- spec/lib/xml-fu_spec.rb
|
137
143
|
- spec/lib/xml_spec.rb
|
138
144
|
- spec/spec_helper.rb
|