happymapper 0.1.7 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History +6 -0
- data/Manifest +5 -1
- data/examples/amazon.rb +1 -1
- data/examples/current_weather.rb +4 -4
- data/examples/dashed_elements.rb +3 -6
- data/happymapper.gemspec +3 -3
- data/lib/happymapper/item.rb +29 -18
- data/lib/happymapper/version.rb +1 -1
- data/lib/happymapper.rb +50 -70
- data/lib/libxml_ext/libxml_helper.rb +1 -37
- data/spec/fixtures/family_tree.xml +7 -0
- data/spec/fixtures/multiple_namespaces.xml +170 -0
- data/spec/fixtures/product_default_namespace.xml +10 -0
- data/spec/fixtures/product_no_namespace.xml +10 -0
- data/spec/fixtures/product_single_namespace.xml +10 -0
- data/spec/happymapper_item_spec.rb +43 -22
- data/spec/happymapper_spec.rb +290 -132
- data/spec/spec_helper.rb +4 -0
- metadata +8 -3
data/History
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
== 0.2.0
|
2
|
+
* 1 major enhancement, 2 minor ehancements
|
3
|
+
* Automatic handling of namespaces (part by Robert Lowrey and rest by John Nunemaker)
|
4
|
+
* Added :root option to tag method. This allows setting an object as the root element, which sets xpath to use / and sets single to true
|
5
|
+
* Now defaulting tag names for classes in modules to last constant downcased
|
6
|
+
|
1
7
|
== 0.1.7 2009-01-29
|
2
8
|
* 1 minor enhancement
|
3
9
|
* Support dashes in elements (Josh Nichols)
|
data/Manifest
CHANGED
@@ -3,7 +3,6 @@ examples/current_weather.rb
|
|
3
3
|
examples/dashed_elements.rb
|
4
4
|
examples/post.rb
|
5
5
|
examples/twitter.rb
|
6
|
-
happymapper.gemspec
|
7
6
|
History
|
8
7
|
lib/happymapper/attribute.rb
|
9
8
|
lib/happymapper/element.rb
|
@@ -18,8 +17,13 @@ README
|
|
18
17
|
spec/fixtures/address.xml
|
19
18
|
spec/fixtures/commit.xml
|
20
19
|
spec/fixtures/current_weather.xml
|
20
|
+
spec/fixtures/family_tree.xml
|
21
|
+
spec/fixtures/multiple_namespaces.xml
|
21
22
|
spec/fixtures/pita.xml
|
22
23
|
spec/fixtures/posts.xml
|
24
|
+
spec/fixtures/product_default_namespace.xml
|
25
|
+
spec/fixtures/product_no_namespace.xml
|
26
|
+
spec/fixtures/product_single_namespace.xml
|
23
27
|
spec/fixtures/radar.xml
|
24
28
|
spec/fixtures/statuses.xml
|
25
29
|
spec/happymapper_attribute_spec.rb
|
data/examples/amazon.rb
CHANGED
@@ -23,7 +23,7 @@ module PITA
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
item = PITA::Items.parse(file_contents, :single => true
|
26
|
+
item = PITA::Items.parse(file_contents, :single => true)
|
27
27
|
item.items.each do |i|
|
28
28
|
puts i.asin, i.detail_page_url, i.manufacturer, ''
|
29
29
|
end
|
data/examples/current_weather.rb
CHANGED
@@ -5,10 +5,10 @@ file_contents = File.read(dir + '/../spec/fixtures/current_weather.xml')
|
|
5
5
|
|
6
6
|
class CurrentWeather
|
7
7
|
include HappyMapper
|
8
|
-
tag '
|
9
|
-
element :temperature, Integer, :tag => '
|
10
|
-
element :feels_like, Integer, :tag => '
|
11
|
-
element :current_condition, String, :tag => '
|
8
|
+
tag 'ob'
|
9
|
+
element :temperature, Integer, :tag => 'temp'
|
10
|
+
element :feels_like, Integer, :tag => 'feels-like'
|
11
|
+
element :current_condition, String, :tag => 'current-condition', :attributes => {:icon => String}
|
12
12
|
end
|
13
13
|
|
14
14
|
CurrentWeather.parse(file_contents).each do |current_weather|
|
data/examples/dashed_elements.rb
CHANGED
@@ -7,8 +7,7 @@ module GitHub
|
|
7
7
|
class Commit
|
8
8
|
include HappyMapper
|
9
9
|
|
10
|
-
tag "commit"
|
11
|
-
|
10
|
+
tag "commit", :root => true
|
12
11
|
element :url, String
|
13
12
|
element :tree, String
|
14
13
|
element :message, String
|
@@ -17,7 +16,5 @@ module GitHub
|
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
puts commit.committed_date, commit.url, commit.id
|
23
|
-
end
|
19
|
+
commit = GitHub::Commit.parse(file_contents)
|
20
|
+
puts commit.committed_date, commit.url, commit.id
|
data/happymapper.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{happymapper}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.2.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["John Nunemaker"]
|
9
|
-
s.date = %q{2009-01-
|
9
|
+
s.date = %q{2009-01-29}
|
10
10
|
s.description = %q{object to xml mapping library}
|
11
11
|
s.email = %q{nunemaker@gmail.com}
|
12
12
|
s.extra_rdoc_files = ["lib/happymapper/attribute.rb", "lib/happymapper/element.rb", "lib/happymapper/item.rb", "lib/happymapper/version.rb", "lib/happymapper.rb", "lib/libxml_ext/libxml_helper.rb", "README", "TODO"]
|
13
|
-
s.files = ["examples/amazon.rb", "examples/current_weather.rb", "examples/dashed_elements.rb", "examples/post.rb", "examples/twitter.rb", "
|
13
|
+
s.files = ["examples/amazon.rb", "examples/current_weather.rb", "examples/dashed_elements.rb", "examples/post.rb", "examples/twitter.rb", "History", "lib/happymapper/attribute.rb", "lib/happymapper/element.rb", "lib/happymapper/item.rb", "lib/happymapper/version.rb", "lib/happymapper.rb", "lib/libxml_ext/libxml_helper.rb", "License", "Manifest", "Rakefile", "README", "spec/fixtures/address.xml", "spec/fixtures/commit.xml", "spec/fixtures/current_weather.xml", "spec/fixtures/family_tree.xml", "spec/fixtures/multiple_namespaces.xml", "spec/fixtures/pita.xml", "spec/fixtures/posts.xml", "spec/fixtures/product_default_namespace.xml", "spec/fixtures/product_no_namespace.xml", "spec/fixtures/product_single_namespace.xml", "spec/fixtures/radar.xml", "spec/fixtures/statuses.xml", "spec/happymapper_attribute_spec.rb", "spec/happymapper_element_spec.rb", "spec/happymapper_item_spec.rb", "spec/happymapper_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "TODO", "website/css/common.css", "website/index.html", "happymapper.gemspec"]
|
14
14
|
s.has_rdoc = true
|
15
15
|
s.homepage = %q{http://happymapper.rubyforge.org}
|
16
16
|
s.post_install_message = %q{May you have many happy mappings!}
|
data/lib/happymapper/item.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
module HappyMapper
|
2
2
|
class Item
|
3
|
-
attr_accessor :type, :tag, :options
|
4
|
-
attr_reader :name
|
3
|
+
attr_accessor :name, :type, :tag, :options, :namespace
|
5
4
|
|
6
5
|
Types = [String, Float, Time, Date, DateTime, Integer, Boolean]
|
7
6
|
|
@@ -10,26 +9,36 @@ module HappyMapper
|
|
10
9
|
# grandchildren and all others down the chain (// in expath)
|
11
10
|
# :single => Boolean False if object should be collection, True for single object
|
12
11
|
def initialize(name, type, o={})
|
13
|
-
self.name
|
14
|
-
self.
|
12
|
+
self.name = name.to_s
|
13
|
+
self.type = type
|
14
|
+
self.tag = o.delete(:tag) || name.to_s
|
15
|
+
self.options = {
|
16
|
+
:single => false,
|
17
|
+
:deep => false,
|
18
|
+
}.merge(o)
|
19
|
+
|
15
20
|
@xml_type = self.class.to_s.split('::').last.downcase
|
16
21
|
end
|
17
|
-
|
18
|
-
def name=(new_name)
|
19
|
-
@name = new_name.to_s
|
20
|
-
end
|
21
22
|
|
22
|
-
def from_xml_node(node
|
23
|
+
def from_xml_node(node)
|
23
24
|
if primitive?
|
24
|
-
value_from_xml_node(node
|
25
|
+
value_from_xml_node(node) do |value_before_type_cast|
|
25
26
|
typecast(value_before_type_cast)
|
26
27
|
end
|
27
28
|
else
|
28
|
-
|
29
|
-
type.parse(node, options.merge(:use_default_namespace => use_default_namespace))
|
29
|
+
type.parse(node, options)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
def xpath
|
34
|
+
xpath = ''
|
35
|
+
xpath += './/' if options[:deep]
|
36
|
+
xpath += namespace if namespace
|
37
|
+
xpath += tag
|
38
|
+
# puts "xpath: #{xpath}"
|
39
|
+
xpath
|
40
|
+
end
|
41
|
+
|
33
42
|
def primitive?
|
34
43
|
Types.include?(type)
|
35
44
|
end
|
@@ -42,6 +51,10 @@ module HappyMapper
|
|
42
51
|
!element?
|
43
52
|
end
|
44
53
|
|
54
|
+
def method_name
|
55
|
+
@method_name ||= name.tr('-', '_')
|
56
|
+
end
|
57
|
+
|
45
58
|
def typecast(value)
|
46
59
|
return value if value.kind_of?(type) || value.nil?
|
47
60
|
begin
|
@@ -72,13 +85,11 @@ module HappyMapper
|
|
72
85
|
end
|
73
86
|
end
|
74
87
|
|
75
|
-
private
|
76
|
-
def value_from_xml_node(node
|
77
|
-
node.register_default_namespace(namespace.chop) if namespace
|
78
|
-
|
88
|
+
private
|
89
|
+
def value_from_xml_node(node)
|
79
90
|
if element?
|
80
|
-
|
81
|
-
|
91
|
+
result = node.find_first(xpath)
|
92
|
+
# puts "vfxn: #{xpath} #{result.inspect}"
|
82
93
|
if result
|
83
94
|
value = yield(result.content)
|
84
95
|
if options[:attributes].is_a?(Hash)
|
data/lib/happymapper/version.rb
CHANGED
data/lib/happymapper.rb
CHANGED
@@ -25,7 +25,7 @@ module HappyMapper
|
|
25
25
|
attribute = Attribute.new(name, type, options)
|
26
26
|
@attributes[to_s] ||= []
|
27
27
|
@attributes[to_s] << attribute
|
28
|
-
|
28
|
+
attr_accessor attribute.method_name.intern
|
29
29
|
end
|
30
30
|
|
31
31
|
def attributes
|
@@ -36,7 +36,7 @@ module HappyMapper
|
|
36
36
|
element = Element.new(name, type, options)
|
37
37
|
@elements[to_s] ||= []
|
38
38
|
@elements[to_s] << element
|
39
|
-
|
39
|
+
attr_accessor element.method_name.intern
|
40
40
|
end
|
41
41
|
|
42
42
|
def elements
|
@@ -51,90 +51,70 @@ module HappyMapper
|
|
51
51
|
element name, type, {:single => false}.merge(options)
|
52
52
|
end
|
53
53
|
|
54
|
-
|
54
|
+
# Options:
|
55
|
+
# :root => Boolean, true means this is xml root
|
56
|
+
def tag(new_tag_name, o={})
|
57
|
+
options = {:root => false}.merge(o)
|
58
|
+
@root = options.delete(:root)
|
55
59
|
@tag_name = new_tag_name.to_s
|
56
60
|
end
|
57
61
|
|
58
62
|
def get_tag_name
|
59
|
-
@tag_name ||=
|
63
|
+
@tag_name ||= begin
|
64
|
+
to_s.split('::')[-1].downcase
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def is_root?
|
69
|
+
@root
|
60
70
|
end
|
61
71
|
|
62
|
-
def parse(xml, o={})
|
63
|
-
options = {
|
64
|
-
|
65
|
-
|
66
|
-
}.merge(o)
|
72
|
+
def parse(xml, o={})
|
73
|
+
xpath, collection, options = '', [], {:single => false}.merge(o)
|
74
|
+
doc = xml.is_a?(LibXML::XML::Node) ? xml : xml.to_libxml_doc
|
75
|
+
node = doc.respond_to?(:root) ? doc.root : doc
|
67
76
|
|
68
|
-
|
69
|
-
doc = xml.is_a?(LibXML::XML::Node) ? xml : xml.to_libxml_doc
|
77
|
+
# puts doc.inspect, doc.respond_to?(:root) ? doc.root.inspect : ''
|
70
78
|
|
71
|
-
|
72
|
-
|
73
|
-
node.
|
74
|
-
|
75
|
-
else
|
76
|
-
doc.find("//#{get_tag_name}")
|
79
|
+
unless node.namespaces.default.nil?
|
80
|
+
namespace = "default_ns:"
|
81
|
+
node.namespaces.default_prefix = namespace.chop
|
82
|
+
# warn "Default XML namespace present -- results are unpredictable"
|
77
83
|
end
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
node.register_default_namespace(namespace.chop)
|
82
|
-
node.find("#{namespace}#{get_tag_name}")
|
83
|
-
else
|
84
|
-
nested = '.' unless doc.respond_to?(:root)
|
85
|
-
path = "#{nested}//#{get_tag_name}"
|
86
|
-
doc.find(path)
|
84
|
+
|
85
|
+
if node.namespaces.to_a.size > 0 && namespace.nil? && !node.namespaces.namespace.nil?
|
86
|
+
namespace = node.namespaces.namespace.prefix + ":"
|
87
87
|
end
|
88
|
-
|
89
|
-
collection = create_collection(nodes, namespace)
|
90
88
|
|
91
|
-
#
|
92
|
-
|
93
|
-
|
89
|
+
# xpath += doc.respond_to?(:root) ? '' : '.'
|
90
|
+
xpath += is_root? ? '/' : './/'
|
91
|
+
xpath += namespace if namespace
|
92
|
+
xpath += get_tag_name
|
93
|
+
# puts "parse: #{xpath}"
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
attributes.each { |attr| obj.send("#{normalize_name attr.name}=", attr.from_xml_node(el)) }
|
103
|
-
elements.each { |elem| obj.send("#{normalize_name elem.name}=", elem.from_xml_node(el, namespace)) }
|
104
|
-
acc << obj
|
95
|
+
nodes = node.find(xpath)
|
96
|
+
nodes.each do |n|
|
97
|
+
obj = new
|
98
|
+
|
99
|
+
attributes.each do |attr|
|
100
|
+
obj.send("#{attr.method_name}=",
|
101
|
+
attr.from_xml_node(n))
|
105
102
|
end
|
103
|
+
|
104
|
+
elements.each do |elem|
|
105
|
+
elem.namespace = namespace
|
106
|
+
obj.send("#{elem.method_name}=",
|
107
|
+
elem.from_xml_node(n))
|
108
|
+
end
|
109
|
+
collection << obj
|
106
110
|
end
|
107
|
-
|
108
|
-
def create_getter(name)
|
109
|
-
name = normalize_name(name)
|
110
|
-
|
111
|
-
class_eval <<-EOS, __FILE__, __LINE__
|
112
|
-
def #{name}
|
113
|
-
@#{name}
|
114
|
-
end
|
115
|
-
EOS
|
116
|
-
end
|
117
|
-
|
118
|
-
def create_setter(name)
|
119
|
-
name = normalize_name(name)
|
120
|
-
|
121
|
-
class_eval <<-EOS, __FILE__, __LINE__
|
122
|
-
def #{name}=(value)
|
123
|
-
@#{name} = value
|
124
|
-
end
|
125
|
-
EOS
|
126
|
-
end
|
127
|
-
|
128
|
-
def create_accessor(name)
|
129
|
-
name = normalize_name(name)
|
130
111
|
|
131
|
-
|
132
|
-
|
133
|
-
|
112
|
+
# per http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354
|
113
|
+
nodes = nil
|
114
|
+
GC.start
|
134
115
|
|
135
|
-
|
136
|
-
|
137
|
-
end
|
116
|
+
options[:single] || is_root? ? collection.first : collection
|
117
|
+
end
|
138
118
|
end
|
139
119
|
end
|
140
120
|
|
@@ -5,12 +5,7 @@ class XML::Node
|
|
5
5
|
# Open up XML::Node from libxml and add convenience methods inspired
|
6
6
|
# by hpricot.
|
7
7
|
# (http://code.whytheluckystiff.net/hpricot/wiki/HpricotBasics)
|
8
|
-
|
9
|
-
# * provide better handling of default namespaces
|
10
|
-
|
11
|
-
# an array of default namespaces to past into
|
12
|
-
attr_accessor :default_namespaces
|
13
|
-
|
8
|
+
|
14
9
|
# find the child node with the given xpath
|
15
10
|
def at(xpath)
|
16
11
|
self.find_first(xpath)
|
@@ -51,37 +46,6 @@ class XML::Node
|
|
51
46
|
def xpath
|
52
47
|
self.path
|
53
48
|
end
|
54
|
-
|
55
|
-
# provide a name for the default namespace
|
56
|
-
def register_default_namespace(name)
|
57
|
-
default_namespace = namespaces.default
|
58
|
-
|
59
|
-
if default_namespace
|
60
|
-
register_namespace("#{name}:#{default_namespace.href}")
|
61
|
-
else
|
62
|
-
raise "No default namespace found"
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# register a namespace, of the form "foo:http://example.com/ns"
|
67
|
-
def register_namespace(name_and_href)
|
68
|
-
(@default_namespaces ||= []) << name_and_href
|
69
|
-
end
|
70
|
-
|
71
|
-
def find_with_default_ns(xpath_expr, namespace=nil)
|
72
|
-
find_base(xpath_expr, namespace || default_namespaces)
|
73
|
-
end
|
74
|
-
|
75
|
-
def find_first_with_default_ns(xpath_expr, namespace=nil)
|
76
|
-
find_first_base(xpath_expr, namespace || default_namespaces)
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
alias_method :find_base, :find unless method_defined?(:find_base)
|
81
|
-
alias_method :find, :find_with_default_ns
|
82
|
-
|
83
|
-
alias_method :find_first_base, :find_first unless method_defined?(:find_first_base)
|
84
|
-
alias_method :find_first, :find_first_with_default_ns
|
85
49
|
end
|
86
50
|
|
87
51
|
class String
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<familytree xmlns="http://api.familysearch.org/familytree/v1" xmlns:fsapi-v1="http://api.familysearch.org/v1" version="1.0.20071213.942" statusMessage="OK" statusCode="200">
|
3
|
+
<persons>
|
4
|
+
<person version="1199378491000" modified="2008-01-03T09:41:31-07:00" id="KWQS-BBQ">
|
5
|
+
</person>
|
6
|
+
</persons>
|
7
|
+
</familytree>
|
@@ -0,0 +1,170 @@
|
|
1
|
+
<?xml version='1.0' encoding='UTF-8'?>
|
2
|
+
<v2:TrackReply xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:v2='http://fedex.com/ws/track/v2'>
|
3
|
+
<v2:HighestSeverity>SUCCESS</v2:HighestSeverity>
|
4
|
+
<v2:Notifications>
|
5
|
+
<v2:Severity>SUCCESS</v2:Severity>
|
6
|
+
<v2:Source>trck</v2:Source>
|
7
|
+
<v2:Code>0</v2:Code>
|
8
|
+
<v2:Message>Request was successfully processed.</v2:Message>
|
9
|
+
<v2:LocalizedMessage>Request was successfully processed.</v2:LocalizedMessage>
|
10
|
+
</v2:Notifications>
|
11
|
+
<ns:TransactionDetail xmlns:ns='http://fedex.com/ws/track/v2'>
|
12
|
+
<ns:CustomerTransactionId>20090102-111321</ns:CustomerTransactionId>
|
13
|
+
</ns:TransactionDetail>
|
14
|
+
<ns:Version xmlns:ns='http://fedex.com/ws/track/v2'>
|
15
|
+
<ns:ServiceId>trck</ns:ServiceId>
|
16
|
+
<ns:Major>2</ns:Major>
|
17
|
+
<ns:Intermediate>0</ns:Intermediate>
|
18
|
+
<ns:Minor>0</ns:Minor>
|
19
|
+
</ns:Version>
|
20
|
+
<v2:DuplicateWaybill>false</v2:DuplicateWaybill>
|
21
|
+
<v2:MoreData>false</v2:MoreData>
|
22
|
+
<v2:TrackDetails>
|
23
|
+
<v2:TrackingNumber>9611018034267800045212</v2:TrackingNumber>
|
24
|
+
<v2:TrackingNumberUniqueIdentifier>120081227094248461000~034267800045212</v2:TrackingNumberUniqueIdentifier>
|
25
|
+
<v2:StatusCode>OD</v2:StatusCode>
|
26
|
+
<v2:StatusDescription>On FedEx vehicle for delivery</v2:StatusDescription>
|
27
|
+
<v2:CarrierCode>FDXG</v2:CarrierCode>
|
28
|
+
<v2:ServiceInfo>Ground-Package Returns Program-Domestic</v2:ServiceInfo>
|
29
|
+
<v2:PackageWeight>
|
30
|
+
<v2:Units>LB</v2:Units>
|
31
|
+
<v2:Value>2.6</v2:Value>
|
32
|
+
</v2:PackageWeight>
|
33
|
+
<v2:Packaging>Package</v2:Packaging>
|
34
|
+
<v2:PackageSequenceNumber>1</v2:PackageSequenceNumber>
|
35
|
+
<v2:PackageCount>1</v2:PackageCount>
|
36
|
+
<v2:OriginLocationAddress>
|
37
|
+
<v2:City>SANFORD</v2:City>
|
38
|
+
<v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
|
39
|
+
<v2:CountryCode>US</v2:CountryCode>
|
40
|
+
<v2:Residential>false</v2:Residential>
|
41
|
+
</v2:OriginLocationAddress>
|
42
|
+
<v2:ShipTimestamp>2008-12-29T00:00:00</v2:ShipTimestamp>
|
43
|
+
<v2:EstimatedDeliveryTimestamp>2009-01-02T00:00:00</v2:EstimatedDeliveryTimestamp>
|
44
|
+
<v2:SignatureProofOfDeliveryAvailable>false</v2:SignatureProofOfDeliveryAvailable>
|
45
|
+
<v2:ProofOfDeliveryNotificationsAvailable>true</v2:ProofOfDeliveryNotificationsAvailable>
|
46
|
+
<v2:ExceptionNotificationsAvailable>true</v2:ExceptionNotificationsAvailable>
|
47
|
+
<v2:Events>
|
48
|
+
<v2:Timestamp>2009-01-02T06:00:00</v2:Timestamp>
|
49
|
+
<v2:EventType>OD</v2:EventType>
|
50
|
+
<v2:EventDescription>On FedEx vehicle for delivery</v2:EventDescription>
|
51
|
+
<v2:Address>
|
52
|
+
<v2:City>WICHITA</v2:City>
|
53
|
+
<v2:StateOrProvinceCode>KS</v2:StateOrProvinceCode>
|
54
|
+
<v2:PostalCode>67226</v2:PostalCode>
|
55
|
+
<v2:CountryCode>US</v2:CountryCode>
|
56
|
+
<v2:Residential>false</v2:Residential>
|
57
|
+
</v2:Address>
|
58
|
+
</v2:Events>
|
59
|
+
<v2:Events>
|
60
|
+
<v2:Timestamp>2009-01-02T01:17:32</v2:Timestamp>
|
61
|
+
<v2:EventType>AR</v2:EventType>
|
62
|
+
<v2:EventDescription>At local FedEx facility</v2:EventDescription>
|
63
|
+
<v2:Address>
|
64
|
+
<v2:City>WICHITA</v2:City>
|
65
|
+
<v2:StateOrProvinceCode>KS</v2:StateOrProvinceCode>
|
66
|
+
<v2:PostalCode>67226</v2:PostalCode>
|
67
|
+
<v2:CountryCode>US</v2:CountryCode>
|
68
|
+
<v2:Residential>false</v2:Residential>
|
69
|
+
</v2:Address>
|
70
|
+
</v2:Events>
|
71
|
+
<v2:Events>
|
72
|
+
<v2:Timestamp>2009-01-01T21:49:49</v2:Timestamp>
|
73
|
+
<v2:EventType>DP</v2:EventType>
|
74
|
+
<v2:EventDescription>Departed FedEx location</v2:EventDescription>
|
75
|
+
<v2:Address>
|
76
|
+
<v2:City>LENEXA</v2:City>
|
77
|
+
<v2:StateOrProvinceCode>KS</v2:StateOrProvinceCode>
|
78
|
+
<v2:PostalCode>66227</v2:PostalCode>
|
79
|
+
<v2:CountryCode>US</v2:CountryCode>
|
80
|
+
<v2:Residential>false</v2:Residential>
|
81
|
+
</v2:Address>
|
82
|
+
</v2:Events>
|
83
|
+
<v2:Events>
|
84
|
+
<v2:Timestamp>2008-12-31T16:19:00</v2:Timestamp>
|
85
|
+
<v2:EventType>AR</v2:EventType>
|
86
|
+
<v2:EventDescription>Arrived at FedEx location</v2:EventDescription>
|
87
|
+
<v2:Address>
|
88
|
+
<v2:City>LENEXA</v2:City>
|
89
|
+
<v2:StateOrProvinceCode>KS</v2:StateOrProvinceCode>
|
90
|
+
<v2:PostalCode>66227</v2:PostalCode>
|
91
|
+
<v2:CountryCode>US</v2:CountryCode>
|
92
|
+
<v2:Residential>false</v2:Residential>
|
93
|
+
</v2:Address>
|
94
|
+
</v2:Events>
|
95
|
+
<v2:Events>
|
96
|
+
<v2:Timestamp>2008-12-30T11:01:23</v2:Timestamp>
|
97
|
+
<v2:EventType>DP</v2:EventType>
|
98
|
+
<v2:EventDescription>Departed FedEx location</v2:EventDescription>
|
99
|
+
<v2:Address>
|
100
|
+
<v2:City>ORLANDO</v2:City>
|
101
|
+
<v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
|
102
|
+
<v2:PostalCode>32809</v2:PostalCode>
|
103
|
+
<v2:CountryCode>US</v2:CountryCode>
|
104
|
+
<v2:Residential>false</v2:Residential>
|
105
|
+
</v2:Address>
|
106
|
+
</v2:Events>
|
107
|
+
<v2:Events>
|
108
|
+
<v2:Timestamp>2008-12-30T05:00:00</v2:Timestamp>
|
109
|
+
<v2:EventType>AR</v2:EventType>
|
110
|
+
<v2:EventDescription>Arrived at FedEx location</v2:EventDescription>
|
111
|
+
<v2:Address>
|
112
|
+
<v2:City>ORLANDO</v2:City>
|
113
|
+
<v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
|
114
|
+
<v2:PostalCode>32809</v2:PostalCode>
|
115
|
+
<v2:CountryCode>US</v2:CountryCode>
|
116
|
+
<v2:Residential>false</v2:Residential>
|
117
|
+
</v2:Address>
|
118
|
+
</v2:Events>
|
119
|
+
<v2:Events>
|
120
|
+
<v2:Timestamp>2008-12-30T03:16:33</v2:Timestamp>
|
121
|
+
<v2:EventType>DP</v2:EventType>
|
122
|
+
<v2:EventDescription>Left FedEx origin facility</v2:EventDescription>
|
123
|
+
<v2:Address>
|
124
|
+
<v2:City>SANFORD</v2:City>
|
125
|
+
<v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
|
126
|
+
<v2:PostalCode>32771</v2:PostalCode>
|
127
|
+
<v2:CountryCode>US</v2:CountryCode>
|
128
|
+
<v2:Residential>false</v2:Residential>
|
129
|
+
</v2:Address>
|
130
|
+
</v2:Events>
|
131
|
+
<v2:Events>
|
132
|
+
<v2:Timestamp>2008-12-29T22:46:00</v2:Timestamp>
|
133
|
+
<v2:EventType>AR</v2:EventType>
|
134
|
+
<v2:EventDescription>Arrived at FedEx location</v2:EventDescription>
|
135
|
+
<v2:Address>
|
136
|
+
<v2:City>SANFORD</v2:City>
|
137
|
+
<v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
|
138
|
+
<v2:PostalCode>32771</v2:PostalCode>
|
139
|
+
<v2:CountryCode>US</v2:CountryCode>
|
140
|
+
<v2:Residential>false</v2:Residential>
|
141
|
+
</v2:Address>
|
142
|
+
</v2:Events>
|
143
|
+
<v2:Events>
|
144
|
+
<v2:Timestamp>2008-12-29T17:12:00</v2:Timestamp>
|
145
|
+
<v2:EventType>PU</v2:EventType>
|
146
|
+
<v2:EventDescription>Picked up</v2:EventDescription>
|
147
|
+
<v2:Address>
|
148
|
+
<v2:City>SANFORD</v2:City>
|
149
|
+
<v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
|
150
|
+
<v2:PostalCode>32771</v2:PostalCode>
|
151
|
+
<v2:CountryCode>US</v2:CountryCode>
|
152
|
+
<v2:Residential>false</v2:Residential>
|
153
|
+
</v2:Address>
|
154
|
+
</v2:Events>
|
155
|
+
<v2:Events>
|
156
|
+
<v2:Timestamp>2008-12-27T09:40:00</v2:Timestamp>
|
157
|
+
<v2:EventType>IP</v2:EventType>
|
158
|
+
<v2:EventDescription>In FedEx possession</v2:EventDescription>
|
159
|
+
<v2:StatusExceptionCode>084</v2:StatusExceptionCode>
|
160
|
+
<v2:StatusExceptionDescription>Tendered at FedEx location</v2:StatusExceptionDescription>
|
161
|
+
<v2:Address>
|
162
|
+
<v2:City>LONGWOOD</v2:City>
|
163
|
+
<v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
|
164
|
+
<v2:PostalCode>327506398</v2:PostalCode>
|
165
|
+
<v2:CountryCode>US</v2:CountryCode>
|
166
|
+
<v2:Residential>false</v2:Residential>
|
167
|
+
</v2:Address>
|
168
|
+
</v2:Events>
|
169
|
+
</v2:TrackDetails>
|
170
|
+
</v2:TrackReply>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<products xmlns:juju="http://bigco.com">
|
2
|
+
<product>
|
3
|
+
<title>A Title</title>
|
4
|
+
<features_bullets>
|
5
|
+
<feature>This is feature text 1</feature>
|
6
|
+
<feature>This is feature text 2</feature>
|
7
|
+
<bug>This is a bug</bug>
|
8
|
+
</features_bullets>
|
9
|
+
</product>
|
10
|
+
</products>
|
@@ -4,70 +4,91 @@ describe HappyMapper::Item do
|
|
4
4
|
|
5
5
|
describe "new instance" do
|
6
6
|
before do
|
7
|
-
@
|
7
|
+
@item = HappyMapper::Item.new(:foo, String, :tag => 'foobar')
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should accept a name" do
|
11
|
-
@
|
11
|
+
@item.name.should == 'foo'
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'should accept a type' do
|
15
|
-
@
|
15
|
+
@item.type.should == String
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'should accept :tag as an option' do
|
19
|
-
@
|
19
|
+
@item.tag.should == 'foobar'
|
20
20
|
end
|
21
21
|
|
22
|
-
it
|
23
|
-
@
|
22
|
+
it "should have a method_name" do
|
23
|
+
@item.method_name.should == 'foo'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#method_name" do
|
28
|
+
it "should convert dashes to underscores" do
|
29
|
+
item = HappyMapper::Item.new(:'foo-bar', String, :tag => 'foobar')
|
30
|
+
item.method_name.should == 'foo_bar'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#xpath" do
|
35
|
+
it "should default to tag" do
|
36
|
+
item = HappyMapper::Item.new(:foo, String, :tag => 'foobar')
|
37
|
+
item.xpath.should == 'foobar'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should prepend with .// if options[:deep] true" do
|
41
|
+
item = HappyMapper::Item.new(:foo, String, :tag => 'foobar', :deep => true)
|
42
|
+
item.xpath.should == './/foobar'
|
24
43
|
end
|
25
44
|
|
26
|
-
it
|
27
|
-
|
45
|
+
it "should prepend namespace if namespace exists" do
|
46
|
+
item = HappyMapper::Item.new(:foo, String, :tag => 'foobar')
|
47
|
+
item.namespace = 'v2:'
|
48
|
+
item.xpath.should == 'v2:foobar'
|
28
49
|
end
|
29
50
|
end
|
30
51
|
|
31
52
|
describe "typecasting" do
|
32
53
|
it "should work with Strings" do
|
33
|
-
|
54
|
+
item = HappyMapper::Item.new(:foo, String)
|
34
55
|
[21, '21'].each do |a|
|
35
|
-
|
56
|
+
item.typecast(a).should == '21'
|
36
57
|
end
|
37
58
|
end
|
38
59
|
|
39
60
|
it "should work with Integers" do
|
40
|
-
|
61
|
+
item = HappyMapper::Item.new(:foo, Integer)
|
41
62
|
[21, 21.0, '21'].each do |a|
|
42
|
-
|
63
|
+
item.typecast(a).should == 21
|
43
64
|
end
|
44
65
|
end
|
45
66
|
|
46
67
|
it "should work with Floats" do
|
47
|
-
|
68
|
+
item = HappyMapper::Item.new(:foo, Float)
|
48
69
|
[21, 21.0, '21'].each do |a|
|
49
|
-
|
70
|
+
item.typecast(a).should == 21.0
|
50
71
|
end
|
51
72
|
end
|
52
73
|
|
53
74
|
it "should work with Times" do
|
54
|
-
|
55
|
-
|
75
|
+
item = HappyMapper::Item.new(:foo, Time)
|
76
|
+
item.typecast('2000-01-01 01:01:01.123456').should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
|
56
77
|
end
|
57
78
|
|
58
79
|
it "should work with Dates" do
|
59
|
-
|
60
|
-
|
80
|
+
item = HappyMapper::Item.new(:foo, Date)
|
81
|
+
item.typecast('2000-01-01').should == Date.new(2000, 1, 1)
|
61
82
|
end
|
62
83
|
|
63
84
|
it "should work with DateTimes" do
|
64
|
-
|
65
|
-
|
85
|
+
item = HappyMapper::Item.new(:foo, DateTime)
|
86
|
+
item.typecast('2000-01-01 00:00:00').should == DateTime.new(2000, 1, 1, 0, 0, 0)
|
66
87
|
end
|
67
88
|
|
68
89
|
it "should work with Boolean" do
|
69
|
-
|
70
|
-
|
90
|
+
item = HappyMapper::Item.new(:foo, Boolean)
|
91
|
+
item.typecast('false').should == false
|
71
92
|
end
|
72
93
|
end
|
73
94
|
end
|
data/spec/happymapper_spec.rb
CHANGED
@@ -1,8 +1,127 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
require 'pp'
|
2
3
|
|
3
|
-
class
|
4
|
+
class Feature
|
5
|
+
include HappyMapper
|
6
|
+
element :name, String, :tag => '.|.//text()'
|
7
|
+
end
|
8
|
+
|
9
|
+
class FeatureBullet
|
4
10
|
include HappyMapper
|
5
11
|
|
12
|
+
tag 'features_bullets'
|
13
|
+
has_many :features, Feature
|
14
|
+
element :bug, String
|
15
|
+
end
|
16
|
+
|
17
|
+
class Product
|
18
|
+
include HappyMapper
|
19
|
+
|
20
|
+
element :title, String
|
21
|
+
has_one :feature_bullets, FeatureBullet
|
22
|
+
end
|
23
|
+
|
24
|
+
module FamilySearch
|
25
|
+
class Person
|
26
|
+
include HappyMapper
|
27
|
+
|
28
|
+
attribute :version, String
|
29
|
+
attribute :modified, Time
|
30
|
+
attribute :id, String
|
31
|
+
end
|
32
|
+
|
33
|
+
class Persons
|
34
|
+
include HappyMapper
|
35
|
+
has_many :person, Person
|
36
|
+
end
|
37
|
+
|
38
|
+
class FamilyTree
|
39
|
+
include HappyMapper
|
40
|
+
|
41
|
+
tag 'familytree', :root => true
|
42
|
+
attribute :version, String
|
43
|
+
attribute :status_message, String, :tag => 'statusMessage'
|
44
|
+
attribute :status_code, String, :tag => 'statusCode'
|
45
|
+
has_one :persons, Persons
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module FedEx
|
50
|
+
class Address
|
51
|
+
include HappyMapper
|
52
|
+
|
53
|
+
tag 'Address'
|
54
|
+
element :city, String, :tag => 'City'
|
55
|
+
element :state, String, :tag => 'StateOrProvinceCode'
|
56
|
+
element :zip, String, :tag => 'PostalCode'
|
57
|
+
element :countrycode, String, :tag => 'CountryCode'
|
58
|
+
element :residential, Boolean, :tag => 'Residential'
|
59
|
+
end
|
60
|
+
|
61
|
+
class Event
|
62
|
+
include HappyMapper
|
63
|
+
|
64
|
+
tag 'Events'
|
65
|
+
element :timestamp, String, :tag => 'Timestamp'
|
66
|
+
element :eventtype, String, :tag => 'EventType'
|
67
|
+
element :eventdescription, String, :tag => 'EventDescription'
|
68
|
+
has_one :address, Address
|
69
|
+
end
|
70
|
+
|
71
|
+
class PackageWeight
|
72
|
+
include HappyMapper
|
73
|
+
|
74
|
+
tag 'PackageWeight'
|
75
|
+
element :units, String, :tag => 'Units'
|
76
|
+
element :value, Integer, :tag => 'Value'
|
77
|
+
end
|
78
|
+
|
79
|
+
class TrackDetails
|
80
|
+
include HappyMapper
|
81
|
+
|
82
|
+
tag 'TrackDetails'
|
83
|
+
element :tracking_number, String, :tag => 'TrackingNumber'
|
84
|
+
element :status_code, String, :tag => 'StatusCode'
|
85
|
+
element :status_desc, String, :tag => 'StatusDescription'
|
86
|
+
element :carrier_code, String, :tag => 'CarrierCode'
|
87
|
+
element :service_info, String, :tag => 'ServiceInfo'
|
88
|
+
has_one :weight, PackageWeight, :tag => 'PackageWeight'
|
89
|
+
element :est_delivery, String, :tag => 'EstimatedDeliveryTimestamp'
|
90
|
+
has_many :events, Event
|
91
|
+
end
|
92
|
+
|
93
|
+
class Notification
|
94
|
+
include HappyMapper
|
95
|
+
|
96
|
+
tag 'Notifications'
|
97
|
+
element :severity, String, :tag => 'Severity'
|
98
|
+
element :source, String, :tag => 'Source'
|
99
|
+
element :code, Integer, :tag => 'Code'
|
100
|
+
element :message, String, :tag => 'Message'
|
101
|
+
element :localized_message, String, :tag => 'LocalizedMessage'
|
102
|
+
end
|
103
|
+
|
104
|
+
class TransactionDetail
|
105
|
+
include HappyMapper
|
106
|
+
|
107
|
+
tag 'TransactionDetail'
|
108
|
+
element :cust_tran_id, String, :tag => 'CustomerTransactionId'
|
109
|
+
end
|
110
|
+
|
111
|
+
class TrackReply
|
112
|
+
include HappyMapper
|
113
|
+
|
114
|
+
tag 'TrackReply', :root => true
|
115
|
+
element :highest_severity, String, :tag => 'HighestSeverity'
|
116
|
+
element :more_data, Boolean, :tag => 'MoreData'
|
117
|
+
has_many :notifications, Notification, :tag => 'Notifications'
|
118
|
+
has_many :trackdetails, TrackDetails, :tag => 'TrackDetails'
|
119
|
+
has_one :tran_detail, TransactionDetail, :tab => 'TransactionDetail'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class Place
|
124
|
+
include HappyMapper
|
6
125
|
element :name, String
|
7
126
|
end
|
8
127
|
|
@@ -53,15 +172,17 @@ end
|
|
53
172
|
|
54
173
|
class CurrentWeather
|
55
174
|
include HappyMapper
|
56
|
-
|
57
|
-
|
58
|
-
element :
|
59
|
-
element :
|
175
|
+
|
176
|
+
tag 'ob'
|
177
|
+
element :temperature, Integer, :tag => 'temp'
|
178
|
+
element :feels_like, Integer, :tag => 'feels-like'
|
179
|
+
element :current_condition, String, :tag => 'current-condition', :attributes => {:icon => String}
|
60
180
|
end
|
61
181
|
|
62
182
|
class Address
|
63
183
|
include HappyMapper
|
64
184
|
|
185
|
+
tag 'address', :root => true
|
65
186
|
element :street, String
|
66
187
|
element :postcode, String
|
67
188
|
element :housenumber, String
|
@@ -93,8 +214,7 @@ module GitHub
|
|
93
214
|
class Commit
|
94
215
|
include HappyMapper
|
95
216
|
|
96
|
-
tag "commit"
|
97
|
-
|
217
|
+
tag "commit", :root => true
|
98
218
|
element :url, String
|
99
219
|
element :tree, String
|
100
220
|
element :message, String
|
@@ -171,10 +291,15 @@ describe HappyMapper do
|
|
171
291
|
element.options[:single] = false
|
172
292
|
end
|
173
293
|
|
174
|
-
it "should default tag name to class" do
|
294
|
+
it "should default tag name to lowercase class" do
|
175
295
|
Foo.get_tag_name.should == 'foo'
|
176
296
|
end
|
177
297
|
|
298
|
+
it "should default tag name of class in modules to the last constant lowercase" do
|
299
|
+
module Bar; class Baz; include HappyMapper; end; end
|
300
|
+
Bar::Baz.get_tag_name.should == 'baz'
|
301
|
+
end
|
302
|
+
|
178
303
|
it "should allow setting tag name" do
|
179
304
|
Foo.tag('FooBar')
|
180
305
|
Foo.get_tag_name.should == 'FooBar'
|
@@ -199,139 +324,172 @@ describe HappyMapper do
|
|
199
324
|
end
|
200
325
|
end
|
201
326
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
first.href.should == 'http://roxml.rubyforge.org/'
|
214
|
-
first.hash.should == '19bba2ab667be03a19f67fb67dc56917'
|
215
|
-
first.description.should == 'ROXML - Ruby Object to XML Mapping Library'
|
216
|
-
first.tag.should == 'ruby xml gems mapping'
|
217
|
-
first.time.should == Time.utc(2008, 8, 9, 5, 24, 20)
|
218
|
-
first.others.should == 56
|
219
|
-
first.extended.should == 'ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML. Using simple annotations, it enables Ruby classes to be custom-mapped to XML. ROXML takes care of the marshalling and unmarshalling of mapped attributes so that developers can focus on building first-class Ruby classes.'
|
220
|
-
end
|
327
|
+
it "should parse xml attributes into ruby objects" do
|
328
|
+
posts = Post.parse(fixture_file('posts.xml'))
|
329
|
+
posts.size.should == 20
|
330
|
+
first = posts.first
|
331
|
+
first.href.should == 'http://roxml.rubyforge.org/'
|
332
|
+
first.hash.should == '19bba2ab667be03a19f67fb67dc56917'
|
333
|
+
first.description.should == 'ROXML - Ruby Object to XML Mapping Library'
|
334
|
+
first.tag.should == 'ruby xml gems mapping'
|
335
|
+
first.time.should == Time.utc(2008, 8, 9, 5, 24, 20)
|
336
|
+
first.others.should == 56
|
337
|
+
first.extended.should == 'ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML. Using simple annotations, it enables Ruby classes to be custom-mapped to XML. ROXML takes care of the marshalling and unmarshalling of mapped attributes so that developers can focus on building first-class Ruby classes.'
|
221
338
|
end
|
222
339
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
first.user.screen_name.should == 'jnunemaker'
|
244
|
-
first.user.location.should == 'Mishawaka, IN, US'
|
245
|
-
first.user.description.should == 'Loves his wife, ruby, notre dame football and iu basketball'
|
246
|
-
first.user.profile_image_url.should == 'http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg'
|
247
|
-
first.user.url.should == 'http://addictedtonew.com'
|
248
|
-
first.user.protected.should be_false
|
249
|
-
first.user.followers_count.should == 486
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
describe "#parse (with xml containing the desired element as root node)" do
|
254
|
-
before do
|
255
|
-
file_contents = File.read(File.dirname(__FILE__) + '/fixtures/address.xml')
|
256
|
-
@address = Address.parse(file_contents, :single => true)
|
257
|
-
end
|
258
|
-
|
259
|
-
it "should properly create objects" do
|
260
|
-
@address.street.should == 'Milchstrasse'
|
261
|
-
@address.postcode.should == '26131'
|
262
|
-
@address.housenumber.should == '23'
|
263
|
-
@address.city.should == 'Oldenburg'
|
264
|
-
@address.country.should == 'Germany'
|
265
|
-
end
|
340
|
+
it "should parse xml elements to ruby objcts" do
|
341
|
+
statuses = Status.parse(fixture_file('statuses.xml'))
|
342
|
+
statuses.size.should == 20
|
343
|
+
first = statuses.first
|
344
|
+
first.id.should == 882281424
|
345
|
+
first.created_at.should == Time.utc(2008, 8, 9, 5, 38, 12)
|
346
|
+
first.source.should == 'web'
|
347
|
+
first.truncated.should be_false
|
348
|
+
first.in_reply_to_status_id.should == 1234
|
349
|
+
first.in_reply_to_user_id.should == 12345
|
350
|
+
first.favorited.should be_false
|
351
|
+
first.user.id.should == 4243
|
352
|
+
first.user.name.should == 'John Nunemaker'
|
353
|
+
first.user.screen_name.should == 'jnunemaker'
|
354
|
+
first.user.location.should == 'Mishawaka, IN, US'
|
355
|
+
first.user.description.should == 'Loves his wife, ruby, notre dame football and iu basketball'
|
356
|
+
first.user.profile_image_url.should == 'http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg'
|
357
|
+
first.user.url.should == 'http://addictedtonew.com'
|
358
|
+
first.user.protected.should be_false
|
359
|
+
first.user.followers_count.should == 486
|
266
360
|
end
|
267
361
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
it "should properly create objects" do
|
276
|
-
@items.total_results.should == 22
|
277
|
-
@items.total_pages.should == 3
|
278
|
-
first = @items.items[0]
|
279
|
-
second = @items.items[1]
|
280
|
-
first.asin.should == '0321480791'
|
281
|
-
first.detail_page_url.should == 'http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh'
|
282
|
-
first.manufacturer.should == 'Addison-Wesley Professional'
|
283
|
-
second.asin.should == '047022388X'
|
284
|
-
second.manufacturer.should == 'Wrox'
|
285
|
-
end
|
362
|
+
it "should parse xml containing the desired element as root node" do
|
363
|
+
address = Address.parse(fixture_file('address.xml'), :single => true)
|
364
|
+
address.street.should == 'Milchstrasse'
|
365
|
+
address.postcode.should == '26131'
|
366
|
+
address.housenumber.should == '23'
|
367
|
+
address.city.should == 'Oldenburg'
|
368
|
+
address.country.should == 'Germany'
|
286
369
|
end
|
287
370
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
end
|
371
|
+
it "should parse xml with default namespace (amazon)" do
|
372
|
+
file_contents = fixture_file('pita.xml')
|
373
|
+
items = PITA::Items.parse(file_contents, :single => true)
|
374
|
+
items.total_results.should == 22
|
375
|
+
items.total_pages.should == 3
|
376
|
+
first = items.items[0]
|
377
|
+
second = items.items[1]
|
378
|
+
first.asin.should == '0321480791'
|
379
|
+
first.detail_page_url.should == 'http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh'
|
380
|
+
first.manufacturer.should == 'Addison-Wesley Professional'
|
381
|
+
second.asin.should == '047022388X'
|
382
|
+
second.manufacturer.should == 'Wrox'
|
301
383
|
end
|
302
384
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
@first = @radars[0]
|
311
|
-
@first.places.size.should == 1
|
312
|
-
@first.places[0].name.should == 'Store'
|
313
|
-
@second = @radars[1]
|
314
|
-
@second.places.size.should == 0
|
315
|
-
@third = @radars[2]
|
316
|
-
@third.places.size.should == 2
|
317
|
-
@third.places[0].name.should == 'Work'
|
318
|
-
@third.places[1].name.should == 'Home'
|
319
|
-
end
|
385
|
+
it "should parse xml that has attributes of elements" do
|
386
|
+
items = CurrentWeather.parse(fixture_file('current_weather.xml'))
|
387
|
+
first = items[0]
|
388
|
+
first.temperature.should == 51
|
389
|
+
first.feels_like.should == 51
|
390
|
+
first.current_condition.should == 'Sunny'
|
391
|
+
first.current_condition.icon.should == 'http://deskwx.weatherbug.com/images/Forecast/icons/cond007.gif'
|
320
392
|
end
|
321
393
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
394
|
+
it "should parse xml with nested elements" do
|
395
|
+
radars = Radar.parse(fixture_file('radar.xml'))
|
396
|
+
first = radars[0]
|
397
|
+
first.places.size.should == 1
|
398
|
+
first.places[0].name.should == 'Store'
|
399
|
+
second = radars[1]
|
400
|
+
second.places.size.should == 0
|
401
|
+
third = radars[2]
|
402
|
+
third.places.size.should == 2
|
403
|
+
third.places[0].name.should == 'Work'
|
404
|
+
third.places[1].name.should == 'Home'
|
405
|
+
end
|
406
|
+
|
407
|
+
it "should parse xml that has elements with dashes" do
|
408
|
+
commit = GitHub::Commit.parse(fixture_file('commit.xml'))
|
409
|
+
commit.message.should == "move commands.rb and helpers.rb into commands/ dir"
|
410
|
+
commit.url.should == "http://github.com/defunkt/github-gem/commit/c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b"
|
411
|
+
commit.id.should == "c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b"
|
412
|
+
commit.committed_date.should == Date.parse("2008-03-02T16:45:41-08:00")
|
413
|
+
commit.tree.should == "28a1a1ca3e663d35ba8bf07d3f1781af71359b76"
|
414
|
+
end
|
415
|
+
|
416
|
+
it "should parse xml with no namespace" do
|
417
|
+
product = Product.parse(fixture_file('product_no_namespace.xml'), :single => true)
|
418
|
+
product.title.should == "A Title"
|
419
|
+
product.feature_bullets.bug.should == 'This is a bug'
|
420
|
+
product.feature_bullets.features.size.should == 2
|
421
|
+
product.feature_bullets.features[0].name.should == 'This is feature text 1'
|
422
|
+
product.feature_bullets.features[1].name.should == 'This is feature text 2'
|
423
|
+
end
|
424
|
+
|
425
|
+
it "should parse xml with default namespace" do
|
426
|
+
product = Product.parse(fixture_file('product_default_namespace.xml'), :single => true)
|
427
|
+
product.title.should == "A Title"
|
428
|
+
product.feature_bullets.bug.should == 'This is a bug'
|
429
|
+
product.feature_bullets.features.size.should == 2
|
430
|
+
product.feature_bullets.features[0].name.should == 'This is feature text 1'
|
431
|
+
product.feature_bullets.features[1].name.should == 'This is feature text 2'
|
432
|
+
end
|
433
|
+
|
434
|
+
it "should parse xml with single namespace" do
|
435
|
+
product = Product.parse(fixture_file('product_single_namespace.xml'), :single => true)
|
436
|
+
product.title.should == "A Title"
|
437
|
+
product.feature_bullets.bug.should == 'This is a bug'
|
438
|
+
product.feature_bullets.features.size.should == 2
|
439
|
+
product.feature_bullets.features[0].name.should == 'This is feature text 1'
|
440
|
+
product.feature_bullets.features[1].name.should == 'This is feature text 2'
|
441
|
+
end
|
442
|
+
|
443
|
+
it "should parse xml with multiple namespaces" do
|
444
|
+
track = FedEx::TrackReply.parse(fixture_file('multiple_namespaces.xml'))
|
445
|
+
track.highest_severity.should == 'SUCCESS'
|
446
|
+
track.more_data.should be_false
|
447
|
+
notification = track.notifications.first
|
448
|
+
notification.code.should == 0
|
449
|
+
notification.localized_message.should == 'Request was successfully processed.'
|
450
|
+
notification.message.should == 'Request was successfully processed.'
|
451
|
+
notification.severity.should == 'SUCCESS'
|
452
|
+
notification.source.should == 'trck'
|
453
|
+
detail = track.trackdetails.first
|
454
|
+
detail.carrier_code.should == 'FDXG'
|
455
|
+
detail.est_delivery.should == '2009-01-02T00:00:00'
|
456
|
+
detail.service_info.should == 'Ground-Package Returns Program-Domestic'
|
457
|
+
detail.status_code.should == 'OD'
|
458
|
+
detail.status_desc.should == 'On FedEx vehicle for delivery'
|
459
|
+
detail.tracking_number.should == '9611018034267800045212'
|
460
|
+
detail.weight.units.should == 'LB'
|
461
|
+
detail.weight.value.should == 2
|
462
|
+
events = detail.events
|
463
|
+
events.size.should == 10
|
464
|
+
first_event = events[0]
|
465
|
+
first_event.eventdescription.should == 'On FedEx vehicle for delivery'
|
466
|
+
first_event.eventtype.should == 'OD'
|
467
|
+
first_event.timestamp.should == '2009-01-02T06:00:00'
|
468
|
+
first_event.address.city.should == 'WICHITA'
|
469
|
+
first_event.address.countrycode.should == 'US'
|
470
|
+
first_event.address.residential.should be_false
|
471
|
+
first_event.address.state.should == 'KS'
|
472
|
+
first_event.address.zip.should == '67226'
|
473
|
+
last_event = events[-1]
|
474
|
+
last_event.eventdescription.should == 'In FedEx possession'
|
475
|
+
last_event.eventtype.should == 'IP'
|
476
|
+
last_event.timestamp.should == '2008-12-27T09:40:00'
|
477
|
+
last_event.address.city.should == 'LONGWOOD'
|
478
|
+
last_event.address.countrycode.should == 'US'
|
479
|
+
last_event.address.residential.should be_false
|
480
|
+
last_event.address.state.should == 'FL'
|
481
|
+
last_event.address.zip.should == '327506398'
|
482
|
+
track.tran_detail.cust_tran_id.should == '20090102-111321'
|
483
|
+
end
|
484
|
+
|
485
|
+
xit "should parse family search xml" do
|
486
|
+
tree = FamilySearch::FamilyTree.parse(fixture_file('family_tree.xml'))
|
487
|
+
tree.version.should == '1.0.20071213.942'
|
488
|
+
tree.status_message.should == 'OK'
|
489
|
+
tree.status_code.should == '200'
|
490
|
+
# tree.people.size.should == 1
|
491
|
+
# tree.people.first.version.should == '1199378491000'
|
492
|
+
# tree.people.first.modified.should == Time.utc(2008, 1, 3, 16, 41, 31) # 2008-01-03T09:41:31-07:00
|
493
|
+
# tree.people.first.id.should == 'KWQS-BBQ'
|
336
494
|
end
|
337
495
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: happymapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-01-
|
12
|
+
date: 2009-01-29 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -53,7 +53,6 @@ files:
|
|
53
53
|
- examples/dashed_elements.rb
|
54
54
|
- examples/post.rb
|
55
55
|
- examples/twitter.rb
|
56
|
-
- happymapper.gemspec
|
57
56
|
- History
|
58
57
|
- lib/happymapper/attribute.rb
|
59
58
|
- lib/happymapper/element.rb
|
@@ -68,8 +67,13 @@ files:
|
|
68
67
|
- spec/fixtures/address.xml
|
69
68
|
- spec/fixtures/commit.xml
|
70
69
|
- spec/fixtures/current_weather.xml
|
70
|
+
- spec/fixtures/family_tree.xml
|
71
|
+
- spec/fixtures/multiple_namespaces.xml
|
71
72
|
- spec/fixtures/pita.xml
|
72
73
|
- spec/fixtures/posts.xml
|
74
|
+
- spec/fixtures/product_default_namespace.xml
|
75
|
+
- spec/fixtures/product_no_namespace.xml
|
76
|
+
- spec/fixtures/product_single_namespace.xml
|
73
77
|
- spec/fixtures/radar.xml
|
74
78
|
- spec/fixtures/statuses.xml
|
75
79
|
- spec/happymapper_attribute_spec.rb
|
@@ -81,6 +85,7 @@ files:
|
|
81
85
|
- TODO
|
82
86
|
- website/css/common.css
|
83
87
|
- website/index.html
|
88
|
+
- happymapper.gemspec
|
84
89
|
has_rdoc: true
|
85
90
|
homepage: http://happymapper.rubyforge.org
|
86
91
|
post_install_message: May you have many happy mappings!
|