xml_hate 0.8.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/.gitignore +6 -0
- data/.rvmrc +55 -0
- data/Gemfile +15 -0
- data/Guardfile +12 -0
- data/Rakefile +1 -0
- data/lib/xml_hate/document.rb +83 -0
- data/lib/xml_hate/node.rb +31 -0
- data/lib/xml_hate/version.rb +3 -0
- data/lib/xml_hate.rb +7 -0
- data/readme.md +55 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/xml_hate/document_spec.rb +236 -0
- data/spec/xml_hate/node_spec.rb +80 -0
- data/xml_hate.gemspec +24 -0
- metadata +84 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
+
# development environment upon cd'ing into the directory
|
5
|
+
|
6
|
+
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
|
7
|
+
environment_id="ruby-1.8.7-p352@xml_hate"
|
8
|
+
|
9
|
+
#
|
10
|
+
# Uncomment following line if you want options to be set only for given project.
|
11
|
+
#
|
12
|
+
# PROJECT_JRUBY_OPTS=( --1.9 )
|
13
|
+
|
14
|
+
#
|
15
|
+
# First we attempt to load the desired environment directly from the environment
|
16
|
+
# file. This is very fast and efficient compared to running through the entire
|
17
|
+
# CLI and selector. If you want feedback on which environment was used then
|
18
|
+
# insert the word 'use' after --create as this triggers verbose mode.
|
19
|
+
#
|
20
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
|
21
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
22
|
+
then
|
23
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
24
|
+
|
25
|
+
if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
|
26
|
+
then
|
27
|
+
. "${rvm_path:-$HOME/.rvm}/hooks/after_use"
|
28
|
+
fi
|
29
|
+
else
|
30
|
+
# If the environment file has not yet been created, use the RVM CLI to select.
|
31
|
+
if ! rvm --create "$environment_id"
|
32
|
+
then
|
33
|
+
echo "Failed to create RVM environment '${environment_id}'."
|
34
|
+
return 1
|
35
|
+
fi
|
36
|
+
fi
|
37
|
+
|
38
|
+
#
|
39
|
+
# If you use an RVM gemset file to install a list of gems (*.gems), you can have
|
40
|
+
# it be automatically loaded. Uncomment the following and adjust the filename if
|
41
|
+
# necessary.
|
42
|
+
#
|
43
|
+
# filename=".gems"
|
44
|
+
# if [[ -s "$filename" ]]
|
45
|
+
# then
|
46
|
+
# rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
|
47
|
+
# fi
|
48
|
+
|
49
|
+
# If you use bundler, this might be useful to you:
|
50
|
+
# if command -v bundle && [[ -s Gemfile ]]
|
51
|
+
# then
|
52
|
+
# bundle install
|
53
|
+
# fi
|
54
|
+
|
55
|
+
|
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in xml_hate.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'xml-simple'
|
7
|
+
gem 'hashie'
|
8
|
+
gem 'activesupport'
|
9
|
+
|
10
|
+
gem 'minitest'
|
11
|
+
group :development do
|
12
|
+
gem 'guard'
|
13
|
+
gem 'guard-minitest', :git => 'git://github.com/aspiers/guard-minitest.git'
|
14
|
+
gem 'ruby_gntp'
|
15
|
+
end
|
data/Guardfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
guard 'minitest' do
|
2
|
+
watch(%r|^test/test_(.*)\.rb|)
|
3
|
+
watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
|
4
|
+
watch(%r|^test/test_helper\.rb|) { "test" }
|
5
|
+
watch(%r|^lib/(.*)\.rb|) { |m| "test/test_#{m[1]}.rb" }
|
6
|
+
|
7
|
+
watch(%r{^spec/.+_spec\.rb$})
|
8
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
9
|
+
watch(%r{^lib/xml_hate/(.+)\.rb$}) { |m| "spec/xml_hate/#{m[1]}_spec.rb" }
|
10
|
+
watch(%r{^spec/models/.+\.rb$}) { ["spec/models", "spec/acceptance"] }
|
11
|
+
watch('spec/spec_helper.rb') { "spec" }
|
12
|
+
end
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
|
4
|
+
module XmlHate
|
5
|
+
class Document
|
6
|
+
def initialize(xml)
|
7
|
+
@document = XmlSimple.xml_in(xml)
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(meth, *args, &blk)
|
11
|
+
return "" if @document.has_key?(meth.to_s) == false
|
12
|
+
objects = pull_the_objects_from_the_xml_document(meth)
|
13
|
+
objects.count == 1 ? objects[0] : objects
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def pull_the_objects_from_the_xml_document(meth)
|
19
|
+
nodes = read_the_matching_nodes_from_the_xml_document(meth)
|
20
|
+
convert_the_hashes_to_objects(nodes)
|
21
|
+
end
|
22
|
+
|
23
|
+
def read_the_matching_nodes_from_the_xml_document(meth)
|
24
|
+
@document[meth.to_s].map { |n| process_this_top_level_node(n) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def convert_the_hashes_to_objects(objects)
|
28
|
+
objects.map do |v|
|
29
|
+
v.class == Hashie::Mash ? Node.new(v) : v
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def process_this_top_level_node(node)
|
34
|
+
return node if node.class == String
|
35
|
+
new_object = Hashie::Mash.new(node)
|
36
|
+
process_this_inner_node(new_object)
|
37
|
+
end
|
38
|
+
|
39
|
+
def process_this_inner_node(node)
|
40
|
+
# get the values to pluralize before modifying the node
|
41
|
+
values_to_pluralize = get_values_to_pluralize(node)
|
42
|
+
|
43
|
+
# this may modify the values checked to be pluralized
|
44
|
+
bring_up_single_elements_as_properties(node)
|
45
|
+
|
46
|
+
# now "pluralize" by setting the pluralized key
|
47
|
+
values_to_pluralize.each { |key, value| node[key] = value }
|
48
|
+
|
49
|
+
node
|
50
|
+
end
|
51
|
+
|
52
|
+
def bring_up_single_elements_as_properties(node)
|
53
|
+
get_properties_with_multiple_elements(node).each do |key, value|
|
54
|
+
value.each { |v| process_this_inner_node(v) }
|
55
|
+
node[key] = value[0] if get_the_number_of_elements(value) == 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_values_to_pluralize(node)
|
60
|
+
values_to_pluralize = {}
|
61
|
+
get_properties_with_multiple_elements(node).each do |key, value|
|
62
|
+
values_to_pluralize[key.pluralize] = value if key.pluralize != key
|
63
|
+
end
|
64
|
+
values_to_pluralize
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_properties_with_multiple_elements(node)
|
68
|
+
begin
|
69
|
+
node.select{|k,v| get_the_number_of_elements(v) >= 1}
|
70
|
+
rescue
|
71
|
+
[]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_the_number_of_elements(value)
|
76
|
+
begin
|
77
|
+
value.count
|
78
|
+
rescue
|
79
|
+
0
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module XmlHate
|
2
|
+
class Node
|
3
|
+
def initialize(hash)
|
4
|
+
hash.each { |k,v| create_accessor_for k, convert_the_value_to_the_appropriate_form(v) }
|
5
|
+
end
|
6
|
+
|
7
|
+
def method_missing(meth, *args, &blk)
|
8
|
+
an_empty_array_for_plurals_or_empty_string_for_singulars meth
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def an_empty_array_for_plurals_or_empty_string_for_singulars(meth)
|
14
|
+
meth.to_s == meth.to_s.pluralize ? [] : ""
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_accessor_for(k, v)
|
18
|
+
self.instance_variable_set("@#{k}", v)
|
19
|
+
self.instance_eval("
|
20
|
+
class << self
|
21
|
+
attr_accessor :#{k.to_sym}
|
22
|
+
end")
|
23
|
+
end
|
24
|
+
|
25
|
+
def convert_the_value_to_the_appropriate_form(value)
|
26
|
+
return Node.new(value) if value.class == Hashie::Mash
|
27
|
+
return value.map {|i| i.class == Hashie::Mash ? Node.new(i) : i} if value.class == Array
|
28
|
+
value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/xml_hate.rb
ADDED
data/readme.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# XML Hate
|
2
|
+
|
3
|
+
## Reading XML with my own ten-foot poll.
|
4
|
+
|
5
|
+
xml_hate is a small gem that describes my feelings for XML imports. I've written a billion of them, yet each time I start another I feel like I'm writing Assembler. Shouldn't it be easier? Shouldn't the code look nicer? Shouldn't this be more fun?
|
6
|
+
|
7
|
+
I've also noticed a number of things that I always tend to do. I always convert the XML to objects, I parse through the hierarchy to find child objects, I put in defensive checks for data that might-or-might-not exist, etc.
|
8
|
+
|
9
|
+
This gem is where I'm going to put these conventions and processes of mine. My goal is to take a XML document and immediately get it in the form that I need to use it.
|
10
|
+
|
11
|
+
### Example
|
12
|
+
|
13
|
+
``` xml
|
14
|
+
<root>
|
15
|
+
<directory>
|
16
|
+
<employee lastname="Galt">
|
17
|
+
<address>123 W St</address>
|
18
|
+
<address>456 S Blvd</address>
|
19
|
+
<firstname>John</firstname>
|
20
|
+
</employee>
|
21
|
+
<employee lastname="Roark" firstname="Howard">
|
22
|
+
<address>789 S</address>
|
23
|
+
</employee>
|
24
|
+
<employee lastname="Rearden" />
|
25
|
+
</directory>
|
26
|
+
</root>
|
27
|
+
```
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
document = XmlHate::Document.new(xml)
|
31
|
+
|
32
|
+
document.directory.employees.count # 3, note pluralization happened automatically
|
33
|
+
|
34
|
+
john_galt = document.directory.employees[0]
|
35
|
+
|
36
|
+
# note how I treat the single-value element and attribute the same
|
37
|
+
john_galt.lastname # Galt
|
38
|
+
john_galt.firstname # John
|
39
|
+
|
40
|
+
john_galt.addresses.count # 2, notice pluralization again
|
41
|
+
|
42
|
+
howard_roark = document.directory.employees[1]
|
43
|
+
|
44
|
+
howard_roark.firstname # Howard
|
45
|
+
howard_roark.lastname # Roark
|
46
|
+
howard_roark.addresses.count # 1
|
47
|
+
howard_roark.address # 789 S
|
48
|
+
|
49
|
+
rearden = document.directory.employees[2]
|
50
|
+
rearden.lastname # Rearden
|
51
|
+
rearden.firstname # "", defaults to empty string if the value cannot be found
|
52
|
+
rearden.whatever_i_want # "", see above
|
53
|
+
rearden.addresses.count # 0, returns [] by assuming you want the plural version
|
54
|
+
|
55
|
+
```
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,236 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe XmlHate::Document do
|
4
|
+
|
5
|
+
describe "with a simple car xml block" do
|
6
|
+
before do
|
7
|
+
xml = <<DOC
|
8
|
+
<root>
|
9
|
+
<car>a car</car>
|
10
|
+
</root>
|
11
|
+
DOC
|
12
|
+
@document = XmlHate::Document.new(xml)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return an object for car" do
|
16
|
+
@document.car.wont_be_nil
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return empty string for anything else" do
|
20
|
+
@document.blah.must_equal ""
|
21
|
+
@document.something.must_equal ""
|
22
|
+
@document.else.must_equal ""
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "with a simple truck xml block" do
|
27
|
+
before do
|
28
|
+
xml = <<DOC
|
29
|
+
<root>
|
30
|
+
<truck>a truck</truck>
|
31
|
+
</root>
|
32
|
+
DOC
|
33
|
+
@document = XmlHate::Document.new(xml)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should return an object for car" do
|
37
|
+
@document.truck.wont_be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return empty string for anything else" do
|
41
|
+
@document.car.must_equal ""
|
42
|
+
@document.blah.must_equal ""
|
43
|
+
@document.something.must_equal ""
|
44
|
+
@document.else.must_equal ""
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "with a more complex boat xml block" do
|
49
|
+
before do
|
50
|
+
xml = <<DOC
|
51
|
+
<root>
|
52
|
+
<boat name="Bulstrode" type="Cargo">
|
53
|
+
<attitude>grumpy</attitude>
|
54
|
+
<location>The ocean</location>
|
55
|
+
<episode>ep 10</episode>
|
56
|
+
<episode>ep 11</episode>
|
57
|
+
<narrator firstname="George" lastname="Carlin" />
|
58
|
+
</boat>
|
59
|
+
</root>
|
60
|
+
DOC
|
61
|
+
@document = XmlHate::Document.new(xml)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return a node object for boat" do
|
65
|
+
@document.boat.class.must_equal XmlHate::Node
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should return Bulstrode as the name" do
|
69
|
+
@document.boat.name.must_equal "Bulstrode"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return Cargo as the type" do
|
73
|
+
@document.boat.type.must_equal "Cargo"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should return attitude as grumpy" do
|
77
|
+
@document.boat.attitude.must_equal "grumpy"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return location as the ocean" do
|
81
|
+
@document.boat.locations.count.must_equal 1
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should return locations" do
|
85
|
+
@document.boat.location.must_equal "The ocean"
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should return both episodes" do
|
89
|
+
@document.boat.episode.count.must_equal 2
|
90
|
+
@document.boat.episode[0].must_equal "ep 10"
|
91
|
+
@document.boat.episode[1].must_equal "ep 11"
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should return all information about the narrator" do
|
95
|
+
@document.boat.narrator.firstname.must_equal "George"
|
96
|
+
@document.boat.narrator.lastname.must_equal "Carlin"
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should set the narrator to an empty object" do
|
100
|
+
@document.boat.narrator.class.must_equal XmlHate::Node
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "with an even more complex movie xml block" do
|
106
|
+
before do
|
107
|
+
xml = <<DOC
|
108
|
+
<root>
|
109
|
+
<movie name="Deep Impact">
|
110
|
+
<actor name="Morgan Freeman" gender="Male" />
|
111
|
+
<actor name="Tea Leoni" gender="Female" />
|
112
|
+
<actor name="Elijah Wood" gender="Male">
|
113
|
+
<movie name="Lord of the Rings 1" />
|
114
|
+
<movie name="Lord of the Rings 2">
|
115
|
+
<actor name="Sean Astin" />
|
116
|
+
<year>2004</year>
|
117
|
+
</movie>
|
118
|
+
</actor>
|
119
|
+
</movie>
|
120
|
+
</root>
|
121
|
+
DOC
|
122
|
+
@document = XmlHate::Document.new(xml)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should have a movie element" do
|
126
|
+
@document.movie.nil?.must_equal false
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should have three actors" do
|
130
|
+
@document.movie.actor.count.must_equal 3
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should be able to pull acotrs out with plural property" do
|
134
|
+
@document.movie.actors.count.must_equal 3
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should have two other movies on the third actor" do
|
138
|
+
@document.movie.actor[2].movie.count.must_equal 2
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should be able to pull the actor deep down the chain" do
|
142
|
+
@document.movie.actor[2].movie[1].actor.name.must_equal "Sean Astin"
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should be able to pull the year deep down the chain" do
|
146
|
+
@document.movie.actor[2].movie[1].year.must_equal "2004"
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should maintain years as an array deep down the list" do
|
150
|
+
@document.movie.actor[2].movie[1].years.count.must_equal 1
|
151
|
+
@document.movie.actor[2].movie[1].years[0].must_equal "2004"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
describe "another xml example" do
|
157
|
+
before do
|
158
|
+
xml = <<DOC
|
159
|
+
<root>
|
160
|
+
<product_group>
|
161
|
+
<name>A product group</name>
|
162
|
+
<listofgroup></listofgroup>
|
163
|
+
<listofgroup>
|
164
|
+
<product_group id="100"></product_group>
|
165
|
+
<product_group id="3">
|
166
|
+
<name>Another product group</name>
|
167
|
+
</product_group>
|
168
|
+
</listofgroup>
|
169
|
+
</product_group>
|
170
|
+
</root>
|
171
|
+
DOC
|
172
|
+
@document = XmlHate::Document.new(xml)
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should have data" do
|
176
|
+
@document.product_group.listofgroups[1].product_groups[1].name.must_equal "Another product group"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "another xml example with plurals after the root" do
|
181
|
+
before do
|
182
|
+
xml = <<DOC
|
183
|
+
<root>
|
184
|
+
<product_group />
|
185
|
+
<product_group>
|
186
|
+
<name>A product group</name>
|
187
|
+
<listofgroup></listofgroup>
|
188
|
+
<listofgroup>
|
189
|
+
<product_group id="100"></product_group>
|
190
|
+
<product_group id="3">
|
191
|
+
<name>Another product group</name>
|
192
|
+
</product_group>
|
193
|
+
</listofgroup>
|
194
|
+
</product_group>
|
195
|
+
</root>
|
196
|
+
DOC
|
197
|
+
@document = XmlHate::Document.new(xml)
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should have data" do
|
201
|
+
@document.product_group[1].listofgroups[1].product_groups[1].name.must_equal "Another product group"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "an example from the readme file" do
|
206
|
+
before do
|
207
|
+
xml = <<DOC
|
208
|
+
<root>
|
209
|
+
<directory>
|
210
|
+
<employee lastname="Galt">
|
211
|
+
<address>123 W St</address>
|
212
|
+
<address>456 S Blvd</address>
|
213
|
+
<firstname>John</firstname>
|
214
|
+
</employee>
|
215
|
+
<employee lastname="Roark" firstname="Howard">
|
216
|
+
<address>789 S</address>
|
217
|
+
</employee>
|
218
|
+
<employee lastname="Rearden" />
|
219
|
+
</directory>
|
220
|
+
</root>
|
221
|
+
DOC
|
222
|
+
@document = XmlHate::Document.new xml
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should return directory as a Node" do
|
226
|
+
@document.directory.class.must_equal XmlHate::Node
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should return the employees as Nodes" do
|
230
|
+
@document.directory.employees.each do |e|
|
231
|
+
e.class.must_equal XmlHate::Node
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe XmlHate::Node do
|
4
|
+
describe "creating a node with a simple node" do
|
5
|
+
before do
|
6
|
+
@object = XmlHate::Node.new({:firstname => "John", :lastname => "Carter" })
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should respond to first name" do
|
10
|
+
@object.respond_to?(:firstname).must_equal true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should respond to last name" do
|
14
|
+
@object.respond_to?(:lastname).must_equal true
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should not respond to other things" do
|
18
|
+
@object.respond_to?(:something).must_equal false
|
19
|
+
@object.respond_to?(:else).must_equal false
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return the first name" do
|
23
|
+
@object.firstname.must_equal "John"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return the last name" do
|
27
|
+
@object.lastname.must_equal "Carter"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return an empty string for a singular name" do
|
31
|
+
@object.cat.must_equal ""
|
32
|
+
@object.dog.must_equal ""
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should return an empty array for plural names" do
|
36
|
+
@object.cats.must_equal []
|
37
|
+
@object.dogs.must_equal []
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "creating a node with a child Hashie::Match" do
|
42
|
+
before do
|
43
|
+
@object = XmlHate::Node.new({:thing => Hashie::Mash.new({:firstname => "John", :lastname => "Carter" })})
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return a node object for thing" do
|
47
|
+
@object.thing.class.must_equal XmlHate::Node
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "creating a node with an Array" do
|
53
|
+
before do
|
54
|
+
@object = XmlHate::Node.new({:thing => [Hashie::Mash.new(), "test"]})
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return a node object for the first item" do
|
58
|
+
@object.thing[0].class.must_equal XmlHate::Node
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should return a string for the second item" do
|
62
|
+
@object.thing[1].class.must_equal String
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "creating a node will create attributes for single instances of node" do
|
67
|
+
before do
|
68
|
+
@object1 = XmlHate::Node.new({:first_name => "Tyrone", :last_name => "Groves"})
|
69
|
+
@object2 = XmlHate::Node.new({:customer_id => 23})
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should not respond to first name" do
|
73
|
+
@object2.respond_to?(:first_name).must_equal false
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should not respond to last name" do
|
77
|
+
@object2.respond_to?(:last_name).must_equal false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/xml_hate.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "xml_hate/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "xml_hate"
|
7
|
+
s.version = XmlHate::VERSION
|
8
|
+
s.authors = ["Darren Cauthon"]
|
9
|
+
s.email = ["darren@cauthon.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Handling xml with my own ten-foot poll.}
|
12
|
+
s.description = %q{I hate xml.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "xml_hate"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_runtime_dependency 'xml-simple'
|
23
|
+
s.add_runtime_dependency 'hashie'
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xml_hate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.8.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Darren Cauthon
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: xml-simple
|
16
|
+
requirement: &70214612517320 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70214612517320
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hashie
|
27
|
+
requirement: &70214612533220 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70214612533220
|
36
|
+
description: I hate xml.
|
37
|
+
email:
|
38
|
+
- darren@cauthon.com
|
39
|
+
executables: []
|
40
|
+
extensions: []
|
41
|
+
extra_rdoc_files: []
|
42
|
+
files:
|
43
|
+
- .gitignore
|
44
|
+
- .rvmrc
|
45
|
+
- Gemfile
|
46
|
+
- Guardfile
|
47
|
+
- Rakefile
|
48
|
+
- lib/xml_hate.rb
|
49
|
+
- lib/xml_hate/document.rb
|
50
|
+
- lib/xml_hate/node.rb
|
51
|
+
- lib/xml_hate/version.rb
|
52
|
+
- readme.md
|
53
|
+
- spec/spec_helper.rb
|
54
|
+
- spec/xml_hate/document_spec.rb
|
55
|
+
- spec/xml_hate/node_spec.rb
|
56
|
+
- xml_hate.gemspec
|
57
|
+
homepage: ''
|
58
|
+
licenses: []
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project: xml_hate
|
77
|
+
rubygems_version: 1.8.10
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: Handling xml with my own ten-foot poll.
|
81
|
+
test_files:
|
82
|
+
- spec/spec_helper.rb
|
83
|
+
- spec/xml_hate/document_spec.rb
|
84
|
+
- spec/xml_hate/node_spec.rb
|