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.
Files changed (102) hide show
  1. data/.gitignore +7 -0
  2. data/.gitmodules +3 -0
  3. data/History.txt +354 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +195 -0
  6. data/Rakefile +117 -0
  7. data/TODO +37 -0
  8. data/VERSION +1 -0
  9. data/examples/amazon.rb +35 -0
  10. data/examples/current_weather.rb +27 -0
  11. data/examples/dashed_elements.rb +20 -0
  12. data/examples/library.rb +40 -0
  13. data/examples/posts.rb +27 -0
  14. data/examples/rails.rb +70 -0
  15. data/examples/twitter.rb +37 -0
  16. data/examples/xml/active_record.xml +70 -0
  17. data/examples/xml/amazon.xml +133 -0
  18. data/examples/xml/current_weather.xml +89 -0
  19. data/examples/xml/dashed_elements.xml +52 -0
  20. data/examples/xml/posts.xml +23 -0
  21. data/examples/xml/twitter.xml +422 -0
  22. data/lib/roxml.rb +556 -0
  23. data/lib/roxml/definition.rb +238 -0
  24. data/lib/roxml/hash_definition.rb +25 -0
  25. data/lib/roxml/xml.rb +40 -0
  26. data/lib/roxml/xml/parsers/libxml.rb +85 -0
  27. data/lib/roxml/xml/parsers/nokogiri.rb +82 -0
  28. data/lib/roxml/xml/references.rb +322 -0
  29. data/roxml.gemspec +206 -0
  30. data/spec/definition_spec.rb +494 -0
  31. data/spec/examples/active_record_spec.rb +40 -0
  32. data/spec/examples/amazon_spec.rb +54 -0
  33. data/spec/examples/current_weather_spec.rb +37 -0
  34. data/spec/examples/dashed_elements_spec.rb +20 -0
  35. data/spec/examples/library_spec.rb +46 -0
  36. data/spec/examples/post_spec.rb +24 -0
  37. data/spec/examples/twitter_spec.rb +32 -0
  38. data/spec/roxml_spec.rb +372 -0
  39. data/spec/shared_specs.rb +15 -0
  40. data/spec/spec.opts +1 -0
  41. data/spec/spec_helper.rb +14 -0
  42. data/spec/support/libxml.rb +3 -0
  43. data/spec/support/nokogiri.rb +3 -0
  44. data/spec/xml/array_spec.rb +36 -0
  45. data/spec/xml/attributes_spec.rb +71 -0
  46. data/spec/xml/encoding_spec.rb +52 -0
  47. data/spec/xml/namespace_spec.rb +270 -0
  48. data/spec/xml/namespaces_spec.rb +67 -0
  49. data/spec/xml/object_spec.rb +82 -0
  50. data/spec/xml/parser_spec.rb +21 -0
  51. data/spec/xml/text_spec.rb +71 -0
  52. data/test/fixtures/book_malformed.xml +5 -0
  53. data/test/fixtures/book_pair.xml +8 -0
  54. data/test/fixtures/book_text_with_attribute.xml +5 -0
  55. data/test/fixtures/book_valid.xml +5 -0
  56. data/test/fixtures/book_with_authors.xml +7 -0
  57. data/test/fixtures/book_with_contributions.xml +9 -0
  58. data/test/fixtures/book_with_contributors.xml +7 -0
  59. data/test/fixtures/book_with_contributors_attrs.xml +7 -0
  60. data/test/fixtures/book_with_default_namespace.xml +9 -0
  61. data/test/fixtures/book_with_depth.xml +6 -0
  62. data/test/fixtures/book_with_octal_pages.xml +4 -0
  63. data/test/fixtures/book_with_publisher.xml +7 -0
  64. data/test/fixtures/book_with_wrapped_attr.xml +3 -0
  65. data/test/fixtures/dictionary_of_attr_name_clashes.xml +8 -0
  66. data/test/fixtures/dictionary_of_attrs.xml +6 -0
  67. data/test/fixtures/dictionary_of_guarded_names.xml +6 -0
  68. data/test/fixtures/dictionary_of_mixeds.xml +4 -0
  69. data/test/fixtures/dictionary_of_name_clashes.xml +10 -0
  70. data/test/fixtures/dictionary_of_names.xml +4 -0
  71. data/test/fixtures/dictionary_of_texts.xml +10 -0
  72. data/test/fixtures/library.xml +30 -0
  73. data/test/fixtures/library_uppercase.xml +30 -0
  74. data/test/fixtures/muffins.xml +3 -0
  75. data/test/fixtures/nameless_ageless_youth.xml +2 -0
  76. data/test/fixtures/node_with_attr_name_conflicts.xml +1 -0
  77. data/test/fixtures/node_with_name_conflicts.xml +4 -0
  78. data/test/fixtures/numerology.xml +4 -0
  79. data/test/fixtures/person.xml +1 -0
  80. data/test/fixtures/person_with_guarded_mothers.xml +13 -0
  81. data/test/fixtures/person_with_mothers.xml +10 -0
  82. data/test/load_test.rb +6 -0
  83. data/test/mocks/dictionaries.rb +57 -0
  84. data/test/mocks/mocks.rb +279 -0
  85. data/test/support/fixtures.rb +11 -0
  86. data/test/test_helper.rb +34 -0
  87. data/test/unit/definition_test.rb +235 -0
  88. data/test/unit/deprecations_test.rb +24 -0
  89. data/test/unit/to_xml_test.rb +81 -0
  90. data/test/unit/xml_attribute_test.rb +39 -0
  91. data/test/unit/xml_block_test.rb +81 -0
  92. data/test/unit/xml_bool_test.rb +122 -0
  93. data/test/unit/xml_convention_test.rb +150 -0
  94. data/test/unit/xml_hash_test.rb +115 -0
  95. data/test/unit/xml_initialize_test.rb +49 -0
  96. data/test/unit/xml_name_test.rb +141 -0
  97. data/test/unit/xml_namespace_test.rb +31 -0
  98. data/test/unit/xml_object_test.rb +205 -0
  99. data/test/unit/xml_required_test.rb +94 -0
  100. data/test/unit/xml_text_test.rb +71 -0
  101. data/website/index.html +98 -0
  102. metadata +300 -0
