ROXML 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.gitmodules +3 -0
- data/History.txt +299 -0
- data/MIT-LICENSE +18 -0
- data/README.rdoc +161 -0
- data/Rakefile +95 -0
- data/TODO +39 -0
- data/VERSION +1 -0
- data/config/website.yml +2 -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 +547 -0
- data/lib/roxml/definition.rb +236 -0
- data/lib/roxml/hash_definition.rb +25 -0
- data/lib/roxml/xml.rb +43 -0
- data/lib/roxml/xml/parsers/libxml.rb +91 -0
- data/lib/roxml/xml/parsers/nokogiri.rb +77 -0
- data/lib/roxml/xml/references.rb +297 -0
- data/roxml.gemspec +201 -0
- data/spec/definition_spec.rb +486 -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/attributes_spec.rb +36 -0
- data/spec/xml/namespace_spec.rb +240 -0
- data/spec/xml/namespaces_spec.rb +32 -0
- data/spec/xml/parser_spec.rb +26 -0
- data/tasks/rdoc.rake +13 -0
- data/tasks/rspec.rake +25 -0
- data/tasks/test.rake +35 -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/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 +207 -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 +254 -0
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
PROC_TRUE = proc {|val| val ? 'TRUE' : 'FALSE'}
|
4
|
+
PROC_True = proc {|val| val ? 'True' : 'False'}
|
5
|
+
PROC_true = proc {|val| val.to_s}
|
6
|
+
PROC_1 = proc {|val| val ? 1 : 0}
|
7
|
+
|
8
|
+
class XmlBool
|
9
|
+
include ROXML
|
10
|
+
|
11
|
+
xml_name 'xml_bool'
|
12
|
+
xml_reader :true_from_TRUE?, :to_xml => PROC_TRUE
|
13
|
+
xml_reader :false_from_FALSE?, :from => 'text_for_FALSE', :to_xml => PROC_TRUE
|
14
|
+
xml_reader :true_from_one?, :from => '@attr_for_one', :to_xml => PROC_1
|
15
|
+
xml_reader :false_from_zero?, :from => 'text_for_zero', :in => 'container', :to_xml => PROC_1
|
16
|
+
xml_reader :true_from_True?, :from => '@attr_for_True', :in => 'container', :to_xml => PROC_True
|
17
|
+
xml_reader :false_from_False?, :from => 'false_from_cdata_False', :cdata => true, :to_xml => PROC_True
|
18
|
+
xml_reader :true_from_true?, :to_xml => PROC_true
|
19
|
+
xml_reader :false_from_false?, :to_xml => PROC_true
|
20
|
+
xml_reader :missing?
|
21
|
+
end
|
22
|
+
|
23
|
+
class XmlBoolRequired
|
24
|
+
include ROXML
|
25
|
+
|
26
|
+
xml_reader :required?, :required => true
|
27
|
+
end
|
28
|
+
|
29
|
+
class XmlBoolUnexpected
|
30
|
+
include ROXML
|
31
|
+
|
32
|
+
xml_reader :unexpected?
|
33
|
+
end
|
34
|
+
|
35
|
+
class XmlBoolUnexpectedWithBlock
|
36
|
+
include ROXML
|
37
|
+
|
38
|
+
xml_reader :unexpected? do |val|
|
39
|
+
val
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
BOOL_XML = %{
|
44
|
+
<xml_bool attr_for_one="1">
|
45
|
+
<true_from_TRUE>TRUE</true_from_TRUE>
|
46
|
+
<text_for_FALSE>FALSE</text_for_FALSE>
|
47
|
+
<container attr_for_True="True">
|
48
|
+
<text_for_zero>0</text_for_zero>
|
49
|
+
</container>
|
50
|
+
<false_from_cdata_False><![CDATA[False]]></false_from_cdata_False>
|
51
|
+
<true_from_true>true</true_from_true>
|
52
|
+
<false_from_false>false</false_from_false>
|
53
|
+
</xml_bool>
|
54
|
+
}
|
55
|
+
PRESENT = %{
|
56
|
+
<xml_bool_required>
|
57
|
+
<required>true</required>
|
58
|
+
</xml_bool_required>
|
59
|
+
}
|
60
|
+
ABSENT = %{
|
61
|
+
<xml_bool_required>
|
62
|
+
</xml_bool_required>
|
63
|
+
}
|
64
|
+
UNEXPECTED_VALUE_XML = %{
|
65
|
+
<xml_bool_unexpected>
|
66
|
+
<unexpected>Unexpected Value</unexpected>
|
67
|
+
</xml_bool_unexpected>
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
class TestXMLBool < ActiveSupport::TestCase
|
72
|
+
def test_bool_results_for_various_inputs
|
73
|
+
x = XmlBool.from_xml(BOOL_XML)
|
74
|
+
assert_equal true, x.true_from_TRUE?
|
75
|
+
assert_equal false, x.false_from_FALSE?
|
76
|
+
assert_equal true, x.true_from_one?
|
77
|
+
assert_equal false, x.false_from_zero?
|
78
|
+
assert_equal true, x.true_from_True?
|
79
|
+
assert_equal false, x.false_from_False?
|
80
|
+
assert_equal true, x.true_from_true?
|
81
|
+
assert_equal false, x.false_from_false?
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_missing_results_in_nil
|
85
|
+
x = XmlBool.from_xml(BOOL_XML)
|
86
|
+
assert_equal nil, x.missing?
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_unexpected_value_results_in_nil
|
90
|
+
x = XmlBoolUnexpected.from_xml(UNEXPECTED_VALUE_XML)
|
91
|
+
assert_equal nil, x.unexpected?
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_block_recieves_unexpected_value_rather_than_nil
|
95
|
+
x = XmlBoolUnexpectedWithBlock.from_xml(UNEXPECTED_VALUE_XML)
|
96
|
+
assert_equal "Unexpected Value", x.unexpected?
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_required_raises_on_missing
|
100
|
+
assert_nothing_raised do
|
101
|
+
XmlBoolRequired.from_xml(PRESENT)
|
102
|
+
end
|
103
|
+
|
104
|
+
assert_raise ROXML::RequiredElementMissing do
|
105
|
+
XmlBoolRequired.from_xml(ABSENT)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_writable_references_properly_handle_punctuation
|
110
|
+
klass = Class.new do
|
111
|
+
include ROXML
|
112
|
+
xml_accessor :punctuation?
|
113
|
+
end
|
114
|
+
|
115
|
+
instance = klass.from_xml("<xml><punctuation>True</punctuation></xml>")
|
116
|
+
assert_equal true, instance.punctuation?
|
117
|
+
instance.punctuation = false
|
118
|
+
assert_equal false, instance.punctuation?
|
119
|
+
end
|
120
|
+
|
121
|
+
to_xml_test XmlBool => BOOL_XML
|
122
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
XML_CAMELLOWER = %{
|
4
|
+
<bookCase name="Jonas' Books">
|
5
|
+
<bookCount>12</bookCount>
|
6
|
+
<bigBooks>
|
7
|
+
<bigBook>GED</bigBook>
|
8
|
+
<bigBook>House of Leaves</bigBook>
|
9
|
+
</bigBooks>
|
10
|
+
</bookCase>
|
11
|
+
}
|
12
|
+
|
13
|
+
XML_CAMELCASE = %{
|
14
|
+
<BookCase Name="Jonas' Books">
|
15
|
+
<BookCount>12</BookCount>
|
16
|
+
<BigBooks>
|
17
|
+
<BigBook>GED</BigBook>
|
18
|
+
<BigBook>House of Leaves</BigBook>
|
19
|
+
</BigBooks>
|
20
|
+
</BookCase>
|
21
|
+
}
|
22
|
+
|
23
|
+
XML_UNDERSCORE = %{
|
24
|
+
<book_case name="Jonas' Books">
|
25
|
+
<book_count>12</book_count>
|
26
|
+
<big_books>
|
27
|
+
<big_book>GED</big_book>
|
28
|
+
<big_book>House of Leaves</big_book>
|
29
|
+
</big_books>
|
30
|
+
</book_case>
|
31
|
+
}
|
32
|
+
|
33
|
+
XML_DASHES = %{
|
34
|
+
<book-case name="Jonas' Books">
|
35
|
+
<book-count>12</book-count>
|
36
|
+
<big-books>
|
37
|
+
<big-book>GED</big-book>
|
38
|
+
<big-book>House of Leaves</big-book>
|
39
|
+
</big-books>
|
40
|
+
</book-case>
|
41
|
+
}
|
42
|
+
|
43
|
+
XML_UPCASE = %{
|
44
|
+
<BOOKCASE NAME="Jonas' Books">
|
45
|
+
<BOOKCOUNT>12</BOOKCOUNT>
|
46
|
+
<BIGBOOKS>
|
47
|
+
<BIGBOOK>GED</BIGBOOK>
|
48
|
+
<BIGBOOK>House of Leaves</BIGBOOK>
|
49
|
+
</BIGBOOKS>
|
50
|
+
</BOOKCASE>
|
51
|
+
}
|
52
|
+
|
53
|
+
class BookCase
|
54
|
+
include ROXML
|
55
|
+
|
56
|
+
xml_reader :book_count, :as => Integer, :required => true
|
57
|
+
xml_reader :big_books, :as => [], :required => true
|
58
|
+
end
|
59
|
+
|
60
|
+
class BookCaseCamelCase < BookCase
|
61
|
+
xml_convention :camelcase
|
62
|
+
end
|
63
|
+
|
64
|
+
class BookCaseUnderScore < BookCase
|
65
|
+
xml_convention :underscore
|
66
|
+
end
|
67
|
+
|
68
|
+
class BookCaseDashes < BookCase
|
69
|
+
xml_convention &:dasherize
|
70
|
+
end
|
71
|
+
|
72
|
+
class BookCaseCamelLower < BookCase
|
73
|
+
xml_convention {|val| val.camelcase(:lower) }
|
74
|
+
end
|
75
|
+
|
76
|
+
class BookCaseUpCase < BookCase
|
77
|
+
xml_convention {|val| val.gsub('_', '').upcase }
|
78
|
+
end
|
79
|
+
|
80
|
+
class InheritedBookCaseCamelCase < BookCaseCamelCase
|
81
|
+
end
|
82
|
+
|
83
|
+
class InheritedBookCaseUpCase < BookCaseUpCase
|
84
|
+
end
|
85
|
+
|
86
|
+
# Same as BookCase. Needed to keep BookCase clean for other tests
|
87
|
+
class ParentBookCaseDefault
|
88
|
+
include ROXML
|
89
|
+
|
90
|
+
xml_reader :book_count, :as => Integer, :required => true
|
91
|
+
xml_reader :big_books, :as => [], :required => true
|
92
|
+
end
|
93
|
+
|
94
|
+
class InheritedBookCaseDefault < ParentBookCaseDefault
|
95
|
+
end
|
96
|
+
|
97
|
+
class TestXMLConvention < ActiveSupport::TestCase
|
98
|
+
# TODO: Test convention applies to xml_name as well...
|
99
|
+
|
100
|
+
def test_default_convention_is_underscore
|
101
|
+
bc = BookCase.from_xml(XML_UNDERSCORE)
|
102
|
+
assert_has_book_case_info(bc)
|
103
|
+
end
|
104
|
+
|
105
|
+
[BookCaseUpCase, BookCaseCamelLower, BookCaseDashes, BookCaseUnderScore, BookCaseCamelCase].each do |klass|
|
106
|
+
define_method(:"test_xml_convention_#{klass.to_s.underscore}") do
|
107
|
+
data = :"XML_#{klass.to_s.sub('BookCase', '').upcase}"
|
108
|
+
assert_equal Proc, klass.roxml_naming_convention.class
|
109
|
+
|
110
|
+
bc = klass.from_xml(Object.const_get(data))
|
111
|
+
assert_has_book_case_info(bc)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_child_should_inherit_convention_if_it_doesnt_declare_one
|
116
|
+
[InheritedBookCaseUpCase, InheritedBookCaseCamelCase].each do |klass|
|
117
|
+
data = :"XML_#{klass.to_s.sub('InheritedBookCase', '').upcase}"
|
118
|
+
assert_equal Proc, klass.roxml_naming_convention.class
|
119
|
+
|
120
|
+
bc = klass.from_xml(Object.const_get(data))
|
121
|
+
assert_has_book_case_info(bc)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_child_should_inherit_convention_even_if_it_is_added_after_child_declaration
|
126
|
+
bc = InheritedBookCaseDefault.from_xml(XML_UNDERSCORE)
|
127
|
+
assert_has_book_case_info(bc)
|
128
|
+
|
129
|
+
ParentBookCaseDefault.class_eval do
|
130
|
+
xml_convention :dasherize
|
131
|
+
end
|
132
|
+
|
133
|
+
bc = InheritedBookCaseDefault.from_xml(XML_DASHES)
|
134
|
+
assert_has_book_case_info(bc)
|
135
|
+
assert_raise ROXML::RequiredElementMissing do
|
136
|
+
InheritedBookCaseDefault.from_xml(XML_UNDERSCORE)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_tag_name_should_get_convention_treatment_as_well
|
141
|
+
assert_equal "book-case-dashes", BookCaseDashes.tag_name
|
142
|
+
assert_equal "INHERITEDBOOKCASEUPCASE", InheritedBookCaseUpCase.tag_name
|
143
|
+
assert_equal "InheritedBookCaseCamelCase", InheritedBookCaseCamelCase.tag_name
|
144
|
+
end
|
145
|
+
|
146
|
+
def assert_has_book_case_info(bc)
|
147
|
+
assert_equal 12, bc.book_count
|
148
|
+
assert_equal ['GED', 'House of Leaves'], bc.big_books
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class BookWithContributorHash
|
4
|
+
include ROXML
|
5
|
+
|
6
|
+
xml_reader :contributors, :as => {:key => '@role',
|
7
|
+
:value => 'name'}
|
8
|
+
end
|
9
|
+
|
10
|
+
class TestXMLHash < ActiveSupport::TestCase
|
11
|
+
def setup
|
12
|
+
@contents = {'quaquaversally' => 'adjective: (of a geological formation) sloping downward from the center in all directions.',
|
13
|
+
'tergiversate' => 'To use evasions or ambiguities; equivocate.'}
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_hash_preserves_data
|
17
|
+
b = BookWithContributorHash.from_xml(%{
|
18
|
+
<book isbn="0974514055">
|
19
|
+
<contributor role="author"><name>David Thomas</name></contributor>
|
20
|
+
<contributor role="supporting author"><name>Andrew Hunt</name></contributor>
|
21
|
+
<contributor role="supporting author"><name>Chad Fowler</name></contributor>
|
22
|
+
</book>
|
23
|
+
})
|
24
|
+
assert_equal({'author' => 'David Thomas', 'supporting author' => ['Andrew Hunt', 'Chad Fowler']},
|
25
|
+
b.contributors)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_hash_with_object_key_fails
|
29
|
+
assert_raise ArgumentError do
|
30
|
+
Class.new do
|
31
|
+
include ROXML
|
32
|
+
|
33
|
+
xml_reader :object_key_to_text, :as => {:key => BookWithContributorHash,
|
34
|
+
:value => 'text_node'}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_hash_with_object_value_fails
|
40
|
+
assert_raise ArgumentError do
|
41
|
+
Class.new do
|
42
|
+
include ROXML
|
43
|
+
|
44
|
+
xml_reader :key_to_object_value, :as => {:key => '@text_node',
|
45
|
+
:value => BookWithContributorHash}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_attrs_hash
|
51
|
+
dict = DictionaryOfAttrs.from_xml(fixture(:dictionary_of_attrs))
|
52
|
+
assert_equal Hash, dict.definitions.class
|
53
|
+
assert_equal @contents, dict.definitions
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_text_hash
|
57
|
+
dict = DictionaryOfTexts.from_xml(fixture(:dictionary_of_texts))
|
58
|
+
assert_equal Hash, dict.definitions.class
|
59
|
+
assert_equal @contents, dict.definitions
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_mixed_content_hash
|
63
|
+
dict = DictionaryOfMixeds.from_xml(fixture(:dictionary_of_mixeds))
|
64
|
+
assert_equal Hash, dict.definitions.class
|
65
|
+
assert_equal @contents, dict.definitions
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_name_hash
|
69
|
+
dict = DictionaryOfNames.from_xml(fixture(:dictionary_of_names))
|
70
|
+
assert_equal Hash, dict.definitions.class
|
71
|
+
assert_equal @contents, dict.definitions
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_guarded_name_hash
|
75
|
+
dict = DictionaryOfGuardedNames.from_xml(fixture(:dictionary_of_guarded_names))
|
76
|
+
assert_equal Hash, dict.definitions.class
|
77
|
+
assert_equal @contents, dict.definitions
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_text_name_clashes
|
81
|
+
dict = DictionaryOfNameClashes.from_xml(fixture(:dictionary_of_name_clashes))
|
82
|
+
assert_equal Hash, dict.definitions.class
|
83
|
+
assert_equal @contents, dict.definitions
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_attr_name_clashes
|
87
|
+
dict = DictionaryOfAttrNameClashes.from_xml(fixture(:dictionary_of_attr_name_clashes))
|
88
|
+
assert_equal Hash, dict.definitions.class
|
89
|
+
assert_equal @contents, dict.definitions
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_it_should_gracefully_handle_empty_hash
|
93
|
+
dict = Class.new do
|
94
|
+
include ROXML
|
95
|
+
|
96
|
+
xml_reader :missing_hash, :as => {:key => :name, :value => :content}, :in => 'EmptyDictionary'
|
97
|
+
end
|
98
|
+
|
99
|
+
assert_equal({}, dict.from_xml(%{
|
100
|
+
<dict>
|
101
|
+
<EmptyDictionary>
|
102
|
+
</EmptyDictionary>
|
103
|
+
</dict>
|
104
|
+
}).missing_hash)
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_as_hash_of_as_type_not_deprecated
|
108
|
+
assert_not_deprecated do
|
109
|
+
opts = ROXML::Definition.new(:name, :as => {:key => :name, :value => {:from => 'value', :as => OctalInteger}})
|
110
|
+
assert opts.hash?
|
111
|
+
assert_equal OctalInteger, opts.hash.value.type
|
112
|
+
assert_equal 'value', opts.hash.value.name
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class InheritedBookWithDepth < Book
|
4
|
+
xml_reader :depth, :as => Measurement
|
5
|
+
end
|
6
|
+
|
7
|
+
class BookWithXmlInitialize < BookWithDepth
|
8
|
+
attr_reader :created_at, :creator
|
9
|
+
|
10
|
+
def initialize(created_at, creator = "Unknown")
|
11
|
+
@created_at = created_at
|
12
|
+
@creator = creator
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TestXMLInitialize < ActiveSupport::TestCase
|
17
|
+
def test_initialize_is_run
|
18
|
+
m = Measurement.from_xml('<measurement units="hundredths-meters">1130</measurement>')
|
19
|
+
assert_equal 11.3, m.value
|
20
|
+
assert_equal 'meters', m.units
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_initialize_is_run_for_nested_type
|
24
|
+
b = BookWithDepth.from_xml(fixture(:book_with_depth))
|
25
|
+
assert_equal Measurement.new(11.3, 'meters'), b.depth
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_initialize_is_run_for_nested_type_with_inheritance
|
29
|
+
b = InheritedBookWithDepth.from_xml(fixture(:book_with_depth))
|
30
|
+
assert_equal Measurement.new(11.3, 'meters'), b.depth
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_initialize_fails_on_missing_required_arg
|
34
|
+
assert_raise ArgumentError do
|
35
|
+
BookWithXmlInitialize.from_xml(fixture(:book_with_depth))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_initialize_with_extra_args
|
40
|
+
now = Time.now
|
41
|
+
b = BookWithXmlInitialize.from_xml(fixture(:book_with_depth), now)
|
42
|
+
assert_equal now, b.created_at
|
43
|
+
assert_equal "Unknown", b.creator
|
44
|
+
|
45
|
+
b = BookWithXmlInitialize.from_xml(fixture(:book_with_depth), Time.now, "Joe Librarian")
|
46
|
+
assert now < b.created_at
|
47
|
+
assert_equal "Joe Librarian", b.creator
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
# Parent | Child
|
4
|
+
# :from | no :from |
|
5
|
+
# -------------------|--------------
|
6
|
+
# :from | xml_name | xml_name-d
|
7
|
+
# value | value |
|
8
|
+
# -------------------|--------------
|
9
|
+
# :from | parent's |
|
10
|
+
# value | accessor | un-xml_name-d
|
11
|
+
# | name |
|
12
|
+
|
13
|
+
class Child
|
14
|
+
include ROXML
|
15
|
+
end
|
16
|
+
|
17
|
+
class NamedChild
|
18
|
+
include ROXML
|
19
|
+
|
20
|
+
xml_name :xml_name_of_child
|
21
|
+
end
|
22
|
+
|
23
|
+
class ParentOfNamedChild
|
24
|
+
include ROXML
|
25
|
+
|
26
|
+
xml_name :parent
|
27
|
+
xml_accessor :child_accessor_name, :as => NamedChild
|
28
|
+
end
|
29
|
+
|
30
|
+
class ParentOfNamedChildWithFrom
|
31
|
+
include ROXML
|
32
|
+
|
33
|
+
xml_name :parent
|
34
|
+
xml_accessor :child_accessor_name, :as => NamedChild, :from => 'child_from_name'
|
35
|
+
end
|
36
|
+
|
37
|
+
class ParentOfUnnamedChild
|
38
|
+
include ROXML
|
39
|
+
|
40
|
+
xml_name :parent
|
41
|
+
xml_accessor :child_accessor_name, :as => Child
|
42
|
+
end
|
43
|
+
|
44
|
+
class ParentOfUnnamedChildWithFrom
|
45
|
+
include ROXML
|
46
|
+
|
47
|
+
xml_name :parent
|
48
|
+
xml_accessor :child_accessor_name,:as => Child, :from => 'child_from_name'
|
49
|
+
end
|
50
|
+
|
51
|
+
class TestXMLName < ActiveSupport::TestCase
|
52
|
+
def test_from_always_dominates_attribute_name_xml_name_or_not
|
53
|
+
parent = ParentOfNamedChildWithFrom.new
|
54
|
+
parent.child_accessor_name = Child.new
|
55
|
+
|
56
|
+
assert_equal "<parent><child_from_name/></parent>", parent.to_xml.to_s.gsub(/[\n ]/, '')
|
57
|
+
|
58
|
+
parent = ParentOfUnnamedChildWithFrom.new
|
59
|
+
parent.child_accessor_name = Child.new
|
60
|
+
|
61
|
+
assert_equal "<parent><child_from_name/></parent>", parent.to_xml.to_s.gsub(/[\n ]/, '')
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_attribute_name_comes_from_the_xml_name_value_if_present
|
65
|
+
parent = ParentOfNamedChild.new
|
66
|
+
parent.child_accessor_name = Child.new
|
67
|
+
|
68
|
+
assert_equal "<parent><xml_name_of_child/></parent>", parent.to_xml.to_s.gsub(/[\n ]/, '')
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_attribute_name_comes_from_parent_accessor_by_default
|
72
|
+
parent = ParentOfUnnamedChild.new
|
73
|
+
parent.child_accessor_name = Child.new
|
74
|
+
|
75
|
+
assert_equal "<parent><child_accessor_name/></parent>", parent.to_xml.to_s.gsub(/[\n ]/, '')
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_it_should_be_inherited
|
79
|
+
class_with_inherited_name = Class.new(ParentOfNamedChild)
|
80
|
+
assert_equal :parent, class_with_inherited_name.tag_name
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_it_should_be_inherited_over_multiple_levels
|
84
|
+
class_with_inherited_name = Class.new(Class.new(ParentOfNamedChild))
|
85
|
+
assert_equal :parent, class_with_inherited_name.tag_name
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_named_books_picked_up
|
89
|
+
named = Library.from_xml(fixture(:library))
|
90
|
+
assert named.books
|
91
|
+
assert_equal :book, named.books.first.class.tag_name
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_nameless_books_missing
|
95
|
+
nameless = LibraryWithBooksOfUnderivableName.from_xml(fixture(:library))
|
96
|
+
assert nameless.novels.empty?
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_tag_name
|
100
|
+
assert_equal :dictionary, DictionaryOfTexts.tag_name
|
101
|
+
|
102
|
+
dict = DictionaryOfTexts.from_xml(fixture(:dictionary_of_texts))
|
103
|
+
|
104
|
+
assert_equal :dictionary, dict.class.tag_name
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_roxml_attrs
|
108
|
+
assert_equal 'definition', DictionaryOfTexts.roxml_attrs.first.name
|
109
|
+
assert_equal 'word', DictionaryOfTexts.roxml_attrs.first.hash.key.name
|
110
|
+
assert_equal 'meaning', DictionaryOfTexts.roxml_attrs.first.hash.value.name
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_xml_name_should_not_be_conventionalized_if_explicitly_set
|
114
|
+
reference = ROXML::XMLTextRef.new(ROXML::Definition.new(:name, :from => 'georss:name'), WrapModule::InstanceStandin.new)
|
115
|
+
assert_equal "georss:name", reference.name
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_xml_name_not_screwed_up_by_xml_convention
|
119
|
+
reference = ROXML::XMLTextRef.new(ROXML::Definition.new(:name, :in => './'), WrapModule::InstanceStandin.new)
|
120
|
+
assert_equal "name value", reference.value_in(ROXML::XML::Parser.parse(%(
|
121
|
+
<Wrapper>
|
122
|
+
<MoreStuff>
|
123
|
+
<DeepWrapper>
|
124
|
+
<Name>name value</Name>
|
125
|
+
</DeepWrapper>
|
126
|
+
</MoreStuff>
|
127
|
+
</Wrapper>
|
128
|
+
)).root)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
module WrapModule
|
133
|
+
class BaseClass
|
134
|
+
include ROXML
|
135
|
+
xml_convention :camelcase
|
136
|
+
end
|
137
|
+
|
138
|
+
class InstanceStandin < BaseClass
|
139
|
+
xml_reader :name, :in => './'
|
140
|
+
end
|
141
|
+
end
|