smacks-apricoteatsgorilla 0.2.4 → 0.2.5

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.
@@ -10,108 +10,120 @@ require 'hpricot'
10
10
  # but it quickly evolved into a more general translation tool.
11
11
  class ApricotEatsGorilla
12
12
 
13
- # Converts XML into a Hash. Starts parsing at root node by default.
14
- # Call with XPath expession (Hpricot search) as second parameter to define
15
- # a custom root node. The root node itself will not be included in the Hash.
16
- #
17
- # E.g.
18
- # xml = "<dude><likes>beer</likes><hates>appletini</hates></dude>"
19
- # ApricotEatsGorilla.xml_to_hash(xml)
20
- # # => { "hates" => "appletini", "likes" => "beer" }
21
- def self.xml_to_hash(xml, root_node = nil)
22
- xml = clean_xml(xml)
23
- doc = Hpricot.XML(xml)
24
- root = root_node ? doc.at(root_node) : doc.root
25
- xml_node_to_hash(root)
26
- end
13
+ class << self
14
+ attr_accessor :sort_keys
27
15
 
28
- # Converts a Hash to XML.
29
- #
30
- # E.g.
31
- # hash = { "dude" => { "likes" => "beer", "hates" => "appletini" } }
32
- # ApricotEatsGorilla.hash_to_xml(hash)
33
- # # => "<dude><hates>appletini</hates><likes>beer</likes></dude>"
34
- def self.hash_to_xml(hash)
35
- nested_data_to_xml(hash.keys.first, hash.values.first)
36
- end
16
+ # Converts XML into a Hash. Starts parsing at root node by default.
17
+ # Call with XPath expession (Hpricot search) as second parameter to define
18
+ # a custom root node. The root node itself will not be included in the Hash.
19
+ #
20
+ # E.g.
21
+ # xml = "<dude><likes>beer</likes><hates>appletini</hates></dude>"
22
+ # ApricotEatsGorilla.xml_to_hash(xml)
23
+ # # => { "hates" => "appletini", "likes" => "beer" }
24
+ def xml_to_hash(xml, root_node = nil)
25
+ xml = clean_xml(xml)
26
+ doc = Hpricot.XML(xml)
27
+ root = root_node ? doc.at(root_node) : doc.root
28
+ xml_node_to_hash(root)
29
+ end
37
30
 
38
- private
31
+ # Converts a Hash to XML.
32
+ #
33
+ # E.g.
34
+ # hash = { "dude" => { "likes" => "beer", "hates" => "appletini" } }
35
+ # ApricotEatsGorilla.hash_to_xml(hash)
36
+ # # => "<dude><hates>appletini</hates><likes>beer</likes></dude>"
37
+ def hash_to_xml(hash)
38
+ nested_data_to_xml(hash.keys.first, hash.values.first)
39
+ end
39
40
 
40
- # Converts XML into a Hash.
41
- def self.xml_node_to_hash(node)
42
- this_node = {}
41
+ private
43
42
 
44
- node.each_child do |child|
45
- if child.children.nil?
46
- key, value = child.name, nil
47
- elsif child.children.size == 1 && child.children.first.text?
48
- key, value = child.name, string_to_bool?(child.children.first.raw_string)
49
- else
50
- key, value = child.name, xml_node_to_hash(child)
51
- end
43
+ # Converts XML into a Hash.
44
+ def xml_node_to_hash(node)
45
+ this_node = {}
52
46
 
53
- current = this_node[key]
54
- case current
55
- when Array:
56
- this_node[key] << value
57
- when nil
58
- this_node[key] = value
47
+ node.each_child do |child|
48
+ if child.children.nil? || child.children.empty?
49
+ key, value = child.name, nil
50
+ elsif child.children.size == 1 && child.children.first.text?
51
+ key, value = child.name, string_to_bool?(child.children.first.inner_text)
59
52
  else
60
- this_node[key] = [current.dup, value]
53
+ key, value = child.name, xml_node_to_hash(child)
54
+ end
55
+
56
+ current = this_node[key]
57
+ case current
58
+ when Array:
59
+ this_node[key] << value
60
+ when nil
61
+ this_node[key] = value
62
+ else
63
+ this_node[key] = [current.dup, value]
64
+ end
61
65
  end