@@ -0,0 +1,3 @@
1
+ <muffins>
2
+ <bakers_dozens>3</bakers_dozens>
3
+ </muffins>
@@ -0,0 +1,2 @@
1
+ <person>
2
+ </person>
@@ -0,0 +1 @@
1
+ <node content="Just junk... really" name="Cartwheel" />
@@ -0,0 +1,4 @@
1
+ <node>
2
+ <content>Just junk... really</content>
3
+ <name>Cartwheel</name>
4
+ </node>
@@ -0,0 +1,4 @@
1
+ <numerology>
2
+ <prediction number="13" meaning="A bad number" />
3
+ <prediction number="7" meaning="A good number" />
4
+ </numerology>
@@ -0,0 +1 @@
1
+ <person>Ben Franklin</person>
@@ -0,0 +1,13 @@
1
+ <person>
2
+ <name>Ben &quot;Benji&quot; Franklin</name>
3
+ <mother>
4
+ <person>
5
+ <name>Abiah &apos;Abby&apos; Folger</name>
6
+ <mother>
7
+ <person>
8
+ <name>Madeup Mother &lt; the third &gt;</name>
9
+ </person>
10
+ </mother>
11
+ </person>
12
+ </mother>
13
+ </person>
@@ -0,0 +1,10 @@
1
+ <person>
2
+ <name>Ben Franklin</name>
3
+ <mother>
4
+ <name>Abiah Folger</name>
5
+ <mother>
6
+ <name>Madeup Mother</name>
7
+ </mother>
8
+ </mother>
9
+ </person>
10
+
@@ -0,0 +1,6 @@
1
+ require 'fileutils'
2
+ FileUtils.cd(File.dirname(__FILE__))
3
+
4
+ require 'rubygems'
5
+ require 'roxml'
6
+ puts ROXML::VERSION
@@ -0,0 +1,57 @@
1
+ require 'lib/roxml'
2
+
3
+ class DictionaryOfAttrs
4
+ include ROXML
5
+
6
+ xml_name :dictionary
7
+ xml_reader :definitions, :as => {:key => '@dt',
8
+ :value => '@dd'}, :in => :definitions
9
+ end
10
+
11
+ class DictionaryOfTexts
12
+ include ROXML
13
+
14
+ xml_name :dictionary
15
+ xml_reader :definitions, :as => {:key => :word,
16
+ :value => :meaning}
17
+ end
18
+
19
+ class DictionaryOfMixeds
20
+ include ROXML
21
+
22
+ xml_name :dictionary
23
+ xml_reader :definitions, :as => {:key => '@word',
24
+ :value => :content}
25
+ end
26
+
27
+ class DictionaryOfNames
28
+ include ROXML
29
+
30
+ xml_name :dictionary
31
+ xml_reader :definitions, :as => {:key => :name,
32
+ :value => :content}
33
+ end
34
+
35
+ class DictionaryOfGuardedNames
36
+ include ROXML
37
+
38
+ xml_name :dictionary
39
+ xml_reader :definitions, :as => {:key => :name,
40
+ :value => :content}, :in => :definitions
41
+ end
42
+
43
+ class DictionaryOfNameClashes
44
+ include ROXML
45
+
46
+ xml_name :dictionary
47
+ xml_reader :definitions, :as => {:key => 'name',
48
+ :value => 'content'}, :from => :definition
49
+ end
50
+
51
+ class DictionaryOfAttrNameClashes
52
+ include ROXML
53
+
54
+ xml_name :dictionary
55
+ xml_reader :definitions, :as => {:key => '@name',
56
+ :value => 'content'}, :from => :definition
57
+ end
@@ -0,0 +1,279 @@
1
+ require "lib/roxml"
2
+
3
+ class Muffins
4
+ include ROXML
5
+
6
+ xml_reader(:count, :from => 'bakers_dozens') {|val| val.to_i * 13 }
7
+ end
8
+
9
+ class MuffinsWithStackedBlocks
10
+ include ROXML
11
+
12
+ xml_reader(:count, :from => 'bakers_dozens', :as => Integer) {|val| val * 13 }
13
+ end
14
+
15
+ class Numerology
16
+ include ROXML
17
+
18
+ xml_reader :predictions, :as => {:key => '@number', :value => '@meaning'} do |k, v|
19
+ [Integer(k), v]
20
+ end
21
+ end
22
+
23
+ class Contributor
24
+ include ROXML
25
+
26
+ xml_reader :role, :from => :attr
27
+ xml_reader :name
28
+ end
29
+
30
+ class WriteableContributor
31
+ include ROXML
32
+
33
+ xml_accessor :role, :from => :attr
34
+ xml_accessor :name
35
+ end
36
+
37
+ class Book
38
+ include ROXML
39
+
40
+ xml_accessor :isbn, :from => '@ISBN'
41
+ xml_reader :title
42
+ xml_reader :description, :cdata => true
43
+ xml_reader :author
44
+ xml_accessor :pages, :from => 'pagecount', :as => Integer
45
+ end
46
+
47
+ class BookWithRequired
48
+ include ROXML
49
+
50
+ xml_accessor :isbn, :from => '@ISBN', :required => true
51
+ xml_reader :title, :required => true
52
+ xml_reader :contributors, :as => [Contributor], :in => 'contributor_array', :required => true
53
+ xml_reader :contributor_hash, :as => {:key => '@role', :value => '@name'},
54
+ :from => 'contributor', :in => 'contributor_hash', :required => true
55
+ end
56
+
57
+ class BookWithAttrFrom
58
+ include ROXML
59
+
60
+ xml_accessor :isbn, :from => '@ISBN'
61
+ end
62
+
63
+ class BookWithWrappedAttr
64
+ include ROXML
65
+
66
+ xml_name :book
67
+ xml_accessor :isbn, :from => '@ISBN', :in => 'ids'
68
+ end
69
+
70
+ class Measurement
71
+ include ROXML
72
+
73
+ xml_reader :units, :from => :attr
74
+ xml_reader :value, :from => :content, :as => Float
75
+
76
+ def initialize(value = 0, units = 'pixels')
77
+ @value = Float(value)
78
+ @units = units.to_s
79
+ normalize_hundredths
80
+ end
81
+
82
+ def to_s
83
+ "#{value} #{units}"
84
+ end
85
+
86
+ def ==(other)
87
+ other.units == @units && other.value == @value
88
+ end
89
+
90
+ private
91
+ def after_parse
92
+ normalize_hundredths
93
+ end
94
+
95
+ def normalize_hundredths
96
+ if @units.starts_with? 'hundredths-'
97
+ @value /= 100
98
+ @units = @units.split('hundredths-')[1]
99
+ end
100
+ end
101
+ end
102
+
103
+ class BookWithDepth
104
+ include ROXML
105
+
106
+ xml_reader :isbn, :from => '@ISBN'
107
+ xml_reader :title
108
+ xml_reader :description, :cdata => true
109
+ xml_reader :author
110
+ xml_reader :depth, :as => Measurement
111
+ end
112
+
113
+ class Author
114
+ include ROXML
115
+
116
+ xml_reader :role, :from => :attr
117
+ xml_reader :text, :from => :content
118
+ end
119
+
120
+ class BookWithAuthors
121
+ include ROXML
122
+
123
+ xml_name :book
124
+ xml_reader :isbn, :from => '@ISBN'
125
+ xml_reader :title
126
+ xml_reader :description, :cdata => true
127
+ xml_reader :authors, :as => []
128
+ end
129
+
130
+ class BookWithAuthorTextAttribute
131
+ include ROXML
132
+
133
+ xml_name :book
134
+ xml_reader :isbn, :from => '@ISBN'
135
+ xml_reader :title
136
+ xml_reader :description, :cdata => true
137
+ xml_reader :author, :as => Author
138
+ end
139
+
140
+ class BookWithContributions
141
+ include ROXML
142
+
143
+ xml_name :book
144
+ xml_reader :isbn, :from => :attr
145
+ xml_reader :title
146
+ xml_reader :description
147
+ xml_reader :contributions, :as => [Contributor], :from => 'contributor', :in => "contributions"
148
+ end
149
+
150
+ class BookWithContributors
151
+ include ROXML
152
+
153
+ xml_name :book
154
+ xml_reader :isbn, :from => :attr
155
+ xml_reader :title
156
+ xml_reader :description
157
+ xml_reader :contributors, :as => [Contributor]
158
+ end
159
+
160
+ class WriteableBookWithContributors
161
+ include ROXML
162
+
163
+ xml_name :book
164
+ xml_accessor :isbn, :from => :attr
165
+ xml_accessor :title
166
+ xml_accessor :description
167
+ xml_accessor :contributors, :as => [Contributor]
168
+ end
169
+
170
+ class NamelessBook
171
+ include ROXML
172
+
173
+ xml_reader :isbn, :from => :attr
174
+ xml_reader :title
175
+ xml_reader :description
176
+ xml_reader :contributors, :as => [Contributor]
177
+ end
178
+
179
+ class Publisher
180
+ include ROXML
181
+
182
+ xml_reader :name
183
+ end
184
+
185
+ class BookWithPublisher
186
+ include ROXML
187
+
188
+ xml_reader :book
189
+ xml_reader :isbn, :from => :attr
190
+ xml_reader :title
191
+ xml_reader :description
192
+ xml_reader :publisher, :as => Publisher
193
+ end
194
+
195
+ class BookPair
196
+ include ROXML
197
+
198
+ xml_reader :isbn, :from => :attr
199
+ xml_reader :title
200
+ xml_reader :description
201
+ xml_reader :author
202
+ xml_reader :book, :as => Book
203
+ end
204
+
205
+ class Library
206
+ include ROXML
207
+
208
+ xml_reader :name
209
+ xml_reader :books, :as => [BookWithContributions]
210
+ end
211
+
212
+ class UppercaseLibrary
213
+ include ROXML
214
+
215
+ xml_name :library
216
+ xml_reader :name, :from => 'NAME'
217
+ xml_reader :books, :as => [BookWithContributions], :from => 'BOOK'
218
+ end
219
+
220
+ class LibraryWithBooksOfUnderivableName
221
+ include ROXML
222
+
223
+ xml_accessor :name
224
+ xml_reader :novels, :as => [NamelessBook]
225
+ end
226
+
227
+ class NodeWithNameConflicts
228
+ include ROXML
229
+
230
+ xml_name :node
231
+ xml_reader :content
232
+ xml_reader :name
233
+ end
234
+
235
+ class NodeWithAttrNameConflicts
236
+ include ROXML
237
+
238
+ xml_name :node
239
+ xml_reader :content, :from => '@content'
240
+ xml_reader :name, :from => '@name'
241
+ end
242
+
243
+ class Person
244
+ include ROXML
245
+
246
+ xml_accessor :age, :from => :attr, :else => 21
247
+ xml_accessor :name, :from => :content, :else => 'Unknown'
248
+
249
+ def self.blank
250
+ new.tap do |instance|
251
+ instance.age = 21
252
+ instance.name = 'Unknown'
253
+ end
254
+ end
255
+ end
256
+
257
+ class PersonWithMother
258
+ include ROXML
259
+
260
+ xml_name :person
261
+ xml_reader :name
262
+ xml_reader :mother, :as => PersonWithMother, :from => 'mother'
263
+ end
264
+
265
+ class PersonWithGuardedMother
266
+ include ROXML
267
+
268
+ xml_name :person
269
+ xml_reader :name
270
+ xml_reader :mother, :as => PersonWithGuardedMother, :from => :person, :in => :mother
271
+ end
272
+
273
+ class PersonWithMotherOrMissing
274
+ include ROXML
275
+
276
+ xml_reader :age, :from => :attr, :else => 21
277
+ xml_reader :name, :else => 'Anonymous'
278
+ xml_reader :mother,:as => PersonWithMotherOrMissing, :else => Person.blank
279
+ end
@@ -0,0 +1,11 @@
1
+ def fixture(name)
2
+ File.read(fixture_path(name))
3
+ end
4
+
5
+ def xml_fixture(name)
6
+ ROXML::XML.parse_file(fixture_path(name)).root
7
+ end
8
+
9
+ def fixture_path(name)
10
+ "test/fixtures/#{name}.xml"
11
+ end
@@ -0,0 +1,34 @@
1
+ require 'rubygems'
2
+ require 'active_support/test_case'
3
+ require 'test/mocks/mocks'
4
+ require 'test/mocks/dictionaries'
5
+ require 'test/support/fixtures'
6
+
7
+ def to_xml_test(*names)
8
+ names = names.first if names.size == 1 && names.first.is_a?(Hash)
9
+ names.each do |name, xml_name|
10
+ xml_name ||= name
11
+
12
+ define_method "test_#{name}" do
13
+ klass = name.is_a?(Symbol) ? name.to_s.camelize.constantize : name
14
+ xml = xml_name.is_a?(Symbol) ? xml_fixture(xml_name) : xml_name
15
+
16
+ dict = klass.from_xml(xml)
17
+ xml = remove_children(xml)
18
+ assert_equal xml.to_s, dict.to_xml.to_s
19
+ end
20
+ end
21
+ end
22
+
23
+ def remove_children(xml)
24
+ xml = ROXML::XML.parse_string(xml).root if xml.is_a?(String)
25
+ return unless xml.respond_to? :children
26
+ xml.children.each do |child|
27
+ if child.to_s.blank?
28
+ defined?(Nokogiri) ? child.remove : child.remove!
29
+ else
30
+ remove_children(child)
31
+ end
32
+ end
33
+ xml
34
+ end
@@ -0,0 +1,235 @@
1
+ require 'test/test_helper'
2
+
3
+ class TestDefinition < ActiveSupport::TestCase
4
+ def assert_hash(opts, kvp)
5
+ assert opts.hash?
6
+ assert !opts.array?
7
+ assert_equal kvp, {opts.hash.key.sought_type => opts.hash.key.name,
8
+ opts.hash.value.sought_type => opts.hash.value.name}
9
+ end
10
+
11
+ def test_empty_array_means_as_array_for_text
12
+ opts = ROXML::Definition.new(:authors, :as => [])
13
+ assert opts.array?
14
+ assert_equal :text, opts.sought_type
15
+ end
16
+
17
+ def test_attr_in_array_means_as_array_for_attr
18
+ opts = ROXML::Definition.new(:authors, :as => [], :from => :attr)
19
+ assert opts.array?
20
+ assert_equal :attr, opts.sought_type
21
+ end
22
+
23
+ def test_block_shorthand_in_array_means_array
24
+ opts = ROXML::Definition.new(:intarray, :as => [Integer])
25
+ assert opts.array?
26
+ assert_equal :text, opts.sought_type
27
+ assert 1, opts.blocks.size
28
+ end
29
+
30
+ def test_required
31
+ assert !ROXML::Definition.new(:author).required?
32
+ assert ROXML::Definition.new(:author, :required => true).required?
33
+ assert !ROXML::Definition.new(:author, :required => false).required?
34
+ end
35
+
36
+ def test_required_conflicts_with_else
37
+ assert_raise ArgumentError do
38
+ ROXML::Definition.new(:author, :required => true, :else => 'Johnny')
39
+ end
40
+ assert_nothing_raised do
41
+ ROXML::Definition.new(:author, :required => false, :else => 'Johnny')
42
+ end
43
+ end
44
+
45
+ def test_hash_of_attrs
46
+ opts = ROXML::Definition.new(:attributes, :as => {:key => '@name', :value => '@value'})
47
+ assert_hash(opts, :attr => 'name', :attr => 'value')
48
+ end
49
+
50
+ def test_hash_with_attr_key_and_text_val
51
+ opts = ROXML::Definition.new(:attributes, :as => {:key => '@name',
52
+ :value => :value})
53
+ assert_hash(opts, :attr => 'name', :text => 'value')
54
+ end
55
+
56
+ def test_hash_with_string_class_for_type
57
+ opts = ROXML::Definition.new(:attributes, :as => {:key => 'name',
58
+ :value => 'value'})
59
+ assert_hash(opts, :text => 'name', :text => 'value')
60
+ end
61
+
62
+ def test_hash_with_attr_key_and_content_val
63
+ opts = ROXML::Definition.new(:attributes, :as => {:key => '@name',
64
+ :value => :content})
65
+ assert_hash(opts, :attr => 'name', :text => '.')
66
+ end
67
+
68
+ def test_hash_with_options
69
+ opts = ROXML::Definition.new(:definitions, :as => {:key => '@dt', :value => '@dd'},
70
+ :in => :definitions, :from => 'definition')
71
+ assert_hash(opts, :attr => 'dt', :attr => 'dd')
72
+ assert_equal 'definition', opts.hash.wrapper
73
+ end
74
+
75
+ def test_no_block_shorthand_means_no_block
76
+ assert ROXML::Definition.new(:count).blocks.empty?
77
+ end
78
+
79
+ def test_block_integer_shorthand
80
+ assert_equal 3, ROXML::Definition.new(:count, :as => Integer).blocks.first['3']
81
+ end
82
+
83
+ def test_block_float_shorthand
84
+ assert_equal 3.1, ROXML::Definition.new(:count, :as => Float).blocks.first['3.1']
85
+ end
86
+
87
+ def test_from_attr_is_supported
88
+ opts = ROXML::Definition.new(:count, :from => :attr)
89
+ assert_equal "count", opts.name
90
+ assert_equal :attr, opts.sought_type
91
+ end
92
+
93
+ def test_from_at_name_is_supported
94
+ opts = ROXML::Definition.new(:count, :from => "@COUNT")
95
+ assert_equal "COUNT", opts.name
96
+ assert_equal :attr, opts.sought_type
97
+ end
98
+
99
+ def test_multiple_shorthands_raises
100
+ assert_raise ArgumentError do
101
+ assert_deprecated do
102
+ ROXML::Definition.new(:count, :as => [Float, Integer])
103
+ end
104
+ end
105
+ end
106
+
107
+ def test_stacked_blocks
108
+ assert_equal 2, ROXML::Definition.new(:count, :as => Integer) {|val| val.to_i }.blocks.size
109
+ assert_equal 2, ROXML::Definition.new(:count, :as => Float) {|val| val.object_id }.blocks.size
110
+ end
111
+
112
+ def test_block_shorthand_supports_bool
113
+ assert_equal true, ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("1")
114
+ assert_equal [true, false, nil], ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call(["TrUe", "0", "328"])
115
+ end
116
+
117
+ def test_block_shorthand_supports_integer
118
+ assert_equal nil, ROXML::Definition.new(:floatvalue, :as => Integer).blocks.first.call(" ")
119
+ assert_equal 792, ROXML::Definition.new(:floatvalue, :as => Integer).blocks.first.call("792")
120
+ assert_raise ArgumentError do
121
+ ROXML::Definition.new(:floatvalue, :as => Integer).blocks.first.call("792.13")
122
+ end
123
+ assert_equal [792, 12, 328], ROXML::Definition.new(:floatvalue, :as => Integer).blocks.first.call(["792", "12", "328"])
124
+ end
125
+
126
+ def test_block_shorthand_supports_float
127
+ assert_equal nil, ROXML::Definition.new(:floatvalue, :as => Float).blocks.first.call(" ")
128
+ assert_equal 792.13, ROXML::Definition.new(:floatvalue, :as => Float).blocks.first.call("792.13")
129
+ assert_equal 240.0, ROXML::Definition.new(:floatvalue, :as => Float).blocks.first.call("240")
130
+ assert_equal [792.13, 240.0, 3.14], ROXML::Definition.new(:floatvalue, :as => Float).blocks.first.call(["792.13", "240", "3.14"])
131
+ end
132
+
133
+ def test_block_shorthand_supports_time
134
+ assert_equal nil, ROXML::Definition.new(:floatvalue, :as => Time).blocks.first.call(" ")
135
+ assert_equal 31, ROXML::Definition.new(:datevalue, :as => Time).blocks.first.call("12:31am").min
136
+ assert_equal [31, 0, 59], ROXML::Definition.new(:datevalue, :as => Time).blocks.first.call(["12:31am", "3:00pm", "11:59pm"]).map(&:min)
137
+ end
138
+
139
+ def test_block_shorthand_supports_date
140
+ assert_equal nil, ROXML::Definition.new(:floatvalue, :as => Date).blocks.first.call(" ")
141
+ assert_equal "1970-09-03", ROXML::Definition.new(:datevalue, :as => Date).blocks.first.call("September 3rd, 1970").to_s
142
+ assert_equal ["1970-09-03", "1776-07-04"], ROXML::Definition.new(:datevalue, :as => Date).blocks.first.call(["September 3rd, 1970", "1776-07-04"]).map(&:to_s)
143
+ end
144
+
145
+ def test_block_shorthand_supports_datetime
146
+ assert_equal nil, ROXML::Definition.new(:floatvalue, :as => DateTime).blocks.first.call(" ")
147
+ assert_equal "1970-09-03T12:05:00+00:00", ROXML::Definition.new(:datevalue, :as => DateTime).blocks.first.call("12:05pm, September 3rd, 1970").to_s
148
+ assert_equal ["1970-09-03T12:05:00+00:00", "1700-05-22T15:00:00+00:00"], ROXML::Definition.new(:datevalue, :as => DateTime).blocks.first.call(["12:05pm, September 3rd, 1970", "3:00pm, May 22, 1700"]).map(&:to_s)
149
+ end
150
+
151
+ def test_name_explicit_indicates_whether_from_option_is_present
152
+ assert_equal true, ROXML::Definition.new(:element, :from => 'somewhere').name_explicit?
153
+ assert_equal false, ROXML::Definition.new(:element).name_explicit?
154
+ end
155
+
156
+ def test_xpath_in_is_formed_properly
157
+ opts = ROXML::Definition.new(:manufacturer, :in => './')
158
+ assert_equal "manufacturer", opts.name
159
+ assert_equal "./", opts.wrapper
160
+ end
161
+
162
+ def test_cdata_is_specifiable
163
+ assert ROXML::Definition.new(:manufacturer, :cdata => true).cdata?
164
+ end
165
+
166
+ def test_as_supports_generic_roxml_types
167
+ assert_equal RoxmlObject, ROXML::Definition.new(:type, :as => RoxmlObject).sought_type
168
+ end
169
+
170
+ def test_as_supports_generic_roxml_types_in_arrays
171
+ assert_equal RoxmlObject, ROXML::Definition.new(:types, :as => [RoxmlObject]).sought_type
172
+ end
173
+
174
+ def test_default_works
175
+ opts = ROXML::Definition.new(:missing, :else => true)
176
+ assert_equal true, opts.to_ref(RoxmlObject.new).value_in(ROXML::XML.parse_string('<xml></xml>'))
177
+ end
178
+
179
+ def test_default_works_for_arrays
180
+ opts = ROXML::Definition.new(:missing, :as => [])
181
+ assert_equal [], opts.to_ref(RoxmlObject.new).value_in(ROXML::XML.parse_string('<xml></xml>'))
182
+ end
183
+
184
+ def test_default_works_for_recursive_objects
185
+ opts = ROXML::Definition.new(:missing, :as => RecursiveObject, :else => false)
186
+ assert_equal false, opts.to_ref(RoxmlObject.new).value_in(ROXML::XML.parse_string('<xml></xml>'))
187
+ end
188
+
189
+ def test_content_is_accepted_as_from
190
+ assert ROXML::Definition.new(:author, :from => :content).content?
191
+ assert ROXML::Definition.new(:author, :from => '.').content?
192
+ end
193
+
194
+ def test_content_is_a_recognized_type
195
+ opts = ROXML::Definition.new(:author, :from => :content)
196
+ assert opts.content?
197
+ assert_equal '.', opts.name
198
+ assert_equal :text, opts.sought_type
199
+ end
200
+
201
+ def test_content_symbol_as_target_is_translated_to_string
202
+ opts = ROXML::Definition.new(:content, :from => :attr)
203
+ assert_equal 'content', opts.name
204
+ assert_equal :attr, opts.sought_type
205
+ end
206
+
207
+ def test_attr_is_accepted_as_from
208
+ assert_equal :attr, ROXML::Definition.new(:author, :from => :attr).sought_type
209
+ assert_equal :attr, ROXML::Definition.new(:author, :from => '@author').sought_type
210
+ end
211
+
212
+ def test_attr_is_a_recognized_type
213
+ opts = ROXML::Definition.new(:author, :from => :attr)
214
+ assert_equal 'author', opts.name
215
+ assert_equal :attr, opts.sought_type
216
+ end
217
+ end
218
+
219
+ class RecursiveObject
220
+ include ROXML
221
+
222
+ xml_reader :next, :as => RecursiveObject, :else => true
223
+ end
224
+
225
+ class RoxmlObject
226
+ include ROXML
227
+ end
228
+
229
+ class HashDefinitionTest < ActiveSupport::TestCase
230
+ def test_content_detected_as_from
231
+ opts = ROXML::Definition.new(:hash, :as => {:key => :content, :value => :name})
232
+ assert_equal '.', opts.hash.key.name
233
+ assert_equal :text, opts.hash.key.sought_type
234
+ end
235
+ end