nokogiri-happymapper 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|