66
+
67
+ this_node
62
68
  end
63
69
 
64
- this_node
65
- end
70
+ # Converts a Hash to XML.
71
+ def nested_data_to_xml(name, item)
72
+ case item
73
+ when String
74
+ make_tag(name) { item }
75
+ when Array
76
+ item.map { |subitem| nested_data_to_xml(name, subitem) }.join
77
+ when Hash
78
+ make_tag(name) do
79
+ opt_order(item).map { |tag, value|
80
+ case value
81
+ when String
82
+ make_tag(tag) { value }
83
+ when Array
84
+ value.map { |subitem| nested_data_to_xml(tag, subitem) }.join
85
+ when Hash
86
+ nested_data_to_xml(tag, value)
87
+ end
88
+ }.join
89
+ end
90
+ end
91
+ end
66
92
 
67
- # Converts a Hash to XML.
68
- def self.nested_data_to_xml(name, item)
69
- case item
70
- when String
71
- make_tag(name) { item }
72
- when Array
73
- item.map { |subitem| nested_data_to_xml(name, subitem) }.join
74
- when Hash
75
- make_tag(name) do
76
- item.map { |tag, value|
77
- case value
78
- when String
79
- make_tag(tag) { value }
80
- when Array
81
- value.map { |subitem| nested_data_to_xml(tag, subitem) }.join
82
- when Hash
83
- nested_data_to_xml(tag, value)
84
- end
85
- }.join
93
+ # Helper to create an XML tag. Expects a block for tag content.
94
+ # Defaults to an empty element tag in case no block was supplied.
95
+ def make_tag(name)
96
+ body = yield
97
+ if body && !body.empty?
98
+ "<#{name}>" << body << "</#{name}>"
99
+ else
100
+ "<#{name} />"
86
101
  end
87
102
  end
88
- end
89
103
 
90
- # Helper to create an XML tag. Expects a block for tag content.
91
- # Defaults to an empty element tag in case no block was supplied.
92
- def self.make_tag(name)
93
- body = yield
94
- if body && !body.empty?
95
- "<#{name}>" << body << "</#{name}>"
96
- else
97
- "<#{name} />"
104
+ def opt_order(hash)
105
+ if sort_keys
106
+ hash.sort_by{ |kv| kv.first }
107
+ else
108
+ hash
109
+ end
98
110
  end
99
- end
100
-
101
- # Helper to remove line breaks and whitespace between XML tags.
102
- def self.clean_xml(xml)
103
- xml = xml.gsub(/\n+/, "")
104
- xml = xml.gsub(/(>)\s*(<)/, '\1\2')
105
- end
106
111
 
107
- # Helper to convert "true" and "false" strings to boolean values.
108
- # Returns the original string in case it doesn't match "true" or "false".
109
- def self.string_to_bool?(string)
110
- return true if string == "true"
111
- return false if string == "false"
112
- string
113
- end
112
+ # Helper to remove line breaks and whitespace between XML tags.
113
+ def clean_xml(xml)
114
+ xml = xml.gsub(/\n+/, "")
115
+ xml = xml.gsub(/(>)\s*(<)/, '\1\2')
116
+ end
114
117
 
118
+ # Helper to convert "true" and "false" strings to boolean values.
119
+ # Returns the original string in case it doesn't match "true" or "false".
120
+ def string_to_bool?(string)
121
+ return true if string == "true"
122
+ return false if string == "false"
123
+ string
124
+ end
125
+
126
+ end
115
127
  end
116
128
 
117
129
  # Shortcut method for translating between XML documents and Hashes.
@@ -4,6 +4,10 @@ require File.join(File.dirname(__FILE__), "..", "lib", "apricoteatsgorilla")
4
4
 
5
5
  class HashToXmlTest < Test::Unit::TestCase
6
6
 
7
+ def setup
8
+ ApricotEatsGorilla.sort_keys = true
9
+ end
10
+
7
11
  def test_dead_simple
8
12
  hash = { "dude" => "likes beer" }
9
13
  expected = "<dude>likes beer</dude>"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smacks-apricoteatsgorilla
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Harrington