nokogiri-happymapper 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +26 -1
- data/README.md +204 -117
- data/lib/happymapper.rb +318 -343
- data/lib/happymapper/anonymous_mapper.rb +27 -29
- data/lib/happymapper/attribute.rb +7 -5
- data/lib/happymapper/element.rb +19 -24
- data/lib/happymapper/item.rb +18 -20
- data/lib/happymapper/supported_types.rb +20 -19
- data/lib/happymapper/text_node.rb +4 -3
- data/lib/happymapper/version.rb +3 -1
- data/spec/attribute_default_value_spec.rb +14 -15
- data/spec/attributes_spec.rb +14 -15
- data/spec/happymapper/attribute_spec.rb +4 -4
- data/spec/happymapper/element_spec.rb +3 -1
- data/spec/happymapper/item_spec.rb +49 -41
- data/spec/happymapper/text_node_spec.rb +3 -1
- data/spec/happymapper_parse_spec.rb +62 -44
- data/spec/happymapper_spec.rb +270 -263
- data/spec/has_many_empty_array_spec.rb +8 -7
- data/spec/ignay_spec.rb +27 -31
- data/spec/inheritance_spec.rb +30 -24
- data/spec/mixed_namespaces_spec.rb +14 -15
- data/spec/parse_with_object_to_update_spec.rb +37 -38
- data/spec/spec_helper.rb +18 -0
- data/spec/to_xml_spec.rb +64 -63
- data/spec/to_xml_with_namespaces_spec.rb +66 -64
- data/spec/wilcard_tag_name_spec.rb +25 -21
- data/spec/wrap_spec.rb +11 -11
- data/spec/xpath_spec.rb +33 -32
- metadata +33 -5
data/spec/attributes_spec.rb
CHANGED
@@ -1,36 +1,35 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'spec_helper'
|
4
4
|
|
5
|
+
describe 'Attribute Method Conversion' do
|
5
6
|
let(:xml_document) do
|
6
|
-
%
|
7
|
+
%(<document>
|
7
8
|
<link data-src='http://cooking.com/roastbeef' type='recipe'>Roast Beef</link>
|
8
|
-
</document>
|
9
|
+
</document>)
|
9
10
|
end
|
10
11
|
|
11
12
|
module AttributeMethodConversion
|
12
13
|
class Document
|
13
14
|
include HappyMapper
|
14
15
|
|
15
|
-
has_many :link, String, :
|
16
|
-
|
16
|
+
has_many :link, String, attributes: { 'data-src': String, type: String, href: String }
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
let(:document) do
|
21
|
-
AttributeMethodConversion::Document.parse(xml_document,single: true)
|
21
|
+
AttributeMethodConversion::Document.parse(xml_document, single: true)
|
22
22
|
end
|
23
23
|
|
24
|
-
it
|
25
|
-
expect(document.link).to eq [
|
24
|
+
it 'link' do
|
25
|
+
expect(document.link).to eq ['Roast Beef']
|
26
26
|
end
|
27
27
|
|
28
|
-
it
|
29
|
-
expect(document.link.first.data_src).to eq
|
28
|
+
it 'link.data_src' do
|
29
|
+
expect(document.link.first.data_src).to eq 'http://cooking.com/roastbeef'
|
30
30
|
end
|
31
31
|
|
32
|
-
it
|
33
|
-
expect(document.link.first.type).to eq
|
32
|
+
it 'link.type' do
|
33
|
+
expect(document.link.first.type).to eq 'recipe'
|
34
34
|
end
|
35
|
-
|
36
|
-
end
|
35
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe HappyMapper::Attribute do
|
4
|
-
|
5
|
-
describe "initialization" do
|
6
|
+
describe 'initialization' do
|
6
7
|
it 'accepts :default option' do
|
7
|
-
attr = described_class.new(:foo, String, :
|
8
|
+
attr = described_class.new(:foo, String, default: 'foobar')
|
8
9
|
expect(attr.default).to eq('foobar')
|
9
10
|
end
|
10
11
|
end
|
11
|
-
|
12
12
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
module Foo
|
@@ -5,13 +7,12 @@ module Foo
|
|
5
7
|
end
|
6
8
|
|
7
9
|
describe HappyMapper::Item do
|
8
|
-
|
9
|
-
describe "new instance" do
|
10
|
+
describe 'new instance' do
|
10
11
|
before do
|
11
|
-
@item = HappyMapper::Item.new(:foo, String, :
|
12
|
+
@item = HappyMapper::Item.new(:foo, String, tag: 'foobar')
|
12
13
|
end
|
13
14
|
|
14
|
-
it
|
15
|
+
it 'should accept a name' do
|
15
16
|
expect(@item.name).to eq('foo')
|
16
17
|
end
|
17
18
|
|
@@ -23,112 +24,119 @@ describe HappyMapper::Item do
|
|
23
24
|
expect(@item.tag).to eq('foobar')
|
24
25
|
end
|
25
26
|
|
26
|
-
it
|
27
|
+
it 'should have a method_name' do
|
27
28
|
expect(@item.method_name).to eq('foo')
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
|
-
describe
|
32
|
-
it
|
32
|
+
describe '#constant' do
|
33
|
+
it 'should just use type if constant' do
|
33
34
|
item = HappyMapper::Item.new(:foo, String)
|
34
35
|
expect(item.constant).to eq(String)
|
35
36
|
end
|
36
37
|
|
37
|
-
it
|
38
|
+
it 'should convert string type to constant' do
|
38
39
|
item = HappyMapper::Item.new(:foo, 'String')
|
39
40
|
expect(item.constant).to eq(String)
|
40
41
|
end
|
41
42
|
|
42
|
-
it
|
43
|
+
it 'should convert string with :: to constant' do
|
43
44
|
item = HappyMapper::Item.new(:foo, 'Foo::Bar')
|
44
45
|
expect(item.constant).to eq(Foo::Bar)
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
48
|
-
describe
|
49
|
-
it
|
50
|
-
item = HappyMapper::Item.new(:'foo-bar', String, :
|
49
|
+
describe '#method_name' do
|
50
|
+
it 'should convert dashes to underscores' do
|
51
|
+
item = HappyMapper::Item.new(:'foo-bar', String, tag: 'foobar')
|
51
52
|
expect(item.method_name).to eq('foo_bar')
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
55
|
-
describe
|
56
|
-
it
|
57
|
-
item = HappyMapper::Item.new(:foo, String, :
|
56
|
+
describe '#xpath' do
|
57
|
+
it 'should default to tag' do
|
58
|
+
item = HappyMapper::Item.new(:foo, String, tag: 'foobar')
|
58
59
|
expect(item.xpath).to eq('foobar')
|
59
60
|
end
|
60
61
|
|
61
|
-
it
|
62
|
-
item = HappyMapper::Item.new(:foo, String, :
|
62
|
+
it 'should prepend with .// if options[:deep] true' do
|
63
|
+
item = HappyMapper::Item.new(:foo, String, tag: 'foobar', deep: true)
|
63
64
|
expect(item.xpath).to eq('.//foobar')
|
64
65
|
end
|
65
66
|
|
66
|
-
it
|
67
|
-
item = HappyMapper::Item.new(:foo, String, :
|
67
|
+
it 'should prepend namespace if namespace exists' do
|
68
|
+
item = HappyMapper::Item.new(:foo, String, tag: 'foobar')
|
68
69
|
item.namespace = 'v2'
|
69
70
|
expect(item.xpath).to eq('v2:foobar')
|
70
71
|
end
|
71
72
|
end
|
72
73
|
|
73
|
-
describe
|
74
|
-
it
|
74
|
+
describe 'typecasting' do
|
75
|
+
it 'should work with Strings' do
|
75
76
|
item = HappyMapper::Item.new(:foo, String)
|
76
77
|
[21, '21'].each do |a|
|
77
78
|
expect(item.typecast(a)).to eq('21')
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
81
|
-
it
|
82
|
+
it 'should work with Integers' do
|
82
83
|
item = HappyMapper::Item.new(:foo, Integer)
|
83
84
|
[21, 21.0, '21'].each do |a|
|
84
85
|
expect(item.typecast(a)).to eq(21)
|
85
86
|
end
|
86
87
|
end
|
87
88
|
|
88
|
-
it
|
89
|
+
it 'should work with Floats' do
|
89
90
|
item = HappyMapper::Item.new(:foo, Float)
|
90
91
|
[21, 21.0, '21'].each do |a|
|
91
92
|
expect(item.typecast(a)).to eq(21.0)
|
92
93
|
end
|
93
94
|
end
|
94
95
|
|
95
|
-
it
|
96
|
+
it 'should work with Times' do
|
96
97
|
item = HappyMapper::Item.new(:foo, Time)
|
97
98
|
expect(item.typecast('2000-01-01 01:01:01.123456')).to eq(Time.local(2000, 1, 1, 1, 1, 1, 123456))
|
98
99
|
end
|
99
100
|
|
100
|
-
it
|
101
|
+
it 'should work with Dates' do
|
101
102
|
item = HappyMapper::Item.new(:foo, Date)
|
102
103
|
expect(item.typecast('2000-01-01')).to eq(Date.new(2000, 1, 1))
|
103
104
|
end
|
104
105
|
|
105
|
-
it
|
106
|
+
it 'should handle nil Dates' do
|
106
107
|
item = HappyMapper::Item.new(:foo, Date)
|
107
108
|
expect(item.typecast(nil)).to eq(nil)
|
108
109
|
end
|
109
110
|
|
110
|
-
it
|
111
|
+
it 'should handle empty string Dates' do
|
111
112
|
item = HappyMapper::Item.new(:foo, Date)
|
112
|
-
expect(item.typecast(
|
113
|
+
expect(item.typecast('')).to eq(nil)
|
113
114
|
end
|
114
115
|
|
115
|
-
|
116
|
-
item
|
117
|
-
expect(item.typecast('2000-01-01 00:00:00')).to eq(DateTime.new(2000, 1, 1, 0, 0, 0))
|
118
|
-
end
|
116
|
+
context 'with DateTime' do
|
117
|
+
let(:item) { HappyMapper::Item.new(:foo, DateTime) }
|
119
118
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
119
|
+
it 'works with a string' do
|
120
|
+
result = item.typecast('2000-01-01 13:42:37')
|
121
|
+
expect(result.to_time).to eq Time.new(2000, 1, 1, 13, 42, 37, '+00:00')
|
122
|
+
end
|
124
123
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
124
|
+
it 'works with a historical date in a string' do
|
125
|
+
result = item.typecast('1616-04-23')
|
126
|
+
expect(result.to_time).to eq Time.new(1616, 4, 23, 0, 0, 0, '+00:00')
|
127
|
+
expect(result).to be_gregorian
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'handles nil' do
|
131
|
+
expect(item.typecast(nil)).to eq(nil)
|
132
|
+
end
|
129
133
|
|
134
|
+
it 'handles empty strings' do
|
135
|
+
expect(item.typecast('')).to eq(nil)
|
136
|
+
end
|
137
|
+
end
|
130
138
|
|
131
|
-
it
|
139
|
+
it 'should work with Boolean' do
|
132
140
|
item = HappyMapper::Item.new(:foo, HappyMapper::Boolean)
|
133
141
|
expect(item.typecast('false')).to eq(false)
|
134
142
|
end
|
@@ -1,88 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe HappyMapper do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
context "on a single root node" do
|
8
|
-
|
6
|
+
context '.parse' do
|
7
|
+
context 'on a single root node' do
|
9
8
|
subject { described_class.parse fixture_file('address.xml') }
|
10
9
|
|
11
|
-
it
|
12
|
-
expect(subject.street).to eq(
|
13
|
-
expect(subject.housenumber).to eq(
|
14
|
-
expect(subject.postcode).to eq(
|
15
|
-
expect(subject.city).to eq(
|
10
|
+
it 'should parse child elements' do
|
11
|
+
expect(subject.street).to eq('Milchstrasse')
|
12
|
+
expect(subject.housenumber).to eq('23')
|
13
|
+
expect(subject.postcode).to eq('26131')
|
14
|
+
expect(subject.city).to eq('Oldenburg')
|
16
15
|
end
|
17
16
|
|
18
|
-
it
|
17
|
+
it 'should not create a content entry when the xml contents no text content' do
|
19
18
|
expect(subject).not_to respond_to :content
|
20
19
|
end
|
21
20
|
|
22
|
-
context
|
23
|
-
|
24
|
-
|
25
|
-
expect(subject.country.code).to eq("de")
|
21
|
+
context 'child elements with attributes' do
|
22
|
+
it 'should parse the attributes' do
|
23
|
+
expect(subject.country.code).to eq('de')
|
26
24
|
end
|
27
25
|
|
28
|
-
it
|
29
|
-
expect(subject.country.content).to eq(
|
26
|
+
it 'should parse the content' do
|
27
|
+
expect(subject.country.content).to eq('Germany')
|
30
28
|
end
|
31
|
-
|
32
29
|
end
|
33
|
-
|
34
30
|
end
|
35
31
|
|
36
|
-
context
|
32
|
+
context 'element names with special characters' do
|
37
33
|
subject { described_class.parse fixture_file('ambigous_items.xml') }
|
38
34
|
|
39
|
-
it
|
35
|
+
it 'should create accessor methods with similar names' do
|
40
36
|
expect(subject.my_items.item).to be_kind_of Array
|
41
37
|
end
|
42
38
|
end
|
43
39
|
|
44
|
-
context
|
45
|
-
|
40
|
+
context 'element names with camelCased elements and Capital Letters' do
|
46
41
|
subject { described_class.parse fixture_file('subclass_namespace.xml') }
|
47
42
|
|
48
|
-
it
|
49
|
-
expect(subject.
|
50
|
-
expect(subject.photo.
|
51
|
-
|
43
|
+
it 'parses camel-cased child elements correctly' do
|
44
|
+
expect(subject.photo.publish_options.author).to eq('Stephanie')
|
45
|
+
expect(subject.gallery.photo.title).to eq('photo title')
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'parses camel-cased child properties correctly' do
|
49
|
+
expect(subject.publish_options.created_day).to eq('2011-01-14')
|
52
50
|
end
|
53
51
|
end
|
54
52
|
|
55
|
-
context
|
56
|
-
subject { described_class.parse
|
53
|
+
context 'with elements with camelCased attribute names' do
|
54
|
+
subject { described_class.parse '<foo barBaz="quuz"/>' }
|
57
55
|
|
58
|
-
it
|
59
|
-
expect(subject.
|
56
|
+
it 'parses attributes correctly' do
|
57
|
+
expect(subject.bar_baz).to eq('quuz')
|
60
58
|
end
|
61
59
|
end
|
62
60
|
|
63
|
-
context
|
61
|
+
context 'several elements nested deep' do
|
62
|
+
subject { described_class.parse fixture_file('ambigous_items.xml') }
|
63
|
+
|
64
|
+
it 'should parse the entire relationship' do
|
65
|
+
expect(subject.my_items.item.first.item.name).to eq('My first internal item')
|
66
|
+
end
|
67
|
+
end
|
64
68
|
|
69
|
+
context 'xml that contains multiple entries' do
|
65
70
|
subject { described_class.parse fixture_file('multiple_primitives.xml') }
|
66
71
|
|
67
72
|
it "should parse the elements as it would a 'has_many'" do
|
73
|
+
expect(subject.name).to eq('value')
|
74
|
+
expect(subject.image).to eq(%w(image1 image2))
|
75
|
+
end
|
76
|
+
end
|
68
77
|
|
69
|
-
|
70
|
-
|
78
|
+
context 'xml with multiple namespaces' do
|
79
|
+
subject { described_class.parse fixture_file('subclass_namespace.xml') }
|
71
80
|
|
81
|
+
it 'should parse the elements an values correctly' do
|
82
|
+
expect(subject.title).to eq('article title')
|
72
83
|
end
|
73
84
|
|
85
|
+
it 'parses attribute names correctly' do
|
86
|
+
expect(subject.name).to eq 'title'
|
87
|
+
end
|
74
88
|
end
|
75
89
|
|
76
|
-
context
|
77
|
-
|
78
|
-
|
90
|
+
context 'with value elements with different namespace' do
|
91
|
+
let(:xml) do
|
92
|
+
<<~XML
|
93
|
+
<a:foo xmlns:a="http://foo.org/a" xmlns:b="http://foo.org/b">
|
94
|
+
<b:bar>Hello</b:bar>
|
95
|
+
</a:foo>
|
96
|
+
XML
|
97
|
+
end
|
98
|
+
let(:result) { described_class.parse xml }
|
79
99
|
|
80
|
-
it
|
81
|
-
expect(
|
100
|
+
it 'parses the value elements correctly' do
|
101
|
+
expect(result.bar).to eq 'Hello'
|
82
102
|
end
|
83
103
|
end
|
84
104
|
|
85
|
-
context
|
105
|
+
context 'after_parse callbacks' do
|
86
106
|
module AfterParseSpec
|
87
107
|
class Address
|
88
108
|
include HappyMapper
|
@@ -94,7 +114,7 @@ describe HappyMapper do
|
|
94
114
|
AfterParseSpec::Address.after_parse_callbacks.clear
|
95
115
|
end
|
96
116
|
|
97
|
-
it
|
117
|
+
it 'should callback with the newly created object' do
|
98
118
|
from_cb = nil
|
99
119
|
called = false
|
100
120
|
cb1 = proc { |object| from_cb = object }
|
@@ -107,7 +127,5 @@ describe HappyMapper do
|
|
107
127
|
expect(called).to eq(true)
|
108
128
|
end
|
109
129
|
end
|
110
|
-
|
111
130
|
end
|
112
|
-
|
113
|
-
end
|
131
|
+
end
|
data/spec/happymapper_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
require 'uri'
|
3
5
|
|
@@ -39,13 +41,12 @@ module Analytics
|
|
39
41
|
|
40
42
|
tag 'entry'
|
41
43
|
element :title, String
|
42
|
-
element :tableId, String, :
|
44
|
+
element :tableId, String, namespace: 'dxp'
|
43
45
|
|
44
46
|
has_many :properties, Property
|
45
47
|
has_many :goals, Goal
|
46
48
|
end
|
47
49
|
|
48
|
-
|
49
50
|
class Entry
|
50
51
|
include HappyMapper
|
51
52
|
|
@@ -53,7 +54,7 @@ module Analytics
|
|
53
54
|
element :id, String
|
54
55
|
element :updated, DateTime
|
55
56
|
element :title, String
|
56
|
-
element :table_id, String, :
|
57
|
+
element :table_id, String, namespace: 'dxp', tag: 'tableId'
|
57
58
|
has_many :properties, Property
|
58
59
|
end
|
59
60
|
|
@@ -73,15 +74,15 @@ module Atom
|
|
73
74
|
include HappyMapper
|
74
75
|
tag 'feed'
|
75
76
|
|
76
|
-
attribute :xmlns, String, :
|
77
|
-
element :id, String, :
|
78
|
-
element :title, String, :
|
79
|
-
element :updated, DateTime, :
|
80
|
-
element :link, String, :
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
77
|
+
attribute :xmlns, String, single: true
|
78
|
+
element :id, String, single: true
|
79
|
+
element :title, String, single: true
|
80
|
+
element :updated, DateTime, single: true
|
81
|
+
element :link, String, single: false, attributes: {
|
82
|
+
rel: String,
|
83
|
+
type: String,
|
84
|
+
href: String
|
85
|
+
}
|
85
86
|
# has_many :entries, Entry # nothing interesting in the entries
|
86
87
|
end
|
87
88
|
end
|
@@ -93,7 +94,6 @@ class Country
|
|
93
94
|
content :name, String
|
94
95
|
end
|
95
96
|
|
96
|
-
|
97
97
|
class State
|
98
98
|
include HappyMapper
|
99
99
|
end
|
@@ -115,7 +115,7 @@ end
|
|
115
115
|
|
116
116
|
class Feature
|
117
117
|
include HappyMapper
|
118
|
-
element :name, String, :
|
118
|
+
element :name, String, xpath: './/text()'
|
119
119
|
end
|
120
120
|
|
121
121
|
class FeatureBullet
|
@@ -143,7 +143,7 @@ module FamilySearch
|
|
143
143
|
include HappyMapper
|
144
144
|
|
145
145
|
tag 'alternateIds'
|
146
|
-
has_many :ids, String, :
|
146
|
+
has_many :ids, String, tag: 'id'
|
147
147
|
end
|
148
148
|
|
149
149
|
class Information
|
@@ -171,8 +171,8 @@ module FamilySearch
|
|
171
171
|
|
172
172
|
tag 'familytree'
|
173
173
|
attribute :version, String
|
174
|
-
attribute :status_message, String, :
|
175
|
-
attribute :status_code, String, :
|
174
|
+
attribute :status_message, String, tag: 'statusMessage'
|
175
|
+
attribute :status_code, String, tag: 'statusCode'
|
176
176
|
has_one :persons, Persons
|
177
177
|
end
|
178
178
|
end
|
@@ -183,11 +183,11 @@ module FedEx
|
|
183
183
|
|
184
184
|
tag 'Address'
|
185
185
|
namespace 'v2'
|
186
|
-
element :city, String, :
|
187
|
-
element :state, String, :
|
188
|
-
element :zip, String, :
|
189
|
-
element :countrycode, String, :
|
190
|
-
element :residential, Boolean, :
|
186
|
+
element :city, String, tag: 'City'
|
187
|
+
element :state, String, tag: 'StateOrProvinceCode'
|
188
|
+
element :zip, String, tag: 'PostalCode'
|
189
|
+
element :countrycode, String, tag: 'CountryCode'
|
190
|
+
element :residential, Boolean, tag: 'Residential'
|
191
191
|
end
|
192
192
|
|
193
193
|
class Event
|
@@ -195,9 +195,9 @@ module FedEx
|
|
195
195
|
|
196
196
|
tag 'Events'
|
197
197
|
namespace 'v2'
|
198
|
-
element :timestamp, String, :
|
199
|
-
element :eventtype, String, :
|
200
|
-
element :eventdescription, String, :
|
198
|
+
element :timestamp, String, tag: 'Timestamp'
|
199
|
+
element :eventtype, String, tag: 'EventType'
|
200
|
+
element :eventdescription, String, tag: 'EventDescription'
|
201
201
|
has_one :address, Address
|
202
202
|
end
|
203
203
|
|
@@ -206,8 +206,8 @@ module FedEx
|
|
206
206
|
|
207
207
|
tag 'PackageWeight'
|
208
208
|
namespace 'v2'
|
209
|
-
element :units, String, :
|
210
|
-
element :value, Integer, :
|
209
|
+
element :units, String, tag: 'Units'
|
210
|
+
element :value, Integer, tag: 'Value'
|
211
211
|
end
|
212
212
|
|
213
213
|
class TrackDetails
|
@@ -215,13 +215,13 @@ module FedEx
|
|
215
215
|
|
216
216
|
tag 'TrackDetails'
|
217
217
|
namespace 'v2'
|
218
|
-
element :tracking_number, String, :
|
219
|
-
element :status_code, String, :
|
220
|
-
element :status_desc, String, :
|
221
|
-
element :carrier_code, String, :
|
222
|
-
element :service_info, String, :
|
223
|
-
has_one :weight, PackageWeight, :
|
224
|
-
element :est_delivery,
|
218
|
+
element :tracking_number, String, tag: 'TrackingNumber'
|
219
|
+
element :status_code, String, tag: 'StatusCode'
|
220
|
+
element :status_desc, String, tag: 'StatusDescription'
|
221
|
+
element :carrier_code, String, tag: 'CarrierCode'
|
222
|
+
element :service_info, String, tag: 'ServiceInfo'
|
223
|
+
has_one :weight, PackageWeight, tag: 'PackageWeight'
|
224
|
+
element :est_delivery, String, tag: 'EstimatedDeliveryTimestamp'
|
225
225
|
has_many :events, Event
|
226
226
|
end
|
227
227
|
|
@@ -230,11 +230,11 @@ module FedEx
|
|
230
230
|
|
231
231
|
tag 'Notifications'
|
232
232
|
namespace 'v2'
|
233
|
-
element :severity, String, :
|
234
|
-
element :source, String, :
|
235
|
-
element :code, Integer, :
|
236
|
-
element :message, String, :
|
237
|
-
element :localized_message, String, :
|
233
|
+
element :severity, String, tag: 'Severity'
|
234
|
+
element :source, String, tag: 'Source'
|
235
|
+
element :code, Integer, tag: 'Code'
|
236
|
+
element :message, String, tag: 'Message'
|
237
|
+
element :localized_message, String, tag: 'LocalizedMessage'
|
238
238
|
end
|
239
239
|
|
240
240
|
class TransactionDetail
|
@@ -242,7 +242,7 @@ module FedEx
|
|
242
242
|
|
243
243
|
tag 'TransactionDetail'
|
244
244
|
namespace 'v2'
|
245
|
-
element :cust_tran_id, String, :
|
245
|
+
element :cust_tran_id, String, tag: 'CustomerTransactionId'
|
246
246
|
end
|
247
247
|
|
248
248
|
class TrackReply
|
@@ -250,11 +250,11 @@ module FedEx
|
|
250
250
|
|
251
251
|
tag 'TrackReply'
|
252
252
|
namespace 'v2'
|
253
|
-
element :highest_severity, String, :
|
254
|
-
element :more_data, Boolean, :
|
255
|
-
has_many :notifications, Notification, :
|
256
|
-
has_many :trackdetails, TrackDetails, :
|
257
|
-
has_one :tran_detail, TransactionDetail, :
|
253
|
+
element :highest_severity, String, tag: 'HighestSeverity'
|
254
|
+
element :more_data, Boolean, tag: 'MoreData'
|
255
|
+
has_many :notifications, Notification, tag: 'Notifications'
|
256
|
+
has_many :trackdetails, TrackDetails, tag: 'TrackDetails'
|
257
|
+
has_one :tran_detail, TransactionDetail, tab: 'TransactionDetail'
|
258
258
|
end
|
259
259
|
end
|
260
260
|
|
@@ -265,7 +265,7 @@ end
|
|
265
265
|
|
266
266
|
class Radar
|
267
267
|
include HappyMapper
|
268
|
-
has_many :places, Place, :
|
268
|
+
has_many :places, Place, tag: :place
|
269
269
|
end
|
270
270
|
|
271
271
|
class Post
|
@@ -297,7 +297,7 @@ end
|
|
297
297
|
class Status
|
298
298
|
include HappyMapper
|
299
299
|
|
300
|
-
register_namespace 'fake',
|
300
|
+
register_namespace 'fake', 'faka:namespace'
|
301
301
|
|
302
302
|
element :id, Integer
|
303
303
|
element :text, String
|
@@ -307,7 +307,7 @@ class Status
|
|
307
307
|
element :in_reply_to_status_id, Integer
|
308
308
|
element :in_reply_to_user_id, Integer
|
309
309
|
element :favorited, Boolean
|
310
|
-
element :non_existent, String, :
|
310
|
+
element :non_existent, String, tag: 'dummy', namespace: 'fake'
|
311
311
|
has_one :user, User
|
312
312
|
end
|
313
313
|
|
@@ -316,9 +316,9 @@ class CurrentWeather
|
|
316
316
|
|
317
317
|
tag 'ob'
|
318
318
|
namespace 'aws'
|
319
|
-
element :temperature, Integer, :
|
320
|
-
element :feels_like, Integer, :
|
321
|
-
element :current_condition, String, :
|
319
|
+
element :temperature, Integer, tag: 'temp'
|
320
|
+
element :feels_like, Integer, tag: 'feels-like'
|
321
|
+
element :current_condition, String, tag: 'current-condition', attributes: { icon: String }
|
322
322
|
end
|
323
323
|
|
324
324
|
# for type coercion
|
@@ -329,19 +329,19 @@ module PITA
|
|
329
329
|
include HappyMapper
|
330
330
|
|
331
331
|
tag 'Item' # if you put class in module you need tag
|
332
|
-
element :asin, String, :
|
333
|
-
element :detail_page_url, URI, :
|
334
|
-
element :manufacturer, String, :
|
335
|
-
element :point, String, :
|
336
|
-
element :product_group, ProductGroup, :
|
332
|
+
element :asin, String, tag: 'ASIN'
|
333
|
+
element :detail_page_url, URI, tag: 'DetailPageURL', parser: :parse
|
334
|
+
element :manufacturer, String, tag: 'Manufacturer', deep: true
|
335
|
+
element :point, String, tag: 'point', namespace: 'georss'
|
336
|
+
element :product_group, ProductGroup, tag: 'ProductGroup', deep: true, parser: :new, raw: true
|
337
337
|
end
|
338
338
|
|
339
339
|
class Items
|
340
340
|
include HappyMapper
|
341
341
|
|
342
342
|
tag 'Items' # if you put class in module you need tag
|
343
|
-
element :total_results, Integer, :
|
344
|
-
element :total_pages, Integer, :
|
343
|
+
element :total_results, Integer, tag: 'TotalResults'
|
344
|
+
element :total_pages, Integer, tag: 'TotalPages'
|
345
345
|
has_many :items, Item
|
346
346
|
end
|
347
347
|
end
|
@@ -350,7 +350,7 @@ module GitHub
|
|
350
350
|
class Commit
|
351
351
|
include HappyMapper
|
352
352
|
|
353
|
-
tag
|
353
|
+
tag 'commit'
|
354
354
|
element :url, String
|
355
355
|
element :tree, String
|
356
356
|
element :message, String
|
@@ -382,10 +382,10 @@ module QuarterTest
|
|
382
382
|
# to be used for all these differently named elements is the next
|
383
383
|
# best thing
|
384
384
|
has_one :details, QuarterTest::Details
|
385
|
-
has_one :q1, QuarterTest::Quarter, :
|
386
|
-
has_one :q2, QuarterTest::Quarter, :
|
387
|
-
has_one :q3, QuarterTest::Quarter, :
|
388
|
-
has_one :q4, QuarterTest::Quarter, :
|
385
|
+
has_one :q1, QuarterTest::Quarter, tag: 'q1'
|
386
|
+
has_one :q2, QuarterTest::Quarter, tag: 'q2'
|
387
|
+
has_one :q3, QuarterTest::Quarter, tag: 'q3'
|
388
|
+
has_one :q4, QuarterTest::Quarter, tag: 'q4'
|
389
389
|
end
|
390
390
|
end
|
391
391
|
|
@@ -394,7 +394,7 @@ class Artist
|
|
394
394
|
include HappyMapper
|
395
395
|
|
396
396
|
tag 'artist'
|
397
|
-
element :images, String, :
|
397
|
+
element :images, String, tag: 'image', single: false
|
398
398
|
element :name, String
|
399
399
|
end
|
400
400
|
|
@@ -402,8 +402,8 @@ class Location
|
|
402
402
|
include HappyMapper
|
403
403
|
|
404
404
|
tag 'point'
|
405
|
-
namespace
|
406
|
-
element :latitude, String, :
|
405
|
+
namespace 'geo'
|
406
|
+
element :latitude, String, tag: 'lat'
|
407
407
|
end
|
408
408
|
|
409
409
|
# Testing the XmlContent type
|
@@ -414,7 +414,7 @@ module Dictionary
|
|
414
414
|
has_xml_content
|
415
415
|
|
416
416
|
def to_html
|
417
|
-
xml_content.gsub('<tag>','<em>').gsub('</tag>','</em>')
|
417
|
+
xml_content.gsub('<tag>', '<em>').gsub('</tag>', '</em>')
|
418
418
|
end
|
419
419
|
end
|
420
420
|
|
@@ -422,7 +422,7 @@ module Dictionary
|
|
422
422
|
include HappyMapper
|
423
423
|
|
424
424
|
tag 'def'
|
425
|
-
element :text, XmlContent, :
|
425
|
+
element :text, XmlContent, tag: 'dtext'
|
426
426
|
end
|
427
427
|
|
428
428
|
class Record
|
@@ -430,7 +430,7 @@ module Dictionary
|
|
430
430
|
|
431
431
|
tag 'record'
|
432
432
|
has_many :definitions, Definition
|
433
|
-
has_many :variants, Variant, :
|
433
|
+
has_many :variants, Variant, tag: 'var'
|
434
434
|
end
|
435
435
|
end
|
436
436
|
|
@@ -449,16 +449,15 @@ class PublishOptions
|
|
449
449
|
|
450
450
|
tag 'publishOptions'
|
451
451
|
|
452
|
-
element :author, String, :
|
453
|
-
|
454
|
-
element :draft, Boolean, :tag => 'draft'
|
455
|
-
element :scheduled_day, String, :tag => 'scheduledDay'
|
456
|
-
element :scheduled_time, String, :tag => 'scheduledTime'
|
457
|
-
element :published_day, String, :tag => 'publishDisplayDay'
|
458
|
-
element :published_time, String, :tag => 'publishDisplayTime'
|
459
|
-
element :created_day, String, :tag => 'publishDisplayDay'
|
460
|
-
element :created_time, String, :tag => 'publishDisplayTime'
|
452
|
+
element :author, String, tag: 'author'
|
461
453
|
|
454
|
+
element :draft, Boolean, tag: 'draft'
|
455
|
+
element :scheduled_day, String, tag: 'scheduledDay'
|
456
|
+
element :scheduled_time, String, tag: 'scheduledTime'
|
457
|
+
element :published_day, String, tag: 'publishDisplayDay'
|
458
|
+
element :published_time, String, tag: 'publishDisplayTime'
|
459
|
+
element :created_day, String, tag: 'publishDisplayDay'
|
460
|
+
element :created_time, String, tag: 'publishDisplayTime'
|
462
461
|
end
|
463
462
|
|
464
463
|
class Article
|
@@ -471,11 +470,10 @@ class Article
|
|
471
470
|
|
472
471
|
element :title, String
|
473
472
|
element :text, String
|
474
|
-
has_many :photos, 'Photo', :
|
475
|
-
has_many :galleries, 'Gallery', :
|
476
|
-
|
477
|
-
element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'article'
|
473
|
+
has_many :photos, 'Photo', tag: 'Photo', namespace: 'photo', xpath: '/article:Article'
|
474
|
+
has_many :galleries, 'Gallery', tag: 'Gallery', namespace: 'gallery'
|
478
475
|
|
476
|
+
element :publish_options, PublishOptions, tag: 'publishOptions', namespace: 'article'
|
479
477
|
end
|
480
478
|
|
481
479
|
class PartiallyBadArticle
|
@@ -488,11 +486,10 @@ class PartiallyBadArticle
|
|
488
486
|
|
489
487
|
element :title, String
|
490
488
|
element :text, String
|
491
|
-
has_many :photos, 'Photo', :
|
492
|
-
has_many :videos, 'Video', :
|
493
|
-
|
494
|
-
element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'article'
|
489
|
+
has_many :photos, 'Photo', tag: 'Photo', namespace: 'photo', xpath: '/article:Article'
|
490
|
+
has_many :videos, 'Video', tag: 'Video', namespace: 'video'
|
495
491
|
|
492
|
+
element :publish_options, PublishOptions, tag: 'publishOptions', namespace: 'article'
|
496
493
|
end
|
497
494
|
|
498
495
|
class Photo
|
@@ -504,8 +501,7 @@ class Photo
|
|
504
501
|
attr_writer :xml_value
|
505
502
|
|
506
503
|
element :title, String
|
507
|
-
element :publish_options, PublishOptions, :
|
508
|
-
|
504
|
+
element :publish_options, PublishOptions, tag: 'publishOptions', namespace: 'photo'
|
509
505
|
end
|
510
506
|
|
511
507
|
class Gallery
|
@@ -517,7 +513,6 @@ class Gallery
|
|
517
513
|
attr_writer :xml_value
|
518
514
|
|
519
515
|
element :title, String
|
520
|
-
|
521
516
|
end
|
522
517
|
|
523
518
|
class Video
|
@@ -529,8 +524,7 @@ class Video
|
|
529
524
|
attr_writer :xml_value
|
530
525
|
|
531
526
|
element :title, String
|
532
|
-
element :publish_options, PublishOptions, :
|
533
|
-
|
527
|
+
element :publish_options, PublishOptions, tag: 'publishOptions', namespace: 'video'
|
534
528
|
end
|
535
529
|
|
536
530
|
class OptionalAttribute
|
@@ -543,78 +537,73 @@ end
|
|
543
537
|
class DefaultNamespaceCombi
|
544
538
|
include HappyMapper
|
545
539
|
|
546
|
-
|
547
|
-
register_namespace '
|
548
|
-
register_namespace '
|
549
|
-
register_namespace 'p', "urn:loc.gov:people"
|
540
|
+
register_namespace 'bk', 'urn:loc.gov:books'
|
541
|
+
register_namespace 'isbn', 'urn:ISBN:0-395-36341-6'
|
542
|
+
register_namespace 'p', 'urn:loc.gov:people'
|
550
543
|
namespace 'bk'
|
551
544
|
|
552
545
|
tag 'book'
|
553
546
|
|
554
|
-
element :title, String, :
|
555
|
-
element :number, String, :
|
556
|
-
element :author, String, :
|
547
|
+
element :title, String, namespace: 'bk', tag: 'title'
|
548
|
+
element :number, String, namespace: 'isbn', tag: 'number'
|
549
|
+
element :author, String, namespace: 'p', tag: 'author'
|
557
550
|
end
|
558
551
|
|
559
552
|
describe HappyMapper do
|
560
|
-
|
561
|
-
describe "being included into another class" do
|
553
|
+
describe 'being included into another class' do
|
562
554
|
before do
|
563
555
|
@klass = Class.new do
|
564
556
|
include HappyMapper
|
565
557
|
|
566
|
-
def self.
|
558
|
+
def self.name
|
567
559
|
'Boo'
|
568
560
|
end
|
569
561
|
end
|
570
562
|
end
|
571
563
|
|
572
|
-
|
573
|
-
|
574
|
-
it "should set attributes to an array" do
|
564
|
+
it 'should set attributes to an array' do
|
575
565
|
expect(@klass.attributes).to eq([])
|
576
566
|
end
|
577
567
|
|
578
|
-
it
|
568
|
+
it 'should set @elements to a hash' do
|
579
569
|
expect(@klass.elements).to eq([])
|
580
570
|
end
|
581
571
|
|
582
|
-
it
|
583
|
-
expect
|
572
|
+
it 'should allow adding an attribute' do
|
573
|
+
expect do
|
584
574
|
@klass.attribute :name, String
|
585
|
-
|
575
|
+
end.to change(@klass, :attributes)
|
586
576
|
end
|
587
577
|
|
588
|
-
it
|
589
|
-
expect
|
578
|
+
it 'should allow adding an attribute containing a dash' do
|
579
|
+
expect do
|
590
580
|
@klass.attribute :'bar-baz', String
|
591
|
-
|
581
|
+
end.to change(@klass, :attributes)
|
592
582
|
end
|
593
583
|
|
594
|
-
it
|
584
|
+
it 'should be able to get all attributes in array' do
|
595
585
|
@klass.attribute :name, String
|
596
586
|
expect(@klass.attributes.size).to eq(1)
|
597
587
|
end
|
598
588
|
|
599
|
-
it
|
600
|
-
expect
|
589
|
+
it 'should allow adding an element' do
|
590
|
+
expect do
|
601
591
|
@klass.element :name, String
|
602
|
-
|
592
|
+
end.to change(@klass, :elements)
|
603
593
|
end
|
604
594
|
|
605
|
-
it
|
606
|
-
expect
|
595
|
+
it 'should allow adding an element containing a dash' do
|
596
|
+
expect do
|
607
597
|
@klass.element :'bar-baz', String
|
608
|
-
|
609
|
-
|
598
|
+
end.to change(@klass, :elements)
|
610
599
|
end
|
611
600
|
|
612
|
-
it
|
601
|
+
it 'should be able to get all elements in array' do
|
613
602
|
@klass.element(:name, String)
|
614
603
|
expect(@klass.elements.size).to eq(1)
|
615
604
|
end
|
616
605
|
|
617
|
-
it
|
606
|
+
it 'should allow has one association' do
|
618
607
|
@klass.has_one(:user, User)
|
619
608
|
element = @klass.elements.first
|
620
609
|
expect(element.name).to eq('user')
|
@@ -622,7 +611,7 @@ describe HappyMapper do
|
|
622
611
|
expect(element.options[:single]).to eq(true)
|
623
612
|
end
|
624
613
|
|
625
|
-
it
|
614
|
+
it 'should allow has many association' do
|
626
615
|
@klass.has_many(:users, User)
|
627
616
|
element = @klass.elements.first
|
628
617
|
expect(element.name).to eq('users')
|
@@ -630,62 +619,67 @@ describe HappyMapper do
|
|
630
619
|
expect(element.options[:single]).to eq(false)
|
631
620
|
end
|
632
621
|
|
633
|
-
it
|
622
|
+
it 'should default tag name to lowercase class' do
|
634
623
|
expect(@klass.tag_name).to eq('boo')
|
635
624
|
end
|
636
625
|
|
637
|
-
it
|
626
|
+
it 'generates no tag name for anonymous class' do
|
627
|
+
@anon = Class.new { include HappyMapper }
|
628
|
+
expect(@anon.tag_name).to be_nil
|
629
|
+
end
|
630
|
+
|
631
|
+
it 'should default tag name of class in modules to the last constant lowercase' do
|
638
632
|
module Bar; class Baz; include HappyMapper; end; end
|
639
633
|
expect(Bar::Baz.tag_name).to eq('baz')
|
640
634
|
end
|
641
635
|
|
642
|
-
it
|
636
|
+
it 'should allow setting tag name' do
|
643
637
|
@klass.tag('FooBar')
|
644
638
|
expect(@klass.tag_name).to eq('FooBar')
|
645
639
|
end
|
646
640
|
|
647
|
-
it
|
648
|
-
@klass.namespace(namespace =
|
641
|
+
it 'should allow setting a namespace' do
|
642
|
+
@klass.namespace(namespace = 'boo')
|
649
643
|
expect(@klass.namespace).to eq(namespace)
|
650
644
|
end
|
651
645
|
|
652
|
-
it
|
646
|
+
it 'should provide #parse' do
|
653
647
|
expect(@klass).to respond_to(:parse)
|
654
648
|
end
|
655
649
|
end
|
656
650
|
|
657
|
-
describe
|
658
|
-
it
|
651
|
+
describe '#attributes' do
|
652
|
+
it 'should only return attributes for the current class' do
|
659
653
|
expect(Post.attributes.size).to eq(7)
|
660
654
|
expect(Status.attributes.size).to eq(0)
|
661
655
|
end
|
662
656
|
end
|
663
657
|
|
664
|
-
describe
|
665
|
-
it
|
658
|
+
describe '#elements' do
|
659
|
+
it 'should only return elements for the current class' do
|
666
660
|
expect(Post.elements.size).to eq(0)
|
667
661
|
expect(Status.elements.size).to eq(10)
|
668
662
|
end
|
669
663
|
end
|
670
664
|
|
671
|
-
describe
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
665
|
+
describe '#content' do
|
666
|
+
it 'should take String as default argument for type' do
|
667
|
+
State.content :name
|
668
|
+
address = Address.parse(fixture_file('address.xml'))
|
669
|
+
expect(address.state.name).to eq('Lower Saxony')
|
670
|
+
address.state.name.class == String
|
671
|
+
end
|
678
672
|
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
673
|
+
it 'should work when specific type is provided' do
|
674
|
+
Rate.content :value, Float
|
675
|
+
Product.has_one :rate, Rate
|
676
|
+
product = Product.parse(fixture_file('product_default_namespace.xml'), single: true)
|
677
|
+
expect(product.rate.value).to eq(120.25)
|
678
|
+
product.rate.class == Float
|
679
|
+
end
|
686
680
|
end
|
687
681
|
|
688
|
-
it
|
682
|
+
it 'should parse xml attributes into ruby objects' do
|
689
683
|
posts = Post.parse(fixture_file('posts.xml'))
|
690
684
|
expect(posts.size).to eq(20)
|
691
685
|
first = posts.first
|
@@ -695,10 +689,15 @@ describe HappyMapper do
|
|
695
689
|
expect(first.tag).to eq('ruby xml gems mapping')
|
696
690
|
expect(first.time).to eq(Time.utc(2008, 8, 9, 5, 24, 20))
|
697
691
|
expect(first.others).to eq(56)
|
698
|
-
expect(first.extended).
|
692
|
+
expect(first.extended).
|
693
|
+
to eq('ROXML is a Ruby library designed to make it easier for Ruby' \
|
694
|
+
' developers to work with XML. Using simple annotations, it enables' \
|
695
|
+
' Ruby classes to be custom-mapped to XML. ROXML takes care of the' \
|
696
|
+
' marshalling and unmarshalling of mapped attributes so that developers can' \
|
697
|
+
' focus on building first-class Ruby classes.')
|
699
698
|
end
|
700
699
|
|
701
|
-
it
|
700
|
+
it 'should parse xml elements to ruby objcts' do
|
702
701
|
statuses = Status.parse(fixture_file('statuses.xml'))
|
703
702
|
expect(statuses.size).to eq(20)
|
704
703
|
first = statuses.first
|
@@ -714,14 +713,15 @@ describe HappyMapper do
|
|
714
713
|
expect(first.user.screen_name).to eq('jnunemaker')
|
715
714
|
expect(first.user.location).to eq('Mishawaka, IN, US')
|
716
715
|
expect(first.user.description).to eq('Loves his wife, ruby, notre dame football and iu basketball')
|
717
|
-
expect(first.user.profile_image_url).
|
716
|
+
expect(first.user.profile_image_url).
|
717
|
+
to eq('http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg')
|
718
718
|
expect(first.user.url).to eq('http://addictedtonew.com')
|
719
719
|
expect(first.user.protected).to be_falsey
|
720
720
|
expect(first.user.followers_count).to eq(486)
|
721
721
|
end
|
722
722
|
|
723
|
-
it
|
724
|
-
address = Address.parse(fixture_file('address.xml'), :
|
723
|
+
it 'should parse xml containing the desired element as root node' do
|
724
|
+
address = Address.parse(fixture_file('address.xml'), single: true)
|
725
725
|
expect(address.street).to eq('Milchstrasse')
|
726
726
|
expect(address.postcode).to eq('26131')
|
727
727
|
expect(address.housenumber).to eq('23')
|
@@ -729,21 +729,21 @@ describe HappyMapper do
|
|
729
729
|
expect(address.country.class).to eq(Country)
|
730
730
|
end
|
731
731
|
|
732
|
-
it
|
733
|
-
address = Address.parse(fixture_file('address.xml'), :
|
732
|
+
it 'should parse text node correctly' do
|
733
|
+
address = Address.parse(fixture_file('address.xml'), single: true)
|
734
734
|
expect(address.country.name).to eq('Germany')
|
735
735
|
expect(address.country.code).to eq('de')
|
736
736
|
end
|
737
737
|
|
738
|
-
it
|
738
|
+
it 'should treat Nokogiri::XML::Document as root' do
|
739
739
|
doc = Nokogiri::XML(fixture_file('address.xml'))
|
740
740
|
address = Address.parse(doc)
|
741
741
|
expect(address.class).to eq(Address)
|
742
742
|
end
|
743
743
|
|
744
|
-
it
|
744
|
+
it 'should parse xml with default namespace (amazon)' do
|
745
745
|
file_contents = fixture_file('pita.xml')
|
746
|
-
items = PITA::Items.parse(file_contents, :
|
746
|
+
items = PITA::Items.parse(file_contents, single: true)
|
747
747
|
expect(items.total_results).to eq(22)
|
748
748
|
expect(items.total_pages).to eq(3)
|
749
749
|
first = items.items[0]
|
@@ -758,7 +758,7 @@ describe HappyMapper do
|
|
758
758
|
expect(second.manufacturer).to eq('Wrox')
|
759
759
|
end
|
760
760
|
|
761
|
-
it
|
761
|
+
it 'should parse xml that has attributes of elements' do
|
762
762
|
items = CurrentWeather.parse(fixture_file('current_weather.xml'))
|
763
763
|
first = items[0]
|
764
764
|
expect(first.temperature).to eq(51)
|
@@ -773,22 +773,22 @@ describe HappyMapper do
|
|
773
773
|
expect(feed.link.last.href).to eq('http://www.example.com/tv_shows.atom')
|
774
774
|
end
|
775
775
|
|
776
|
-
it
|
777
|
-
expect { CurrentWeather.parse(fixture_file('current_weather_missing_elements.xml')) }.to_not raise_error
|
776
|
+
it 'parses xml with optional elements with embedded attributes' do
|
777
|
+
expect { CurrentWeather.parse(fixture_file('current_weather_missing_elements.xml')) }.to_not raise_error
|
778
778
|
end
|
779
779
|
|
780
|
-
it
|
781
|
-
address = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', :
|
780
|
+
it 'returns nil rather than empty array for absent values when :single => true' do
|
781
|
+
address = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', single: true)
|
782
782
|
expect(address).to be_nil
|
783
783
|
end
|
784
784
|
|
785
|
-
it
|
786
|
-
addr1 = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', :
|
787
|
-
addr2 = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', :
|
785
|
+
it 'should return same result for absent values when :single => true, regardless of :in_groups_of' do
|
786
|
+
addr1 = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', single: true)
|
787
|
+
addr2 = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', single: true, in_groups_of: 10)
|
788
788
|
expect(addr1).to eq(addr2)
|
789
789
|
end
|
790
790
|
|
791
|
-
it
|
791
|
+
it 'should parse xml with nested elements' do
|
792
792
|
radars = Radar.parse(fixture_file('radar.xml'))
|
793
793
|
first = radars[0]
|
794
794
|
expect(first.places.size).to eq(1)
|
@@ -801,49 +801,49 @@ describe HappyMapper do
|
|
801
801
|
expect(third.places[1].name).to eq('Home')
|
802
802
|
end
|
803
803
|
|
804
|
-
it
|
804
|
+
it 'should parse xml with element name different to class name' do
|
805
805
|
game = QuarterTest::Game.parse(fixture_file('quarters.xml'))
|
806
806
|
expect(game.q1.start).to eq('4:40:15 PM')
|
807
807
|
expect(game.q2.start).to eq('5:18:53 PM')
|
808
808
|
end
|
809
809
|
|
810
|
-
it
|
810
|
+
it 'should parse xml that has elements with dashes' do
|
811
811
|
commit = GitHub::Commit.parse(fixture_file('commit.xml'))
|
812
|
-
expect(commit.message).to eq(
|
813
|
-
expect(commit.url).to eq(
|
814
|
-
expect(commit.id).to eq(
|
815
|
-
expect(commit.committed_date).to eq(Date.parse(
|
816
|
-
expect(commit.tree).to eq(
|
812
|
+
expect(commit.message).to eq('move commands.rb and helpers.rb into commands/ dir')
|
813
|
+
expect(commit.url).to eq('http://github.com/defunkt/github-gem/commit/c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b')
|
814
|
+
expect(commit.id).to eq('c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b')
|
815
|
+
expect(commit.committed_date).to eq(Date.parse('2008-03-02T16:45:41-08:00'))
|
816
|
+
expect(commit.tree).to eq('28a1a1ca3e663d35ba8bf07d3f1781af71359b76')
|
817
817
|
end
|
818
818
|
|
819
|
-
it
|
820
|
-
product = Product.parse(fixture_file('product_no_namespace.xml'), :
|
821
|
-
expect(product.title).to eq(
|
819
|
+
it 'should parse xml with no namespace' do
|
820
|
+
product = Product.parse(fixture_file('product_no_namespace.xml'), single: true)
|
821
|
+
expect(product.title).to eq('A Title')
|
822
822
|
expect(product.feature_bullets.bug).to eq('This is a bug')
|
823
823
|
expect(product.feature_bullets.features.size).to eq(2)
|
824
824
|
expect(product.feature_bullets.features[0].name).to eq('This is feature text 1')
|
825
825
|
expect(product.feature_bullets.features[1].name).to eq('This is feature text 2')
|
826
826
|
end
|
827
827
|
|
828
|
-
it
|
829
|
-
product = Product.parse(fixture_file('product_default_namespace.xml'), :
|
830
|
-
expect(product.title).to eq(
|
828
|
+
it 'should parse xml with default namespace' do
|
829
|
+
product = Product.parse(fixture_file('product_default_namespace.xml'), single: true)
|
830
|
+
expect(product.title).to eq('A Title')
|
831
831
|
expect(product.feature_bullets.bug).to eq('This is a bug')
|
832
832
|
expect(product.feature_bullets.features.size).to eq(2)
|
833
833
|
expect(product.feature_bullets.features[0].name).to eq('This is feature text 1')
|
834
834
|
expect(product.feature_bullets.features[1].name).to eq('This is feature text 2')
|
835
835
|
end
|
836
836
|
|
837
|
-
it
|
838
|
-
product = Product.parse(fixture_file('product_single_namespace.xml'), :
|
839
|
-
expect(product.title).to eq(
|
837
|
+
it 'should parse xml with single namespace' do
|
838
|
+
product = Product.parse(fixture_file('product_single_namespace.xml'), single: true)
|
839
|
+
expect(product.title).to eq('A Title')
|
840
840
|
expect(product.feature_bullets.bug).to eq('This is a bug')
|
841
841
|
expect(product.feature_bullets.features.size).to eq(2)
|
842
842
|
expect(product.feature_bullets.features[0].name).to eq('This is feature text 1')
|
843
843
|
expect(product.feature_bullets.features[1].name).to eq('This is feature text 2')
|
844
844
|
end
|
845
845
|
|
846
|
-
it
|
846
|
+
it 'should parse xml with multiple namespaces' do
|
847
847
|
track = FedEx::TrackReply.parse(fixture_file('multiple_namespaces.xml'))
|
848
848
|
expect(track.highest_severity).to eq('SUCCESS')
|
849
849
|
expect(track.more_data).to be_falsey
|
@@ -885,7 +885,7 @@ describe HappyMapper do
|
|
885
885
|
expect(track.tran_detail.cust_tran_id).to eq('20090102-111321')
|
886
886
|
end
|
887
887
|
|
888
|
-
it
|
888
|
+
it 'should be able to parse google analytics api xml' do
|
889
889
|
data = Analytics::Feed.parse(fixture_file('analytics.xml'))
|
890
890
|
expect(data.id).to eq('http://www.google.com/analytics/feeds/accounts/nunemaker@gmail.com')
|
891
891
|
expect(data.entries.size).to eq(4)
|
@@ -899,7 +899,7 @@ describe HappyMapper do
|
|
899
899
|
expect(property.value).to eq('85301')
|
900
900
|
end
|
901
901
|
|
902
|
-
it
|
902
|
+
it 'should be able to parse google analytics profile xml with manually declared namespace' do
|
903
903
|
data = Analytics::Profile.parse(fixture_file('analytics_profile.xml'))
|
904
904
|
expect(data.entries.size).to eq(6)
|
905
905
|
|
@@ -909,7 +909,7 @@ describe HappyMapper do
|
|
909
909
|
expect(entry.goals.size).to eq(0)
|
910
910
|
end
|
911
911
|
|
912
|
-
it
|
912
|
+
it 'should allow instantiating with a string' do
|
913
913
|
module StringFoo
|
914
914
|
class Bar
|
915
915
|
include HappyMapper
|
@@ -922,67 +922,65 @@ describe HappyMapper do
|
|
922
922
|
end
|
923
923
|
end
|
924
924
|
|
925
|
-
it
|
925
|
+
it 'should parse family search xml' do
|
926
926
|
tree = FamilySearch::FamilyTree.parse(fixture_file('family_tree.xml'))
|
927
927
|
expect(tree.version).to eq('1.0.20071213.942')
|
928
928
|
expect(tree.status_message).to eq('OK')
|
929
929
|
expect(tree.status_code).to eq('200')
|
930
930
|
expect(tree.persons.person.size).to eq(1)
|
931
931
|
expect(tree.persons.person.first.version).to eq('1199378491000')
|
932
|
-
expect(tree.persons.person.first.modified).
|
932
|
+
expect(tree.persons.person.first.modified).
|
933
|
+
to eq(Time.utc(2008, 1, 3, 16, 41, 31)) # 2008-01-03T09:41:31-07:00
|
933
934
|
expect(tree.persons.person.first.id).to eq('KWQS-BBQ')
|
934
935
|
expect(tree.persons.person.first.information.alternateIds.ids).not_to be_kind_of(String)
|
935
936
|
expect(tree.persons.person.first.information.alternateIds.ids.size).to eq(8)
|
936
937
|
end
|
937
938
|
|
938
|
-
it
|
939
|
+
it 'should parse multiple images' do
|
939
940
|
artist = Artist.parse(fixture_file('multiple_primitives.xml'))
|
940
|
-
expect(artist.name).to eq(
|
941
|
+
expect(artist.name).to eq('value')
|
941
942
|
expect(artist.images.size).to eq(2)
|
942
943
|
end
|
943
944
|
|
944
|
-
it
|
945
|
+
it 'should parse lastfm namespaces' do
|
945
946
|
l = Location.parse(fixture_file('lastfm.xml'))
|
946
|
-
expect(l.first.latitude).to eq(
|
947
|
+
expect(l.first.latitude).to eq('51.53469')
|
947
948
|
end
|
948
949
|
|
949
|
-
describe
|
950
|
-
|
951
|
-
it "should parse an empty String as empty" do
|
950
|
+
describe 'Parse optional attributes' do
|
951
|
+
it 'should parse an empty String as empty' do
|
952
952
|
a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
|
953
|
-
expect(a[0].street).to eq(
|
953
|
+
expect(a[0].street).to eq('')
|
954
954
|
end
|
955
955
|
|
956
|
-
it
|
956
|
+
it 'should parse a String with value' do
|
957
957
|
a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
|
958
|
-
expect(a[1].street).to eq(
|
958
|
+
expect(a[1].street).to eq('Milchstrasse')
|
959
959
|
end
|
960
960
|
|
961
|
-
it
|
961
|
+
it 'should parse a String with value' do
|
962
962
|
a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
|
963
963
|
expect(a[2].street).to be_nil
|
964
964
|
end
|
965
|
-
|
966
965
|
end
|
967
966
|
|
968
|
-
describe
|
967
|
+
describe 'Default namespace combi' do
|
969
968
|
before(:each) do
|
970
969
|
file_contents = fixture_file('default_namespace_combi.xml')
|
971
|
-
@book = DefaultNamespaceCombi.parse(file_contents, :
|
970
|
+
@book = DefaultNamespaceCombi.parse(file_contents, single: true)
|
972
971
|
end
|
973
972
|
|
974
|
-
it
|
975
|
-
expect(@book.author).to eq(
|
973
|
+
it 'should parse author' do
|
974
|
+
expect(@book.author).to eq('Frank Gilbreth')
|
976
975
|
end
|
977
976
|
|
978
|
-
it
|
979
|
-
expect(@book.title).to eq(
|
977
|
+
it 'should parse title' do
|
978
|
+
expect(@book.title).to eq('Cheaper by the Dozen')
|
980
979
|
end
|
981
980
|
|
982
|
-
it
|
983
|
-
expect(@book.number).to eq(
|
981
|
+
it 'should parse number' do
|
982
|
+
expect(@book.number).to eq('1568491379')
|
984
983
|
end
|
985
|
-
|
986
984
|
end
|
987
985
|
|
988
986
|
describe 'Xml Content' do
|
@@ -991,10 +989,12 @@ describe HappyMapper do
|
|
991
989
|
@records = Dictionary::Record.parse(file_contents)
|
992
990
|
end
|
993
991
|
|
994
|
-
it
|
995
|
-
expect(@records.first.definitions.first.text).
|
996
|
-
'a large common parrot, <bn>Cacatua galerita</bn>, predominantly
|
997
|
-
|
992
|
+
it 'should parse XmlContent' do
|
993
|
+
expect(@records.first.definitions.first.text).
|
994
|
+
to eq('a large common parrot, <bn>Cacatua galerita</bn>, predominantly' \
|
995
|
+
' white, with yellow on the undersides of wings and tail and a' \
|
996
|
+
' forward curving yellow crest, found in Australia, New Guinea' \
|
997
|
+
' and nearby islands.')
|
998
998
|
end
|
999
999
|
|
1000
1000
|
it "should save object's xml content" do
|
@@ -1007,91 +1007,87 @@ describe HappyMapper do
|
|
1007
1007
|
end
|
1008
1008
|
end
|
1009
1009
|
|
1010
|
-
it
|
1011
|
-
items = AmbigousItems::Item.parse(fixture_file('ambigous_items.xml'), :
|
1012
|
-
expect(items.map(&:name)).to eq(%w(first second third).map{|s| "My #{s} item" })
|
1010
|
+
it 'should parse ambigous items' do
|
1011
|
+
items = AmbigousItems::Item.parse(fixture_file('ambigous_items.xml'), xpath: '/ambigous/my-items')
|
1012
|
+
expect(items.map(&:name)).to eq(%w(first second third).map { |s| "My #{s} item" })
|
1013
1013
|
end
|
1014
1014
|
|
1015
|
-
|
1016
1015
|
context Article do
|
1017
|
-
it
|
1016
|
+
it 'should parse the publish options for Article and Photo' do
|
1018
1017
|
expect(@article.title).not_to be_nil
|
1019
1018
|
expect(@article.text).not_to be_nil
|
1020
1019
|
expect(@article.photos).not_to be_nil
|
1021
1020
|
expect(@article.photos.first.title).not_to be_nil
|
1022
1021
|
end
|
1023
1022
|
|
1024
|
-
it
|
1023
|
+
it 'should parse the publish options for Article' do
|
1025
1024
|
expect(@article.publish_options).not_to be_nil
|
1026
1025
|
end
|
1027
1026
|
|
1028
|
-
it
|
1027
|
+
it 'should parse the publish options for Photo' do
|
1029
1028
|
expect(@article.photos.first.publish_options).not_to be_nil
|
1030
1029
|
end
|
1031
1030
|
|
1032
|
-
it
|
1031
|
+
it 'should only find only items at the parent level' do
|
1033
1032
|
expect(@article.photos.length).to eq(1)
|
1034
1033
|
end
|
1035
1034
|
|
1036
1035
|
before(:all) do
|
1037
1036
|
@article = Article.parse(fixture_file('subclass_namespace.xml'))
|
1038
1037
|
end
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
context 'Namespace is missing because an optional element that uses it is not present' do
|
1041
|
+
it 'should parse successfully' do
|
1042
|
+
@article = PartiallyBadArticle.parse(fixture_file('subclass_namespace.xml'))
|
1043
|
+
expect(@article).not_to be_nil
|
1044
|
+
expect(@article.title).not_to be_nil
|
1045
|
+
expect(@article.text).not_to be_nil
|
1046
|
+
expect(@article.photos).not_to be_nil
|
1047
|
+
expect(@article.photos.first.title).not_to be_nil
|
1048
|
+
end
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
describe 'with limit option' do
|
1052
|
+
it 'should return results with limited size: 6' do
|
1053
|
+
sizes = []
|
1054
|
+
Post.parse(fixture_file('posts.xml'), in_groups_of: 6) do |a|
|
1055
|
+
sizes << a.size
|
1056
|
+
end
|
1057
|
+
expect(sizes).to eq([6, 6, 6, 2])
|
1058
|
+
end
|
1039
1059
|
|
1060
|
+
it 'should return results with limited size: 10' do
|
1061
|
+
sizes = []
|
1062
|
+
Post.parse(fixture_file('posts.xml'), in_groups_of: 10) do |a|
|
1063
|
+
sizes << a.size
|
1064
|
+
end
|
1065
|
+
expect(sizes).to eq([10, 10])
|
1066
|
+
end
|
1040
1067
|
end
|
1041
1068
|
|
1042
|
-
context
|
1043
|
-
|
1044
|
-
@article = PartiallyBadArticle.parse(fixture_file('subclass_namespace.xml'))
|
1045
|
-
expect(@article).not_to be_nil
|
1046
|
-
expect(@article.title).not_to be_nil
|
1047
|
-
expect(@article.text).not_to be_nil
|
1048
|
-
expect(@article.photos).not_to be_nil
|
1049
|
-
expect(@article.photos.first.title).not_to be_nil
|
1050
|
-
end
|
1051
|
-
end
|
1052
|
-
|
1053
|
-
|
1054
|
-
describe "with limit option" do
|
1055
|
-
it "should return results with limited size: 6" do
|
1056
|
-
sizes = []
|
1057
|
-
Post.parse(fixture_file('posts.xml'), :in_groups_of => 6) do |a|
|
1058
|
-
sizes << a.size
|
1059
|
-
end
|
1060
|
-
expect(sizes).to eq([6, 6, 6, 2])
|
1061
|
-
end
|
1062
|
-
|
1063
|
-
it "should return results with limited size: 10" do
|
1064
|
-
sizes = []
|
1065
|
-
Post.parse(fixture_file('posts.xml'), :in_groups_of => 10) do |a|
|
1066
|
-
sizes << a.size
|
1067
|
-
end
|
1068
|
-
expect(sizes).to eq([10, 10])
|
1069
|
-
end
|
1070
|
-
end
|
1071
|
-
|
1072
|
-
context "when letting user set Nokogiri::XML::ParseOptions" do
|
1073
|
-
let(:default) {
|
1069
|
+
context 'when letting user set Nokogiri::XML::ParseOptions' do
|
1070
|
+
let(:default) do
|
1074
1071
|
Class.new do
|
1075
1072
|
include HappyMapper
|
1076
1073
|
element :item, String
|
1077
1074
|
end
|
1078
|
-
|
1079
|
-
let(:custom)
|
1075
|
+
end
|
1076
|
+
let(:custom) do
|
1080
1077
|
Class.new do
|
1081
1078
|
include HappyMapper
|
1082
1079
|
element :item, String
|
1083
|
-
with_nokogiri_config
|
1084
|
-
config.default_xml
|
1085
|
-
end
|
1080
|
+
with_nokogiri_config(&:default_xml)
|
1086
1081
|
end
|
1087
|
-
|
1082
|
+
end
|
1088
1083
|
|
1089
1084
|
it 'initializes @nokogiri_config_callback to nil' do
|
1090
1085
|
expect(default.nokogiri_config_callback).to be_nil
|
1091
1086
|
end
|
1092
1087
|
|
1093
1088
|
it 'defaults to Nokogiri::XML::ParseOptions::STRICT' do
|
1094
|
-
|
1089
|
+
expect { default.parse(fixture_file('set_config_options.xml')) }.
|
1090
|
+
to raise_error(Nokogiri::XML::SyntaxError)
|
1095
1091
|
end
|
1096
1092
|
|
1097
1093
|
it 'accepts .on_config callback' do
|
@@ -1104,7 +1100,8 @@ describe HappyMapper do
|
|
1104
1100
|
|
1105
1101
|
it 'can clear @nokogiri_config_callback' do
|
1106
1102
|
custom.with_nokogiri_config {}
|
1107
|
-
expect { custom.parse(fixture_file('set_config_options.xml')) }.
|
1103
|
+
expect { custom.parse(fixture_file('set_config_options.xml')) }.
|
1104
|
+
to raise_error(Nokogiri::XML::SyntaxError)
|
1108
1105
|
end
|
1109
1106
|
end
|
1110
1107
|
|
@@ -1113,7 +1110,8 @@ describe HappyMapper do
|
|
1113
1110
|
xml = fixture_file('unformatted_address.xml')
|
1114
1111
|
address = Address.parse(xml, single: true)
|
1115
1112
|
|
1116
|
-
expect(address.xml_value).
|
1113
|
+
expect(address.xml_value).
|
1114
|
+
to eq %(<address><street>Milchstrasse</street><housenumber>23</housenumber></address>)
|
1117
1115
|
end
|
1118
1116
|
end
|
1119
1117
|
|
@@ -1122,8 +1120,17 @@ describe HappyMapper do
|
|
1122
1120
|
xml = fixture_file('unformatted_address.xml')
|
1123
1121
|
address = Address.parse(xml)
|
1124
1122
|
|
1125
|
-
expect(address.xml_content).to eq %
|
1123
|
+
expect(address.xml_content).to eq %(<street>Milchstrasse</street><housenumber>23</housenumber>)
|
1126
1124
|
end
|
1127
1125
|
end
|
1128
1126
|
|
1127
|
+
describe '#to_xml' do
|
1128
|
+
let(:original) { '<foo><bar>baz</bar></foo>' }
|
1129
|
+
let(:parsed) { described_class.parse original }
|
1130
|
+
|
1131
|
+
it 'has UTF-8 encoding by default' do
|
1132
|
+
expect(original.encoding).to eq Encoding::UTF_8
|
1133
|
+
expect(parsed.to_xml.encoding).to eq Encoding::UTF_8
|
1134
|
+
end
|
1135
|
+
end
|
1129
1136
|
end
|