yob-roxml 3.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +7 -0
- data/.gitmodules +3 -0
- data/History.txt +354 -0
- data/LICENSE +20 -0
- data/README.rdoc +195 -0
- data/Rakefile +117 -0
- data/TODO +37 -0
- data/VERSION +1 -0
- data/examples/amazon.rb +35 -0
- data/examples/current_weather.rb +27 -0
- data/examples/dashed_elements.rb +20 -0
- data/examples/library.rb +40 -0
- data/examples/posts.rb +27 -0
- data/examples/rails.rb +70 -0
- data/examples/twitter.rb +37 -0
- data/examples/xml/active_record.xml +70 -0
- data/examples/xml/amazon.xml +133 -0
- data/examples/xml/current_weather.xml +89 -0
- data/examples/xml/dashed_elements.xml +52 -0
- data/examples/xml/posts.xml +23 -0
- data/examples/xml/twitter.xml +422 -0
- data/lib/roxml.rb +556 -0
- data/lib/roxml/definition.rb +238 -0
- data/lib/roxml/hash_definition.rb +25 -0
- data/lib/roxml/xml.rb +40 -0
- data/lib/roxml/xml/parsers/libxml.rb +85 -0
- data/lib/roxml/xml/parsers/nokogiri.rb +82 -0
- data/lib/roxml/xml/references.rb +322 -0
- data/roxml.gemspec +206 -0
- data/spec/definition_spec.rb +494 -0
- data/spec/examples/active_record_spec.rb +40 -0
- data/spec/examples/amazon_spec.rb +54 -0
- data/spec/examples/current_weather_spec.rb +37 -0
- data/spec/examples/dashed_elements_spec.rb +20 -0
- data/spec/examples/library_spec.rb +46 -0
- data/spec/examples/post_spec.rb +24 -0
- data/spec/examples/twitter_spec.rb +32 -0
- data/spec/roxml_spec.rb +372 -0
- data/spec/shared_specs.rb +15 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/libxml.rb +3 -0
- data/spec/support/nokogiri.rb +3 -0
- data/spec/xml/array_spec.rb +36 -0
- data/spec/xml/attributes_spec.rb +71 -0
- data/spec/xml/encoding_spec.rb +52 -0
- data/spec/xml/namespace_spec.rb +270 -0
- data/spec/xml/namespaces_spec.rb +67 -0
- data/spec/xml/object_spec.rb +82 -0
- data/spec/xml/parser_spec.rb +21 -0
- data/spec/xml/text_spec.rb +71 -0
- data/test/fixtures/book_malformed.xml +5 -0
- data/test/fixtures/book_pair.xml +8 -0
- data/test/fixtures/book_text_with_attribute.xml +5 -0
- data/test/fixtures/book_valid.xml +5 -0
- data/test/fixtures/book_with_authors.xml +7 -0
- data/test/fixtures/book_with_contributions.xml +9 -0
- data/test/fixtures/book_with_contributors.xml +7 -0
- data/test/fixtures/book_with_contributors_attrs.xml +7 -0
- data/test/fixtures/book_with_default_namespace.xml +9 -0
- data/test/fixtures/book_with_depth.xml +6 -0
- data/test/fixtures/book_with_octal_pages.xml +4 -0
- data/test/fixtures/book_with_publisher.xml +7 -0
- data/test/fixtures/book_with_wrapped_attr.xml +3 -0
- data/test/fixtures/dictionary_of_attr_name_clashes.xml +8 -0
- data/test/fixtures/dictionary_of_attrs.xml +6 -0
- data/test/fixtures/dictionary_of_guarded_names.xml +6 -0
- data/test/fixtures/dictionary_of_mixeds.xml +4 -0
- data/test/fixtures/dictionary_of_name_clashes.xml +10 -0
- data/test/fixtures/dictionary_of_names.xml +4 -0
- data/test/fixtures/dictionary_of_texts.xml +10 -0
- data/test/fixtures/library.xml +30 -0
- data/test/fixtures/library_uppercase.xml +30 -0
- data/test/fixtures/muffins.xml +3 -0
- data/test/fixtures/nameless_ageless_youth.xml +2 -0
- data/test/fixtures/node_with_attr_name_conflicts.xml +1 -0
- data/test/fixtures/node_with_name_conflicts.xml +4 -0
- data/test/fixtures/numerology.xml +4 -0
- data/test/fixtures/person.xml +1 -0
- data/test/fixtures/person_with_guarded_mothers.xml +13 -0
- data/test/fixtures/person_with_mothers.xml +10 -0
- data/test/load_test.rb +6 -0
- data/test/mocks/dictionaries.rb +57 -0
- data/test/mocks/mocks.rb +279 -0
- data/test/support/fixtures.rb +11 -0
- data/test/test_helper.rb +34 -0
- data/test/unit/definition_test.rb +235 -0
- data/test/unit/deprecations_test.rb +24 -0
- data/test/unit/to_xml_test.rb +81 -0
- data/test/unit/xml_attribute_test.rb +39 -0
- data/test/unit/xml_block_test.rb +81 -0
- data/test/unit/xml_bool_test.rb +122 -0
- data/test/unit/xml_convention_test.rb +150 -0
- data/test/unit/xml_hash_test.rb +115 -0
- data/test/unit/xml_initialize_test.rb +49 -0
- data/test/unit/xml_name_test.rb +141 -0
- data/test/unit/xml_namespace_test.rb +31 -0
- data/test/unit/xml_object_test.rb +205 -0
- data/test/unit/xml_required_test.rb +94 -0
- data/test/unit/xml_text_test.rb +71 -0
- data/website/index.html +98 -0
- metadata +300 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'examples/rails'
|
3
|
+
|
4
|
+
describe ROXML, "under ActiveRecord" do
|
5
|
+
before do
|
6
|
+
@route = Route.from_xml(xml_for('active_record'))
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:all) do
|
10
|
+
FileUtils.rm(DB_PATH) if File.exists?(DB_PATH)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be parsed" do
|
14
|
+
@route.should_not == nil
|
15
|
+
@route.should be_an_instance_of(Route)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "xml attributes" do
|
19
|
+
it "should extract xml attributes" do
|
20
|
+
@route.totalHg.should == "640"
|
21
|
+
@route.lonlatx.should == "357865"
|
22
|
+
@route.lonlaty.should == "271635"
|
23
|
+
@route.grcenter.should == "SH 71635 57865"
|
24
|
+
@route.totalMins.should == "235.75000000000003"
|
25
|
+
@route.totalDist.should == "11185.321521477119"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "xml sub-objects" do
|
30
|
+
it "should extract xml sub-objects" do
|
31
|
+
@route.should have(6).waypoints
|
32
|
+
@route.waypoints.each {|waypoint| waypoint.should be_an_instance_of(Waypoint)}
|
33
|
+
end
|
34
|
+
it "should be usable as a ActiveRecord object" do
|
35
|
+
Waypoint.count.should == 0
|
36
|
+
@route.save!
|
37
|
+
Waypoint.count.should == 6
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'examples/amazon'
|
3
|
+
|
4
|
+
describe PITA::ItemSearchResponse do
|
5
|
+
before do
|
6
|
+
@response = PITA::ItemSearchResponse.from_xml(xml_for('amazon'))
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#total_results" do
|
10
|
+
it "should be parsed as a number" do
|
11
|
+
@response.total_results.should > 0
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#total_pages" do
|
16
|
+
it "should be parsed as a number" do
|
17
|
+
@response.total_pages.should > 0
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#items" do
|
22
|
+
it "should return a collection of items" do
|
23
|
+
@response.items.should be_an_instance_of(Array)
|
24
|
+
@response.items.size.should > 0
|
25
|
+
@response.items.each {|item| item.should be_an_instance_of(PITA::Item) }
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have the some number less than or equal to #total_results" do
|
29
|
+
@response.items.size.should > 0
|
30
|
+
@response.items.size.should <= @response.total_results
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe PITA::Item do
|
36
|
+
before do
|
37
|
+
@items = PITA::ItemSearchResponse.from_xml(xml_for('amazon')).items
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should extract asin" do
|
41
|
+
@items.each {|item| item.asin.should be_an_instance_of(String) }
|
42
|
+
@items.each {|item| item.asin.should_not be_empty }
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should extract detail_page_url" do
|
46
|
+
@items.each {|item| item.detail_page_url.should be_an_instance_of(String) }
|
47
|
+
@items.each {|item| item.detail_page_url.should_not be_empty }
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should extract manufacturer" do
|
51
|
+
@items.each {|item| item.manufacturer.should be_an_instance_of(String) }
|
52
|
+
@items.each {|item| item.manufacturer.should_not be_empty }
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'examples/current_weather'
|
3
|
+
|
4
|
+
describe Weather do
|
5
|
+
before do
|
6
|
+
@weather = Weather.from_xml(xml_for('current_weather'))
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should extract observations" do
|
10
|
+
@weather.observation.should be_an_instance_of(WeatherObservation)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe WeatherObservation do
|
15
|
+
before do
|
16
|
+
@observation = Weather.from_xml(xml_for('current_weather')).observation
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should extract temperature" do
|
20
|
+
@observation.temperature.should > 0
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should extract feels_like" do
|
24
|
+
@observation.feels_like.should > 0
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#current_condition" do
|
28
|
+
it "should extract current_condition" do
|
29
|
+
@observation.current_condition.should_not be_empty
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should extract icon attribute" do
|
33
|
+
pending "need to think options through for HappyMapper-style :attributes extensions"
|
34
|
+
@observation.current_condition.icon.should_not be_empty
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'examples/dashed_elements'
|
3
|
+
|
4
|
+
describe GitHub::Commit do
|
5
|
+
before do
|
6
|
+
@commit = GitHub::Commit.from_xml(xml_for('dashed_elements'))
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should extract committed date" do
|
10
|
+
@commit.committed_date.should be_an_instance_of(Date)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should extract url" do
|
14
|
+
@commit.url.should_not be_empty
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should extract id" do
|
18
|
+
@commit.id.should_not be_empty
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'examples/library'
|
3
|
+
|
4
|
+
describe Library do
|
5
|
+
before :all do
|
6
|
+
book = Novel.new
|
7
|
+
book.isbn = "0201710897"
|
8
|
+
book.title = "The PickAxe"
|
9
|
+
book.description = "Best Ruby book out there!"
|
10
|
+
book.author = "David Thomas, Andrew Hunt, Dave Thomas"
|
11
|
+
book.publisher = Publisher.new('Addison Wesley Longman, Inc.')
|
12
|
+
|
13
|
+
@lib = Library.new
|
14
|
+
@lib.name = "Favorite Books"
|
15
|
+
@lib.novels = [book]
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#to_xml" do
|
19
|
+
it "should contain the expected information" do
|
20
|
+
@lib.to_xml.to_s.should == ROXML::XML.parse_string(%{<library><NAME><![CDATA[Favorite Books]]></NAME><novel ISBN='0201710897'><title>The PickAxe</title><description><![CDATA[Best Ruby book out there!]]></description><author>David Thomas, Andrew Hunt, Dave Thomas</author><publisher><name>Addison Wesley Longman, Inc.</name></publisher></novel></library>}).root.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when written to a file" do
|
24
|
+
before :all do
|
25
|
+
@path = "spec/examples/library.xml"
|
26
|
+
@doc = ROXML::XML::Document.new
|
27
|
+
@doc.root = @lib.to_xml
|
28
|
+
ROXML::XML.save_doc(@doc, @path)
|
29
|
+
end
|
30
|
+
|
31
|
+
after :all do
|
32
|
+
FileUtils.rm @path
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should be contain the expected xml" do
|
36
|
+
ROXML::XML.parse_string(File.read(@path)).to_s.should == ROXML::XML.parse_string(%{<?xml version="1.0"?><library><NAME><![CDATA[Favorite Books]]></NAME><novel ISBN='0201710897'><title>The PickAxe</title><description><![CDATA[Best Ruby book out there!]]></description><author>David Thomas, Andrew Hunt, Dave Thomas</author><publisher><name>Addison Wesley Longman, Inc.</name></publisher></novel></library>}).to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should be re-parsable via .from_xml" do
|
40
|
+
File.open("spec/examples/library.xml") do |file|
|
41
|
+
Library.from_xml(file).should == @lib
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'examples/posts'
|
3
|
+
|
4
|
+
describe Post do
|
5
|
+
before do
|
6
|
+
@posts = Posts.from_xml(xml_for('posts')).posts
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should extract description" do
|
10
|
+
@posts.each {|post| post.description.should_not be_empty }
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should extract href" do
|
14
|
+
@posts.each {|post| post.href.should_not be_empty }
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should extract extended" do
|
18
|
+
@posts.each {|post| post.extended.should_not be_empty }
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should extract time" do
|
22
|
+
@posts.each {|post| post.created_at.should be_an_instance_of(DateTime) }
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'examples/twitter'
|
3
|
+
|
4
|
+
describe Statuses do
|
5
|
+
describe Status do
|
6
|
+
before do
|
7
|
+
@statuses = Statuses.from_xml(xml_for('twitter')).statuses
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should extract text" do
|
11
|
+
@statuses.each {|status| status.text.should_not be_empty }
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should extract source" do
|
15
|
+
@statuses.each {|status| status.source.should_not be_empty }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe User do
|
19
|
+
before do
|
20
|
+
@users = @statuses.map(&:user)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should extract name" do
|
24
|
+
@users.each {|user| user.name.should == "John Nunemaker" }
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should extract screen_name" do
|
28
|
+
@users.each {|user| user.screen_name.should == "jnunemaker" }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/spec/roxml_spec.rb
ADDED
@@ -0,0 +1,372 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ROXML, "#from_xml" do
|
4
|
+
describe "from_xml call", :shared => true do
|
5
|
+
it "should fetch values" do
|
6
|
+
book = BookWithContributors.from_xml(@path)
|
7
|
+
book.title.should == "Programming Ruby - 2nd Edition"
|
8
|
+
book.contributors.map(&:name).should == ["David Thomas","Andrew Hunt","Chad Fowler"]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "called with PathName" do
|
13
|
+
before do
|
14
|
+
@path = Pathname.new(fixture_path(:book_with_contributors))
|
15
|
+
end
|
16
|
+
it_should_behave_like "from_xml call"
|
17
|
+
end
|
18
|
+
|
19
|
+
context "called with File" do
|
20
|
+
before do
|
21
|
+
@path = File.new(fixture_path(:book_with_contributors))
|
22
|
+
end
|
23
|
+
it_should_behave_like "from_xml call"
|
24
|
+
end
|
25
|
+
|
26
|
+
context "called with URI" do
|
27
|
+
before do
|
28
|
+
require 'uri'
|
29
|
+
@path = URI.parse("file://#{File.expand_path(File.expand_path(fixture_path(:book_with_contributors)))}")
|
30
|
+
end
|
31
|
+
it_should_behave_like "from_xml call"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe ROXML, "#xml" do
|
36
|
+
class DescriptionReadonly
|
37
|
+
include ROXML
|
38
|
+
|
39
|
+
xml_reader :writable, :from => :content
|
40
|
+
xml_reader :readonly, :from => :content, :frozen => true
|
41
|
+
end
|
42
|
+
|
43
|
+
class Contributor
|
44
|
+
include ROXML
|
45
|
+
|
46
|
+
xml_reader :role, :from => :attr
|
47
|
+
xml_reader :name
|
48
|
+
end
|
49
|
+
|
50
|
+
class BookWithContributions
|
51
|
+
include ROXML
|
52
|
+
|
53
|
+
xml_name :book
|
54
|
+
xml_reader :isbn, :from => :attr
|
55
|
+
xml_reader :title
|
56
|
+
xml_reader :description, :as => DescriptionReadonly
|
57
|
+
xml_reader :contributions, :as => [Contributor], :from => 'contributor', :in => "contributions"
|
58
|
+
end
|
59
|
+
|
60
|
+
class BookWithContributionsReadonly
|
61
|
+
include ROXML
|
62
|
+
|
63
|
+
xml_name :book
|
64
|
+
xml_reader :isbn, :from => :attr, :frozen => true
|
65
|
+
xml_reader :title, :frozen => true
|
66
|
+
xml_reader :description, :as => DescriptionReadonly, :frozen => true
|
67
|
+
xml_reader :contributions, :as => [Contributor], :from => 'contributor', :in => "contributions", :frozen => true
|
68
|
+
end
|
69
|
+
|
70
|
+
before do
|
71
|
+
@writable = BookWithContributions.from_xml(fixture(:book_with_contributions))
|
72
|
+
@readonly = BookWithContributionsReadonly.from_xml(fixture(:book_with_contributions))
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should raise on duplicate accessor name" do
|
76
|
+
proc do
|
77
|
+
Class.new do
|
78
|
+
include ROXML
|
79
|
+
|
80
|
+
xml_reader :id
|
81
|
+
xml_accessor :id
|
82
|
+
end
|
83
|
+
end.should raise_error(RuntimeError)
|
84
|
+
end
|
85
|
+
|
86
|
+
class OctalInteger
|
87
|
+
def self.from_xml(val)
|
88
|
+
new(Integer(val.content))
|
89
|
+
end
|
90
|
+
|
91
|
+
def initialize(value)
|
92
|
+
@val = value
|
93
|
+
end
|
94
|
+
|
95
|
+
def ==(other)
|
96
|
+
@val == other
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_xml
|
100
|
+
sprintf("%#o", @val)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "overriding output" do
|
105
|
+
class BookWithOctalPages
|
106
|
+
include ROXML
|
107
|
+
|
108
|
+
xml_accessor :pages_with_as, :as => Integer, :to_xml => proc {|val| sprintf("%#o", val) }, :required => true
|
109
|
+
xml_accessor :pages_with_type, :as => OctalInteger, :required => true
|
110
|
+
end
|
111
|
+
|
112
|
+
# to_xml_test :book_with_octal_pages
|
113
|
+
|
114
|
+
describe "with :to_xml option" do
|
115
|
+
it "should output with to_xml filtering"
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "with #to_xml on the object" do
|
119
|
+
it "should output with to_xml filtering"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "overriding input" do
|
124
|
+
before do
|
125
|
+
@book_with_octal_pages_xml = %{
|
126
|
+
<book>
|
127
|
+
<pages>0357</pages>
|
128
|
+
</book>
|
129
|
+
}
|
130
|
+
|
131
|
+
@expected_pages = 239
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "with :as block shorthand" do
|
135
|
+
class BookWithOctalPagesBlockShorthand
|
136
|
+
include ROXML
|
137
|
+
|
138
|
+
xml_accessor :pages, :as => Integer, :required => true
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should apply filtering on input" do
|
142
|
+
book = BookWithOctalPagesBlockShorthand.from_xml(@book_with_octal_pages_xml)
|
143
|
+
book.pages.should == @expected_pages
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "with #from_xml defined on the object" do
|
148
|
+
class BookWithOctalPagesType
|
149
|
+
include ROXML
|
150
|
+
|
151
|
+
xml_accessor :pages, :as => OctalInteger, :required => true
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should apply filtering on input" do
|
155
|
+
book = BookWithOctalPagesType.from_xml(@book_with_octal_pages_xml)
|
156
|
+
book.pages.should == @expected_pages
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "attribute reference" do
|
162
|
+
before do
|
163
|
+
@frozen = @readonly.isbn
|
164
|
+
@unfrozen = @writable.isbn
|
165
|
+
end
|
166
|
+
|
167
|
+
it_should_behave_like "freezable xml reference"
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "text reference" do
|
171
|
+
before do
|
172
|
+
@frozen = @readonly.title
|
173
|
+
@unfrozen = @writable.title
|
174
|
+
end
|
175
|
+
|
176
|
+
it_should_behave_like "freezable xml reference"
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "object reference" do
|
180
|
+
before do
|
181
|
+
@frozen = @readonly.description
|
182
|
+
@unfrozen = @writable.description
|
183
|
+
end
|
184
|
+
|
185
|
+
it_should_behave_like "freezable xml reference"
|
186
|
+
|
187
|
+
describe "indirect reference via an object" do
|
188
|
+
it "does not inherit the frozen status from its parent" do
|
189
|
+
@frozen.writable.frozen?.should be_false
|
190
|
+
@frozen.readonly.frozen?.should be_true
|
191
|
+
|
192
|
+
@unfrozen.writable.frozen?.should be_false
|
193
|
+
@unfrozen.readonly.frozen?.should be_true
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "array reference" do
|
199
|
+
before do
|
200
|
+
@frozen = @readonly.contributions
|
201
|
+
@unfrozen = @writable.contributions
|
202
|
+
end
|
203
|
+
|
204
|
+
it_should_behave_like "freezable xml reference"
|
205
|
+
|
206
|
+
it "should apply :frozen to the constituent elements" do
|
207
|
+
@frozen.all?(&:frozen?).should be_true
|
208
|
+
@unfrozen.any?(&:frozen?).should be_false
|
209
|
+
end
|
210
|
+
|
211
|
+
context "no elements are present in root, no :in is specified" do
|
212
|
+
class BookWithContributors
|
213
|
+
include ROXML
|
214
|
+
|
215
|
+
xml_name :book
|
216
|
+
xml_reader :isbn, :from => :attr
|
217
|
+
xml_reader :title
|
218
|
+
xml_reader :description
|
219
|
+
xml_reader :contributors, :as => [Contributor]
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should look for elements :in the plural of name" do
|
223
|
+
book = BookWithContributors.from_xml(%{
|
224
|
+
<book isbn="0974514055">
|
225
|
+
<contributors>
|
226
|
+
<contributor role="author"><name>David Thomas</name></contributor>
|
227
|
+
<contributor role="supporting author"><name>Andrew Hunt</name></contributor>
|
228
|
+
<contributor role="supporting author"><name>Chad Fowler</name></contributor>
|
229
|
+
</contributors>
|
230
|
+
</book>
|
231
|
+
})
|
232
|
+
book.contributors.map(&:name).sort.should == ["David Thomas","Andrew Hunt","Chad Fowler"].sort
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "hash reference" do
|
238
|
+
class DictionaryOfGuardedNames
|
239
|
+
include ROXML
|
240
|
+
|
241
|
+
xml_name :dictionary
|
242
|
+
xml_reader :definitions, :as => {:key => :name,
|
243
|
+
:value => :content}, :in => :definitions
|
244
|
+
end
|
245
|
+
|
246
|
+
class DictionaryOfGuardedNamesReadonly
|
247
|
+
include ROXML
|
248
|
+
|
249
|
+
xml_name :dictionary
|
250
|
+
xml_reader :definitions, :as => {:key => :name,
|
251
|
+
:value => :content}, :in => :definitions, :frozen => true
|
252
|
+
end
|
253
|
+
|
254
|
+
before do
|
255
|
+
@frozen = DictionaryOfGuardedNamesReadonly.from_xml(fixture(:dictionary_of_guarded_names)).definitions
|
256
|
+
@unfrozen = DictionaryOfGuardedNames.from_xml(fixture(:dictionary_of_guarded_names)).definitions
|
257
|
+
end
|
258
|
+
|
259
|
+
it_should_behave_like "freezable xml reference"
|
260
|
+
|
261
|
+
it "should have frozen keys, as with all hashes" do
|
262
|
+
@frozen.keys.all?(&:frozen?).should be_true
|
263
|
+
@unfrozen.keys.all?(&:frozen?).should be_true
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should apply :frozen to the constituent values" do
|
267
|
+
@frozen.values.all?(&:frozen?).should be_true
|
268
|
+
@unfrozen.values.any?(&:frozen?).should be_false
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe ROXML, "inheritance" do
|
274
|
+
class Book
|
275
|
+
include ROXML
|
276
|
+
|
277
|
+
xml_accessor :isbn, :from => '@ISBN'
|
278
|
+
xml_reader :title
|
279
|
+
xml_reader :description, :cdata => true
|
280
|
+
xml_reader :author
|
281
|
+
xml_accessor :pages, :from => 'pagecount', :as => Integer
|
282
|
+
end
|
283
|
+
|
284
|
+
class Measurement
|
285
|
+
include ROXML
|
286
|
+
|
287
|
+
xml_reader :units, :from => :attr
|
288
|
+
xml_reader :value, :from => :content, :as => Float
|
289
|
+
|
290
|
+
def initialize(value = 0, units = 'pixels')
|
291
|
+
@value = Float(value)
|
292
|
+
@units = units.to_s
|
293
|
+
normalize_hundredths
|
294
|
+
end
|
295
|
+
|
296
|
+
def to_s
|
297
|
+
"#{value} #{units}"
|
298
|
+
end
|
299
|
+
|
300
|
+
def ==(other)
|
301
|
+
other.units == @units && other.value == @value
|
302
|
+
end
|
303
|
+
|
304
|
+
private
|
305
|
+
def after_parse
|
306
|
+
normalize_hundredths
|
307
|
+
end
|
308
|
+
|
309
|
+
def normalize_hundredths
|
310
|
+
if @units.starts_with? 'hundredths-'
|
311
|
+
@value /= 100
|
312
|
+
@units = @units.split('hundredths-')[1]
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
class InheritedBookWithDepth < Book
|
318
|
+
xml_reader :depth, :as => Measurement
|
319
|
+
end
|
320
|
+
|
321
|
+
before do
|
322
|
+
@book_xml = %{
|
323
|
+
<book ISBN="0201710897">
|
324
|
+
<title>The PickAxe</title>
|
325
|
+
<description><![CDATA[Probably the best Ruby book out there]]></description>
|
326
|
+
<author>David Thomas, Andrew Hunt, Dave Thomas</author>
|
327
|
+
<depth units="hundredths-meters">1130</depth>
|
328
|
+
<publisher>Pragmattic Programmers</publisher>
|
329
|
+
</book>
|
330
|
+
}
|
331
|
+
|
332
|
+
@parent = Book.from_xml(@book_xml)
|
333
|
+
@child = InheritedBookWithDepth.from_xml(@book_xml)
|
334
|
+
end
|
335
|
+
|
336
|
+
describe "parent" do
|
337
|
+
it "should include its attributes" do
|
338
|
+
@child.isbn.should == "0201710897"
|
339
|
+
@child.title.should == "The PickAxe"
|
340
|
+
@child.description.should == "Probably the best Ruby book out there"
|
341
|
+
@child.author.should == 'David Thomas, Andrew Hunt, Dave Thomas'
|
342
|
+
@child.pages.should == nil
|
343
|
+
end
|
344
|
+
|
345
|
+
it "should not include its child's attributes" do
|
346
|
+
@parent.should_not respond_to(:depth)
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
describe "child" do
|
351
|
+
it "should include its parent's attributes" do
|
352
|
+
@child.isbn.should == @parent.isbn
|
353
|
+
@child.title.should == @parent.title
|
354
|
+
@child.description.should == @parent.description
|
355
|
+
@child.author.should == @parent.author
|
356
|
+
@child.pages.should == @parent.pages
|
357
|
+
end
|
358
|
+
|
359
|
+
it "should include its attributes" do
|
360
|
+
@child.depth.to_s.should == '11.3 meters'
|
361
|
+
end
|
362
|
+
|
363
|
+
it "should include parent's attributes added after declaration" do
|
364
|
+
Book.class_eval do
|
365
|
+
xml_reader :publisher, :required => true
|
366
|
+
end
|
367
|
+
|
368
|
+
book = InheritedBookWithDepth.from_xml(@book_xml)
|
369
|
+
book.publisher.should == "Pragmattic Programmers"
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|