Empact-roxml 2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/MIT-LICENSE +18 -0
  2. data/README.rdoc +122 -0
  3. data/Rakefile +104 -0
  4. data/lib/roxml.rb +362 -0
  5. data/lib/roxml/array.rb +15 -0
  6. data/lib/roxml/options.rb +175 -0
  7. data/lib/roxml/string.rb +35 -0
  8. data/lib/roxml/xml.rb +243 -0
  9. data/lib/roxml/xml/libxml.rb +63 -0
  10. data/lib/roxml/xml/rexml.rb +59 -0
  11. data/roxml.gemspec +78 -0
  12. data/test/fixtures/book_malformed.xml +5 -0
  13. data/test/fixtures/book_pair.xml +8 -0
  14. data/test/fixtures/book_text_with_attribute.xml +5 -0
  15. data/test/fixtures/book_valid.xml +5 -0
  16. data/test/fixtures/book_with_authors.xml +7 -0
  17. data/test/fixtures/book_with_contributions.xml +9 -0
  18. data/test/fixtures/book_with_contributors.xml +7 -0
  19. data/test/fixtures/book_with_contributors_attrs.xml +7 -0
  20. data/test/fixtures/book_with_default_namespace.xml +9 -0
  21. data/test/fixtures/book_with_depth.xml +6 -0
  22. data/test/fixtures/book_with_publisher.xml +7 -0
  23. data/test/fixtures/dictionary_of_attrs.xml +6 -0
  24. data/test/fixtures/dictionary_of_mixeds.xml +4 -0
  25. data/test/fixtures/dictionary_of_texts.xml +10 -0
  26. data/test/fixtures/library.xml +30 -0
  27. data/test/fixtures/library_uppercase.xml +30 -0
  28. data/test/fixtures/nameless_ageless_youth.xml +2 -0
  29. data/test/fixtures/person.xml +1 -0
  30. data/test/fixtures/person_with_guarded_mothers.xml +13 -0
  31. data/test/fixtures/person_with_mothers.xml +10 -0
  32. data/test/mocks/dictionaries.rb +56 -0
  33. data/test/mocks/mocks.rb +212 -0
  34. data/test/test_helper.rb +16 -0
  35. data/test/unit/options_test.rb +62 -0
  36. data/test/unit/roxml_test.rb +24 -0
  37. data/test/unit/string_test.rb +11 -0
  38. data/test/unit/to_xml_test.rb +75 -0
  39. data/test/unit/xml_attribute_test.rb +34 -0
  40. data/test/unit/xml_construct_test.rb +19 -0
  41. data/test/unit/xml_hash_test.rb +54 -0
  42. data/test/unit/xml_name_test.rb +14 -0
  43. data/test/unit/xml_namespace_test.rb +36 -0
  44. data/test/unit/xml_object_test.rb +94 -0
  45. data/test/unit/xml_text_test.rb +57 -0
  46. metadata +110 -0
@@ -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
@@ -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