Empact-roxml 2.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.
- data/MIT-LICENSE +18 -0
- data/README.rdoc +122 -0
- data/Rakefile +104 -0
- data/lib/roxml.rb +362 -0
- data/lib/roxml/array.rb +15 -0
- data/lib/roxml/options.rb +175 -0
- data/lib/roxml/string.rb +35 -0
- data/lib/roxml/xml.rb +243 -0
- data/lib/roxml/xml/libxml.rb +63 -0
- data/lib/roxml/xml/rexml.rb +59 -0
- data/roxml.gemspec +78 -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_publisher.xml +7 -0
- data/test/fixtures/dictionary_of_attrs.xml +6 -0
- data/test/fixtures/dictionary_of_mixeds.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/nameless_ageless_youth.xml +2 -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 +56 -0
- data/test/mocks/mocks.rb +212 -0
- data/test/test_helper.rb +16 -0
- data/test/unit/options_test.rb +62 -0
- data/test/unit/roxml_test.rb +24 -0
- data/test/unit/string_test.rb +11 -0
- data/test/unit/to_xml_test.rb +75 -0
- data/test/unit/xml_attribute_test.rb +34 -0
- data/test/unit/xml_construct_test.rb +19 -0
- data/test/unit/xml_hash_test.rb +54 -0
- data/test/unit/xml_name_test.rb +14 -0
- data/test/unit/xml_namespace_test.rb +36 -0
- data/test/unit/xml_object_test.rb +94 -0
- data/test/unit/xml_text_test.rb +57 -0
- metadata +110 -0
data/test/mocks/mocks.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
require "lib/roxml"
|
2
|
+
|
3
|
+
class Book
|
4
|
+
include ROXML
|
5
|
+
|
6
|
+
xml_accessor :isbn, :attr => 'ISBN'
|
7
|
+
xml_reader :title
|
8
|
+
xml_reader :description, :as => :cdata
|
9
|
+
xml_reader :author
|
10
|
+
xml_accessor :pages, :text => 'pagecount' do |val|
|
11
|
+
Integer(val)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class BookWithAttrFrom
|
16
|
+
include ROXML
|
17
|
+
|
18
|
+
xml_accessor :isbn, :attr, :from => 'ISBN'
|
19
|
+
end
|
20
|
+
|
21
|
+
class Measurement
|
22
|
+
include ROXML
|
23
|
+
|
24
|
+
xml_reader :units, :attr
|
25
|
+
xml_reader :value, :content
|
26
|
+
xml_construct :value, :units
|
27
|
+
|
28
|
+
def initialize(value, units = 'pixels')
|
29
|
+
@value = Float(value)
|
30
|
+
@units = units.to_s
|
31
|
+
if @units.starts_with? 'hundredths-'
|
32
|
+
@value /= 100
|
33
|
+
@units = @units.split('hundredths-')[1]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def ==(other)
|
38
|
+
other.units == @units && other.value == @value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class BookWithDepth
|
43
|
+
include ROXML
|
44
|
+
|
45
|
+
xml_reader :isbn, :attr => 'ISBN'
|
46
|
+
xml_reader :title
|
47
|
+
xml_reader :description, :as => :cdata
|
48
|
+
xml_reader :author
|
49
|
+
xml_reader :depth, Measurement
|
50
|
+
end
|
51
|
+
|
52
|
+
class InheritedBookWithDepth < Book
|
53
|
+
xml_reader :depth, Measurement
|
54
|
+
end
|
55
|
+
|
56
|
+
class Author
|
57
|
+
include ROXML
|
58
|
+
|
59
|
+
xml_reader :role, :attr
|
60
|
+
xml_reader :text, :content
|
61
|
+
end
|
62
|
+
|
63
|
+
class BookWithAuthors
|
64
|
+
include ROXML
|
65
|
+
|
66
|
+
xml_name :book
|
67
|
+
xml_reader :isbn, :attr, :from => 'ISBN'
|
68
|
+
xml_reader :title
|
69
|
+
xml_reader :description, :as => :cdata
|
70
|
+
xml_reader :authors, :as => :array
|
71
|
+
end
|
72
|
+
|
73
|
+
class BookWithAuthorTextAttribute
|
74
|
+
include ROXML
|
75
|
+
|
76
|
+
xml_name :book
|
77
|
+
xml_reader :isbn, :attr, :from => 'ISBN'
|
78
|
+
xml_reader :title
|
79
|
+
xml_reader :description, :as => :cdata
|
80
|
+
xml_reader :author, Author
|
81
|
+
end
|
82
|
+
|
83
|
+
class Contributor
|
84
|
+
include ROXML
|
85
|
+
|
86
|
+
xml_reader :role, :attr
|
87
|
+
xml_reader :name
|
88
|
+
end
|
89
|
+
|
90
|
+
class BookWithContributions
|
91
|
+
include ROXML
|
92
|
+
|
93
|
+
xml_name :book
|
94
|
+
xml_reader :isbn, :attr
|
95
|
+
xml_reader :title
|
96
|
+
xml_reader :description
|
97
|
+
xml_reader :contributions, [Contributor], :from => 'contributor', :in => "contributions"
|
98
|
+
end
|
99
|
+
|
100
|
+
class BookWithContributors
|
101
|
+
include ROXML
|
102
|
+
|
103
|
+
xml_name :book
|
104
|
+
xml_reader :isbn, :attr
|
105
|
+
xml_reader :title
|
106
|
+
xml_reader :description
|
107
|
+
xml_reader :contributors, Contributor, :as => :array
|
108
|
+
end
|
109
|
+
|
110
|
+
class NamelessBook
|
111
|
+
include ROXML
|
112
|
+
|
113
|
+
xml_reader :isbn, :attr
|
114
|
+
xml_reader :title
|
115
|
+
xml_reader :description
|
116
|
+
xml_reader :contributors, Contributor, :as => :array
|
117
|
+
end
|
118
|
+
|
119
|
+
class Publisher
|
120
|
+
include ROXML
|
121
|
+
|
122
|
+
xml_reader :name
|
123
|
+
end
|
124
|
+
|
125
|
+
class BookWithPublisher
|
126
|
+
include ROXML
|
127
|
+
|
128
|
+
xml_reader :book
|
129
|
+
xml_reader :isbn, :attr
|
130
|
+
xml_reader :title
|
131
|
+
xml_reader :description
|
132
|
+
xml_reader :publisher, Publisher
|
133
|
+
end
|
134
|
+
|
135
|
+
class BookPair
|
136
|
+
include ROXML
|
137
|
+
|
138
|
+
xml_reader :isbn, :attr
|
139
|
+
xml_reader :title
|
140
|
+
xml_reader :description
|
141
|
+
xml_reader :author
|
142
|
+
xml_reader :book, Book
|
143
|
+
end
|
144
|
+
|
145
|
+
class Library
|
146
|
+
include ROXML
|
147
|
+
|
148
|
+
xml_reader :name
|
149
|
+
xml_reader :books, BookWithContributions, :as => :array
|
150
|
+
end
|
151
|
+
|
152
|
+
class UppercaseLibrary
|
153
|
+
include ROXML
|
154
|
+
|
155
|
+
xml_name :library
|
156
|
+
xml_reader :name, :from => 'NAME'
|
157
|
+
xml_reader :books, [BookWithContributions], :from => 'BOOK'
|
158
|
+
end
|
159
|
+
|
160
|
+
class LibraryWithBooksOfUnderivableName
|
161
|
+
include ROXML
|
162
|
+
|
163
|
+
xml :name, true
|
164
|
+
xml_reader :novels, NamelessBook, :as => :array
|
165
|
+
end
|
166
|
+
|
167
|
+
class NodeWithNameConflicts
|
168
|
+
include ROXML
|
169
|
+
|
170
|
+
xml_name :node
|
171
|
+
xml_reader :content
|
172
|
+
xml_reader :name
|
173
|
+
end
|
174
|
+
|
175
|
+
class NodeWithAttrNameConflicts
|
176
|
+
include ROXML
|
177
|
+
|
178
|
+
xml_name :node
|
179
|
+
xml_reader :content, :attr => :content
|
180
|
+
xml_reader :name, :attr => :name
|
181
|
+
end
|
182
|
+
|
183
|
+
class Person
|
184
|
+
include ROXML
|
185
|
+
|
186
|
+
xml_reader :age, :attr, :else => 21
|
187
|
+
xml_accessor :name, :content, :else => 'Unknown'
|
188
|
+
end
|
189
|
+
|
190
|
+
class PersonWithMother
|
191
|
+
include ROXML
|
192
|
+
|
193
|
+
xml_name :person
|
194
|
+
xml_reader :name
|
195
|
+
xml_reader :mother, PersonWithMother
|
196
|
+
end
|
197
|
+
|
198
|
+
class PersonWithGuardedMother
|
199
|
+
include ROXML
|
200
|
+
|
201
|
+
xml_name :person
|
202
|
+
xml_reader :name
|
203
|
+
xml_reader :mother, PersonWithGuardedMother, :from => :person, :in => :mother
|
204
|
+
end
|
205
|
+
|
206
|
+
class PersonWithMotherOrMissing
|
207
|
+
include ROXML
|
208
|
+
|
209
|
+
xml_reader :age, :attr, :else => 21
|
210
|
+
xml_reader :name, :else => 'Anonymous'
|
211
|
+
xml_reader :mother, PersonWithMotherOrMissing, :else => Person.new
|
212
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "lib/roxml"
|
2
|
+
require "test/unit"
|
3
|
+
require 'test/mocks/mocks'
|
4
|
+
require 'test/mocks/dictionaries'
|
5
|
+
|
6
|
+
def fixture(name)
|
7
|
+
File.read(fixture_path(name))
|
8
|
+
end
|
9
|
+
|
10
|
+
def xml_fixture(name)
|
11
|
+
ROXML::XML::Parser.parse_file(fixture_path(name)).root
|
12
|
+
end
|
13
|
+
|
14
|
+
def fixture_path(name)
|
15
|
+
"test/fixtures/#{name}.xml"
|
16
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
class TestOptions < Test::Unit::TestCase
|
4
|
+
def test_text_in_array_means_as_array_for_text
|
5
|
+
opts = ROXML::Opts.new(:authors, [:text])
|
6
|
+
assert opts.array?
|
7
|
+
assert_equal :text, opts.type
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_attr_in_array_means_as_array_for_attr
|
11
|
+
opts = ROXML::Opts.new(:authors, [:attr])
|
12
|
+
assert opts.array?
|
13
|
+
assert_equal :attr, opts.type
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_object_in_array_means_as_array_for_object
|
17
|
+
opts = ROXML::Opts.new(:authors, [Hash])
|
18
|
+
assert opts.array?
|
19
|
+
assert_equal Hash, opts.type
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_content_is_a_recognized_type
|
23
|
+
assert ROXML::Opts.new(:author, :content).content?
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_hash_of_attrs
|
27
|
+
opts = ROXML::Opts.new(:attributes, {:attrs => [:name, :value]})
|
28
|
+
assert opts.hash?
|
29
|
+
assert !opts.array?
|
30
|
+
assert_equal [ROXML::XMLAttributeRef, ROXML::XMLAttributeRef], opts.hash.types
|
31
|
+
assert_equal ['name', 'value'], opts.hash.names
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_hash_with_attr_key_and_text_val
|
35
|
+
opts = ROXML::Opts.new(:attributes, {:key => {:attr => :name},
|
36
|
+
:value => :value})
|
37
|
+
assert opts.hash?
|
38
|
+
assert !opts.array?
|
39
|
+
assert_equal [ROXML::XMLAttributeRef, ROXML::XMLTextRef], opts.hash.types
|
40
|
+
assert_equal ['name', 'value'], opts.hash.names
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_hash_with_attr_key_and_content_val
|
44
|
+
opts = ROXML::Opts.new(:attributes, {:key => {:attr => :name},
|
45
|
+
:value => :content})
|
46
|
+
assert opts.hash?
|
47
|
+
assert !opts.array?
|
48
|
+
assert opts.hash.value.content
|
49
|
+
assert_equal [ROXML::XMLAttributeRef, ROXML::XMLTextRef], opts.hash.types
|
50
|
+
assert_equal ['name', ''], opts.hash.names
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_hash_with_options
|
54
|
+
opts = ROXML::Opts.new(:definitions, {:attrs => [:dt, :dd]},
|
55
|
+
:in => :definitions)
|
56
|
+
|
57
|
+
assert opts.hash?
|
58
|
+
assert !opts.array?
|
59
|
+
assert_equal [ROXML::XMLAttributeRef, ROXML::XMLAttributeRef], opts.hash.types
|
60
|
+
assert_equal ['dt', 'dd'], opts.hash.names
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
class TestROXML < Test::Unit::TestCase
|
4
|
+
# Malformed XML parsing should throw REXML::ParseException
|
5
|
+
def test_malformed
|
6
|
+
ROXML::XML::Parser.register_error_handler {|err| }
|
7
|
+
assert_raise ROXML::XML::Parser::ParseError do
|
8
|
+
book = Book.parse(fixture(:book_malformed))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Verify that an exception is thrown when two accessors have the same
|
13
|
+
# name in a ROXML class.
|
14
|
+
def test_duplicate_accessor
|
15
|
+
assert_raise RuntimeError do
|
16
|
+
Class.new do
|
17
|
+
include ROXML
|
18
|
+
|
19
|
+
xml_reader :id
|
20
|
+
xml_accessor :id
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'lib/roxml/string'
|
2
|
+
|
3
|
+
class TestROXML < Test::Unit::TestCase
|
4
|
+
def test_to_latin_is_accessible
|
5
|
+
assert String.instance_methods.include?('to_latin')
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_to_utf_is_accessible
|
9
|
+
assert String.instance_methods.include?('to_utf')
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
def to_xml_test(*names)
|
4
|
+
names = names.only if names.one? && names.only.is_a?(Hash)
|
5
|
+
names.each do |(name, xml_name)|
|
6
|
+
xml_name ||= name
|
7
|
+
|
8
|
+
define_method "test_#{name}" do
|
9
|
+
dict = name.to_s.camelize.constantize.parse(fixture(xml_name))
|
10
|
+
xml = xml_fixture(xml_name)
|
11
|
+
remove_children(xml)
|
12
|
+
assert_equal xml, dict.to_xml
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def remove_children(xml)
|
18
|
+
return unless xml.respond_to? :children
|
19
|
+
xml.children.each do |child|
|
20
|
+
if child.blank?
|
21
|
+
child.remove!
|
22
|
+
else
|
23
|
+
remove_children(child)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class TestHashToXml < Test::Unit::TestCase
|
29
|
+
to_xml_test :dictionary_of_attrs,
|
30
|
+
:dictionary_of_mixeds,
|
31
|
+
:dictionary_of_texts,
|
32
|
+
:dictionary_of_names,
|
33
|
+
:dictionary_of_guarded_names,
|
34
|
+
:dictionary_of_name_clashes,
|
35
|
+
:dictionary_of_attr_name_clashes
|
36
|
+
end
|
37
|
+
|
38
|
+
class TestOtherToXml < Test::Unit::TestCase
|
39
|
+
to_xml_test :book => :book_valid,
|
40
|
+
:book_with_author_text_attribute => :book_text_with_attribute,
|
41
|
+
:uppercase_library => :library_uppercase
|
42
|
+
|
43
|
+
to_xml_test :book_with_authors,
|
44
|
+
:book_with_contributors,
|
45
|
+
:book_with_contributions,
|
46
|
+
:library,
|
47
|
+
:node_with_name_conflicts,
|
48
|
+
:node_with_attr_name_conflicts
|
49
|
+
|
50
|
+
to_xml_test :person_with_mother => :person_with_mothers,
|
51
|
+
:person_with_guarded_mother => :person_with_guarded_mothers
|
52
|
+
end
|
53
|
+
|
54
|
+
class TestToXmlWithDefaults < Test::Unit::TestCase
|
55
|
+
def test_content_and_attr_defaults_are_represented_in_output
|
56
|
+
dict = Person.parse(fixture(:nameless_ageless_youth))
|
57
|
+
|
58
|
+
xml = '<person age="21">Unknown</person>'
|
59
|
+
assert_equal ROXML::XML::Parser.parse(xml).root, dict.to_xml
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class TestToXmlWithBlocks < Test::Unit::TestCase
|
64
|
+
def test_pagecount_serialized_properly_after_modification
|
65
|
+
b = Book.parse(fixture(:book_valid))
|
66
|
+
xml = xml_fixture(:book_valid)
|
67
|
+
assert_equal '357', xml.search('pagecount').first.content
|
68
|
+
assert_equal 357, b.pages
|
69
|
+
|
70
|
+
b.pages = 500
|
71
|
+
doc = ROXML::XML::Document.new()
|
72
|
+
doc.root = b.to_xml
|
73
|
+
assert_equal '500', doc.search('pagecount').first.content
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
class TestXMLAttribute < Test::Unit::TestCase
|
4
|
+
def test_attr_from
|
5
|
+
# :attr => *
|
6
|
+
book = Book.parse(fixture(:book_text_with_attribute))
|
7
|
+
assert_equal '0201710897', book.isbn
|
8
|
+
|
9
|
+
# :attr, :from => *
|
10
|
+
book = BookWithAttrFrom.parse(fixture(:book_text_with_attribute))
|
11
|
+
assert_equal '0201710897', book.isbn
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_mutable_attr
|
15
|
+
book = Book.parse(fixture(:book_text_with_attribute))
|
16
|
+
assert book.respond_to?(:'isbn=')
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_default_initialization
|
20
|
+
person = PersonWithMotherOrMissing.parse(fixture(:nameless_ageless_youth))
|
21
|
+
assert_equal 21, person.age
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_recursive_with_default_initialization
|
25
|
+
p = PersonWithMotherOrMissing.parse(fixture(:person_with_mothers))
|
26
|
+
assert_equal 21, p.mother.mother.mother.age
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_no_name_clashes
|
30
|
+
n = NodeWithAttrNameConflicts.parse(fixture(:node_with_attr_name_conflicts))
|
31
|
+
assert_equal "Just junk... really", n.content
|
32
|
+
assert_equal "Cartwheel", n.name
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
2
|
+
|
3
|
+
class TestXMLAttribute < Test::Unit::TestCase
|
4
|
+
def test_initialize_is_run
|
5
|
+
m = Measurement.parse('<measurement units="hundredths-meters">1130</measurement>')
|
6
|
+
assert_equal 11.3, m.value
|
7
|
+
assert_equal 'meters', m.units
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_initialize_is_run_for_nested_type
|
11
|
+
b = BookWithDepth.parse(fixture(:book_with_depth))
|
12
|
+
assert_equal Measurement.new(11.3, 'meters'), b.depth
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_initialize_is_run_for_nested_type_with_inheritance
|
16
|
+
b = InheritedBookWithDepth.parse(fixture(:book_with_depth))
|
17
|
+
assert_equal Measurement.new(11.3, 'meters'), b.depth
|
18
|
+
end
|
19
|
+
end
|