roxml 2.4.3 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +54 -0
- data/Manifest.txt +9 -6
- data/README.rdoc +24 -17
- data/Rakefile +2 -1
- data/TODO +30 -31
- data/examples/active_record.rb +69 -0
- data/examples/amazon.rb +1 -1
- data/examples/current_weather.rb +1 -1
- data/examples/posts.rb +8 -8
- data/examples/twitter.rb +2 -2
- data/examples/xml/active_record.xml +70 -0
- data/lib/roxml.rb +174 -174
- data/lib/roxml/definition.rb +165 -89
- data/lib/roxml/extensions/deprecation.rb +5 -0
- data/lib/roxml/extensions/string/conversions.rb +2 -3
- data/lib/roxml/hash_definition.rb +26 -25
- data/lib/roxml/xml.rb +15 -6
- data/lib/roxml/xml/parsers/libxml.rb +9 -6
- data/lib/roxml/xml/parsers/rexml.rb +1 -1
- data/lib/roxml/xml/references.rb +14 -17
- data/roxml.gemspec +8 -5
- data/spec/definition_spec.rb +563 -0
- data/spec/examples/active_record_spec.rb +43 -0
- data/spec/roxml_spec.rb +372 -0
- data/spec/shared_specs.rb +15 -0
- data/spec/spec_helper.rb +21 -4
- data/spec/string_spec.rb +15 -0
- data/spec/xml/parser_spec.rb +22 -0
- data/test/fixtures/book_valid.xml +1 -1
- data/test/fixtures/person_with_guarded_mothers.xml +3 -3
- data/test/mocks/mocks.rb +57 -45
- data/test/unit/definition_test.rb +161 -12
- data/test/unit/deprecations_test.rb +97 -0
- data/test/unit/to_xml_test.rb +30 -1
- data/test/unit/xml_bool_test.rb +15 -3
- data/test/unit/xml_construct_test.rb +6 -6
- data/test/unit/xml_hash_test.rb +18 -0
- data/test/unit/xml_initialize_test.rb +6 -3
- data/test/unit/xml_object_test.rb +66 -5
- data/test/unit/xml_text_test.rb +3 -0
- metadata +23 -15
- data/test/unit/array_test.rb +0 -16
- data/test/unit/freeze_test.rb +0 -71
- data/test/unit/inheritance_test.rb +0 -63
- data/test/unit/overriden_output_test.rb +0 -33
- data/test/unit/roxml_test.rb +0 -60
- data/test/unit/string_test.rb +0 -11
data/lib/roxml.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.dirname(__FILE__)) unless
|
2
2
|
$LOAD_PATH.include?(File.dirname(__FILE__)) || $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
|
3
3
|
|
4
|
+
require 'uri'
|
5
|
+
|
4
6
|
%w(extensions definition xml).each do |file|
|
5
7
|
require File.join('roxml', file)
|
6
8
|
end
|
7
9
|
|
8
10
|
module ROXML # :nodoc:
|
9
|
-
VERSION = '2.
|
11
|
+
VERSION = '2.5.0'
|
10
12
|
|
11
13
|
def self.included(base) # :nodoc:
|
12
14
|
base.extend ClassMethods::Accessors,
|
@@ -46,8 +48,8 @@ module ROXML # :nodoc:
|
|
46
48
|
# class Measurement
|
47
49
|
# include ROXML
|
48
50
|
#
|
49
|
-
# xml_reader :units, :attr
|
50
|
-
# xml_reader :value, :content
|
51
|
+
# xml_reader :units, :from => :attr
|
52
|
+
# xml_reader :value, :from => :content
|
51
53
|
#
|
52
54
|
# def xml_initialize
|
53
55
|
# # the object is instantiated, and all xml attributes are imported
|
@@ -69,14 +71,15 @@ module ROXML # :nodoc:
|
|
69
71
|
# #xml_initialize may be written to take arguments, in which case extra arguments
|
70
72
|
# from from_xml will be passed into the function.
|
71
73
|
#
|
72
|
-
def xml_initialize
|
74
|
+
def xml_initialize # :nodoc:
|
73
75
|
end
|
76
|
+
deprecate :xml_initialize => :after_parse
|
74
77
|
end
|
75
78
|
|
76
79
|
module Conversions
|
77
80
|
# Returns a LibXML::XML::Node or a REXML::Element representing this object
|
78
81
|
def to_xml(name = nil)
|
79
|
-
returning XML::Node.
|
82
|
+
returning XML::Node.new(name || self.class.tag_name) do |root|
|
80
83
|
self.class.roxml_attrs.each do |attr|
|
81
84
|
ref = attr.to_ref(self)
|
82
85
|
v = ref.to_xml
|
@@ -175,9 +178,9 @@ module ROXML # :nodoc:
|
|
175
178
|
(@roxml_naming_convention || superclass.try(:roxml_naming_convention)).freeze
|
176
179
|
end
|
177
180
|
|
178
|
-
# Declares
|
179
|
-
# or a typed collection of nodes.
|
180
|
-
#
|
181
|
+
# Declares a reference to a certain xml element, whether an attribute, a node,
|
182
|
+
# or a typed collection of nodes. This method does not add a corresponding accessor
|
183
|
+
# to the object. For that behavior see the similar methods: .xml_reader and .xml_accessor.
|
181
184
|
#
|
182
185
|
# == Sym Option
|
183
186
|
# [sym] Symbol representing the name of the accessor.
|
@@ -187,12 +190,12 @@ module ROXML # :nodoc:
|
|
187
190
|
# if no other is declared. For example,
|
188
191
|
#
|
189
192
|
# xml_reader :bob
|
190
|
-
# xml_accessor :pony, :attr
|
193
|
+
# xml_accessor :pony, :from => :attr
|
191
194
|
#
|
192
195
|
# are equivalent to:
|
193
196
|
#
|
194
197
|
# xml_reader :bob, :from => 'bob'
|
195
|
-
# xml_accessor :pony, :
|
198
|
+
# xml_accessor :pony, :from => '@pony'
|
196
199
|
#
|
197
200
|
# === Boolean attributes
|
198
201
|
# If the name ends in a ?, ROXML will attempt to coerce the value to true or false,
|
@@ -200,7 +203,7 @@ module ROXML # :nodoc:
|
|
200
203
|
# to false, as shown below:
|
201
204
|
#
|
202
205
|
# xml_reader :desirable?
|
203
|
-
# xml_reader :bizzare?, :
|
206
|
+
# xml_reader :bizzare?, :from => '@BIZZARE'
|
204
207
|
#
|
205
208
|
# x = #from_xml(%{
|
206
209
|
# <object BIZZARE="1">
|
@@ -234,94 +237,90 @@ module ROXML # :nodoc:
|
|
234
237
|
# }).strange?
|
235
238
|
# => DUNNO
|
236
239
|
#
|
237
|
-
# ==
|
238
|
-
#
|
239
|
-
# or used as :from, pointing to a xml name to indicate both type and attribute name.
|
240
|
-
# Also, any type may be passed via an array to indicate that multiple instances
|
241
|
-
# of the object should be returned as an array.
|
240
|
+
# == Blocks
|
241
|
+
# You may also pass a block which manipulates the associated parsed value.
|
242
242
|
#
|
243
|
-
#
|
244
|
-
#
|
243
|
+
# class Muffins
|
244
|
+
# include ROXML
|
245
245
|
#
|
246
|
-
#
|
247
|
-
# class Book
|
248
|
-
# xml_reader :isbn, :attr => "ISBN" # 'ISBN' is used to specify :from
|
249
|
-
# xml_accessor :title, :attr # :from defaults to :title
|
246
|
+
# xml_reader(:count, :from => 'bakers_dozens') {|val| val.to_i * 13 }
|
250
247
|
# end
|
251
248
|
#
|
252
|
-
#
|
253
|
-
#
|
249
|
+
# For hash types, the block recieves the key and value as arguments, and they should
|
250
|
+
# be returned as an array of [key, value]
|
254
251
|
#
|
255
|
-
#
|
256
|
-
# The default type, if none is specified. Declares an accessor that
|
257
|
-
# represents a text node from XML.
|
252
|
+
# For array types, the entire array is passed in, and must be returned in the same fashion.
|
258
253
|
#
|
259
|
-
#
|
260
|
-
#
|
261
|
-
#
|
262
|
-
#
|
263
|
-
# xml_reader :title
|
264
|
-
# end
|
254
|
+
# == Options
|
255
|
+
# === :as
|
256
|
+
# ==== Basic Types
|
257
|
+
# Allows you to specify one of several basic types to return the value as. For example
|
265
258
|
#
|
266
|
-
#
|
259
|
+
# xml_reader :count, :as => Integer
|
260
|
+
#
|
261
|
+
# is equivalent to:
|
262
|
+
#
|
263
|
+
# xml_reader(:count) {|val| Integer(val) unless val.empty? }
|
264
|
+
#
|
265
|
+
# Such block shorthands for Integer, Float, Fixnum, BigDecimal, Date, Time, and DateTime
|
266
|
+
# are currently available, but only for non-Hash declarations.
|
267
|
+
#
|
268
|
+
# To reference many elements, put the desired type in a literal array. e.g.:
|
269
|
+
#
|
270
|
+
# xml_reader :counts, :as => [Integer]
|
271
|
+
#
|
272
|
+
# Even an array of :text nodes can be specified with :as => []
|
273
|
+
#
|
274
|
+
# xml_reader :quotes, :as => []
|
275
|
+
#
|
276
|
+
# === Other ROXML Class
|
277
|
+
# Declares an accessor that represents another ROXML class as child XML element
|
278
|
+
# (one-to-one or composition) or array of child elements (one-to-many or
|
279
|
+
# aggregation) of this type. Default is one-to-one. For one-to-many, simply pass the class
|
280
|
+
# as the only element in an array.
|
281
|
+
#
|
282
|
+
# Composition example:
|
267
283
|
# <book>
|
268
|
-
# <
|
269
|
-
#
|
270
|
-
#
|
284
|
+
# <publisher>
|
285
|
+
# <name>Pragmatic Bookshelf</name>
|
286
|
+
# </publisher>
|
271
287
|
# </book>
|
272
288
|
#
|
273
|
-
#
|
289
|
+
# Can be mapped using the following code:
|
290
|
+
# class Book
|
291
|
+
# xml_reader :publisher, :as => Publisher
|
292
|
+
# end
|
274
293
|
#
|
275
|
-
#
|
294
|
+
# Aggregation example:
|
295
|
+
# <library>
|
296
|
+
# <books>
|
297
|
+
# <book/>
|
298
|
+
# <book/>
|
299
|
+
# </books>
|
300
|
+
# </library>
|
301
|
+
#
|
302
|
+
# Can be mapped using the following code:
|
276
303
|
# class Library
|
277
|
-
# xml_reader :books, [
|
304
|
+
# xml_reader :books, :as => [Book], :in => "books"
|
278
305
|
# end
|
279
306
|
#
|
280
|
-
#
|
307
|
+
# If you don't have the <books> tag to wrap around the list of <book> tags:
|
281
308
|
# <library>
|
282
|
-
#
|
283
|
-
#
|
284
|
-
#
|
285
|
-
# <book>Gödel, Escher, Bach</book>
|
286
|
-
# </books>
|
309
|
+
# <name>Ruby books</name>
|
310
|
+
# <book/>
|
311
|
+
# <book/>
|
287
312
|
# </library>
|
288
313
|
#
|
289
|
-
#
|
290
|
-
#
|
291
|
-
# rather than a sub-node
|
292
|
-
#
|
293
|
-
# Example:
|
294
|
-
# class Contributor
|
295
|
-
# xml_reader :name, :content
|
296
|
-
# xml_reader :role, :attr
|
297
|
-
# end
|
298
|
-
#
|
299
|
-
# To map:
|
300
|
-
# <contributor role="editor">James Wick</contributor>
|
314
|
+
# You can skip the wrapper argument:
|
315
|
+
# xml_reader :books, :as => [Book]
|
301
316
|
#
|
302
|
-
#
|
317
|
+
# ==== Hash
|
303
318
|
# Somewhere between the simplicity of a :text/:attr mapping, and the complexity of
|
304
319
|
# a full Object/Type mapping, lies the Hash mapping. It serves in the case where you have
|
305
320
|
# a collection of key-value pairs represented in your xml. You create a hash declaration by
|
306
321
|
# passing a hash mapping as the type argument. A few examples:
|
307
322
|
#
|
308
|
-
#
|
309
|
-
# For xml such as this:
|
310
|
-
#
|
311
|
-
# <dictionary>
|
312
|
-
# <definitions>
|
313
|
-
# <definition dt="quaquaversally"
|
314
|
-
# dd="adjective: (of a geological formation) sloping downward from the center in all directions." />
|
315
|
-
# <definition dt="tergiversate"
|
316
|
-
# dd="To use evasions or ambiguities; equivocate." />
|
317
|
-
# </definitions>
|
318
|
-
# </dictionary>
|
319
|
-
#
|
320
|
-
# You can use the :attrs key in you has with a [:key, :value] name array:
|
321
|
-
#
|
322
|
-
# xml_reader :definitions, {:attrs => ['dt', 'dd']}, :in => :definitions
|
323
|
-
#
|
324
|
-
# ==== Hash of :texts
|
323
|
+
# ===== Hash of :texts
|
325
324
|
# For xml such as this:
|
326
325
|
#
|
327
326
|
# <dictionary>
|
@@ -336,10 +335,10 @@ module ROXML # :nodoc:
|
|
336
335
|
# </dictionary>
|
337
336
|
#
|
338
337
|
# You can individually declare your key and value names:
|
339
|
-
# xml_reader :definitions, {:key => 'word',
|
340
|
-
#
|
338
|
+
# xml_reader :definitions, :as => {:key => 'word',
|
339
|
+
# :value => 'meaning'}
|
341
340
|
#
|
342
|
-
#
|
341
|
+
# ===== Hash of :content &c.
|
343
342
|
# For xml such as this:
|
344
343
|
#
|
345
344
|
# <dictionary>
|
@@ -350,10 +349,10 @@ module ROXML # :nodoc:
|
|
350
349
|
# You can individually declare the key and value, but with the attr, you need to provide both the type
|
351
350
|
# and name of that type (i.e. {:attr => :word}), because omitting the type will result in ROXML
|
352
351
|
# defaulting to :text
|
353
|
-
# xml_reader :definitions, {:key => {:attr => 'word'},
|
354
|
-
#
|
352
|
+
# xml_reader :definitions, :as => {:key => {:attr => 'word'},
|
353
|
+
# :value => :content}
|
355
354
|
#
|
356
|
-
#
|
355
|
+
# ===== Hash of :name &c.
|
357
356
|
# For xml such as this:
|
358
357
|
#
|
359
358
|
# <dictionary>
|
@@ -362,112 +361,119 @@ module ROXML # :nodoc:
|
|
362
361
|
# </dictionary>
|
363
362
|
#
|
364
363
|
# You can pick up the node names (e.g. quaquaversally) using the :name keyword:
|
365
|
-
# xml_reader :definitions, {:key => :name,
|
366
|
-
#
|
367
|
-
#
|
368
|
-
# === Other ROXML Class
|
369
|
-
# Declares an accessor that represents another ROXML class as child XML element
|
370
|
-
# (one-to-one or composition) or array of child elements (one-to-many or
|
371
|
-
# aggregation) of this type. Default is one-to-one. Use :array option for one-to-many, or
|
372
|
-
# simply pass the class in an array.
|
364
|
+
# xml_reader :definitions, :as => {:key => :name,
|
365
|
+
# :value => :content}
|
373
366
|
#
|
374
|
-
#
|
375
|
-
#
|
376
|
-
#
|
377
|
-
# <name>Pragmatic Bookshelf</name>
|
378
|
-
# </publisher>
|
379
|
-
# </book>
|
367
|
+
# === :from
|
368
|
+
# The name by which the xml value will be found, either an attribute or tag name in XML.
|
369
|
+
# Default is sym, or the singular form of sym, in the case of arrays and hashes.
|
380
370
|
#
|
381
|
-
#
|
382
|
-
# class Book
|
383
|
-
# xml_reader :publisher, Publisher
|
384
|
-
# end
|
371
|
+
# This value may also include XPath notation.
|
385
372
|
#
|
386
|
-
#
|
387
|
-
#
|
388
|
-
#
|
389
|
-
# <book/>
|
390
|
-
# <book/>
|
391
|
-
# </books>
|
392
|
-
# </library>
|
373
|
+
# ==== :from => :content
|
374
|
+
# When :from is set to :content, this refers to the content of the current node,
|
375
|
+
# rather than a sub-node. It is equivalent to :from => '.'
|
393
376
|
#
|
394
|
-
#
|
395
|
-
# class
|
396
|
-
# xml_reader :
|
377
|
+
# Example:
|
378
|
+
# class Contributor
|
379
|
+
# xml_reader :name, :from => :content
|
380
|
+
# xml_reader :role, :from => :attr
|
397
381
|
# end
|
398
382
|
#
|
399
|
-
#
|
400
|
-
# <
|
401
|
-
# <name>Ruby books</name>
|
402
|
-
# <book/>
|
403
|
-
# <book/>
|
404
|
-
# </library>
|
405
|
-
#
|
406
|
-
# You can skip the wrapper argument:
|
407
|
-
# xml_reader :books, [Book]
|
408
|
-
#
|
409
|
-
# == Blocks
|
410
|
-
# You may also pass a block which manipulates the associated parsed value.
|
383
|
+
# To map:
|
384
|
+
# <contributor role="editor">James Wick</contributor>
|
411
385
|
#
|
412
|
-
#
|
413
|
-
#
|
386
|
+
# ==== :from => :attr
|
387
|
+
# When :from is set to :attr, this refers to the content of an attribute,
|
388
|
+
# rather than a sub-node. It is equivalent to :from => '@attribute_name'
|
414
389
|
#
|
415
|
-
#
|
390
|
+
# Example:
|
391
|
+
# class Book
|
392
|
+
# xml_reader :isbn, :from => "@ISBN"
|
393
|
+
# xml_accessor :title, :from => :attr # :from defaults to '@title'
|
416
394
|
# end
|
417
395
|
#
|
418
|
-
#
|
419
|
-
#
|
396
|
+
# To map:
|
397
|
+
# <book ISBN="0974514055" title="Programming Ruby: the pragmatic programmers' guide" />
|
420
398
|
#
|
421
|
-
#
|
399
|
+
# ==== :from => :text
|
400
|
+
# The default source, if none is specified, this means the accessor
|
401
|
+
# represents a text node from XML. This is documented for completeness
|
402
|
+
# only. You should just leave this option off when you want the default behavior,
|
403
|
+
# as in the examples below.
|
422
404
|
#
|
423
|
-
#
|
405
|
+
# :text is equivalent to :from => accessor_name, and you should specify the
|
406
|
+
# actual node name if it differs, as in the case of :author below.
|
424
407
|
#
|
425
|
-
#
|
408
|
+
# Example:
|
409
|
+
# class Book
|
410
|
+
# xml_reader :author, :from => 'Author
|
411
|
+
# xml_accessor :description, :cdata => true
|
412
|
+
# xml_reader :title
|
413
|
+
# end
|
426
414
|
#
|
427
|
-
#
|
415
|
+
# To map:
|
416
|
+
# <book>
|
417
|
+
# <title>Programming Ruby: the pragmatic programmers' guide</title>
|
418
|
+
# <description><![CDATA[Probably the best Ruby book out there]]></description>
|
419
|
+
# <Author>David Thomas</Author>
|
420
|
+
# </book>
|
428
421
|
#
|
429
|
-
#
|
422
|
+
# Likewise, a number of :text node values can be collected in an array like so:
|
430
423
|
#
|
431
|
-
#
|
424
|
+
# Example:
|
425
|
+
# class Library
|
426
|
+
# xml_reader :books, :as => []
|
427
|
+
# end
|
432
428
|
#
|
433
|
-
#
|
434
|
-
#
|
429
|
+
# To map:
|
430
|
+
# <library>
|
431
|
+
# <book>To kill a mockingbird</book>
|
432
|
+
# <book>House of Leaves</book>
|
433
|
+
# <book>Gödel, Escher, Bach</book>
|
434
|
+
# </library>
|
435
435
|
#
|
436
|
-
#
|
437
|
-
# [:
|
438
|
-
#
|
439
|
-
# [:
|
440
|
-
# [:else] Default value for attribute, if missing
|
436
|
+
# === Other Options
|
437
|
+
# [:in] An optional name of a wrapping tag for this XML accessor.
|
438
|
+
# This can include other xpath values, which will be joined with :from with a '/'
|
439
|
+
# [:else] Default value for attribute, if missing from the xml on .from_xml
|
441
440
|
# [:required] If true, throws RequiredElementMissing when the element isn't present
|
442
441
|
# [:frozen] If true, all results are frozen (using #freeze) at parse-time.
|
442
|
+
# [:cdata] True for values which should be input from or output as cdata elements
|
443
443
|
#
|
444
|
-
def
|
445
|
-
|
446
|
-
|
447
|
-
|
444
|
+
def xml_attr(sym, type_and_or_opts = nil, opts = nil, &block)
|
445
|
+
returning Definition.new(sym, *[type_and_or_opts, opts].compact, &block) do |attr|
|
446
|
+
if roxml_attrs.map(&:accessor).include? attr.accessor
|
447
|
+
raise "Accessor #{attr.accessor} is already defined as XML accessor in class #{self.name}"
|
448
|
+
end
|
449
|
+
@roxml_attrs << attr
|
450
|
+
end
|
448
451
|
end
|
449
452
|
|
450
|
-
def xml(sym, writable = false, type_and_or_opts =
|
451
|
-
|
453
|
+
def xml(sym, writable = false, type_and_or_opts = nil, opts = nil, &block) #:nodoc:
|
454
|
+
send(writable ? :xml_accessor : :xml_reader, sym, type_and_or_opts, opts, &block)
|
452
455
|
end
|
453
|
-
deprecate :xml =>
|
456
|
+
deprecate :xml => "use xml_attr, xml_reader, or xml_accessor instead"
|
454
457
|
|
455
|
-
# Declares a read-only xml reference. See
|
458
|
+
# Declares a read-only xml reference. See xml_attr for details.
|
456
459
|
#
|
457
460
|
# Note that while xml_reader does not create a setter for this attribute,
|
458
461
|
# its value can be modified indirectly via methods. For more complete
|
459
462
|
# protection, consider the :frozen option.
|
460
|
-
def xml_reader(sym, type_and_or_opts =
|
461
|
-
|
463
|
+
def xml_reader(sym, type_and_or_opts = nil, opts = nil, &block)
|
464
|
+
attr = xml_attr sym, type_and_or_opts, opts, &block
|
465
|
+
add_reader(attr)
|
462
466
|
end
|
463
467
|
|
464
|
-
# Declares a writable xml reference. See
|
468
|
+
# Declares a writable xml reference. See xml_attr for details.
|
465
469
|
#
|
466
470
|
# Note that while xml_accessor does create a setter for this attribute,
|
467
471
|
# you can use the :frozen option to prevent its value from being
|
468
472
|
# modified indirectly via methods.
|
469
|
-
def xml_accessor(sym, type_and_or_opts =
|
470
|
-
|
473
|
+
def xml_accessor(sym, type_and_or_opts = nil, opts = nil, &block)
|
474
|
+
attr = xml_attr sym, type_and_or_opts, opts, &block
|
475
|
+
add_reader(attr)
|
476
|
+
attr_writer(attr.variable_name)
|
471
477
|
end
|
472
478
|
|
473
479
|
# This method is deprecated, please use xml_initialize instead
|
@@ -484,23 +490,9 @@ module ROXML # :nodoc:
|
|
484
490
|
deprecate :xml_construct => :xml_initialize
|
485
491
|
|
486
492
|
private
|
487
|
-
def
|
488
|
-
if roxml_attrs.map(&:accessor).include? attr.accessor
|
489
|
-
raise "Accessor #{attr.accessor} is already defined as XML accessor in class #{self.name}"
|
490
|
-
end
|
491
|
-
@roxml_attrs << attr
|
492
|
-
|
493
|
+
def add_reader(attr)
|
493
494
|
define_method(attr.accessor) do
|
494
|
-
|
495
|
-
if result.nil?
|
496
|
-
result = attr.default
|
497
|
-
instance_variable_set("@#{attr.variable_name}", result)
|
498
|
-
end
|
499
|
-
result
|
500
|
-
end
|
501
|
-
|
502
|
-
if writable && !instance_methods.include?("#{attr.accessor}=")
|
503
|
-
attr_writer(attr.accessor)
|
495
|
+
instance_variable_get("@#{attr.variable_name}")
|
504
496
|
end
|
505
497
|
end
|
506
498
|
end
|
@@ -559,7 +551,7 @@ module ROXML # :nodoc:
|
|
559
551
|
# Creates a new Ruby object from XML using mapping information
|
560
552
|
# annotated in the class.
|
561
553
|
#
|
562
|
-
# The input data is either an XML::Node or
|
554
|
+
# The input data is either an XML::Node, String, Pathname, or File representing
|
563
555
|
# the XML document.
|
564
556
|
#
|
565
557
|
# Example
|
@@ -568,7 +560,9 @@ module ROXML # :nodoc:
|
|
568
560
|
# book = Book.from_xml("<book><name>Beyond Java</name></book>")
|
569
561
|
#
|
570
562
|
# _initialization_args_ passed into from_xml will be passed into
|
571
|
-
# the object
|
563
|
+
# the object's .new, prior to populating the xml_attrs.
|
564
|
+
#
|
565
|
+
# After the instatiation and xml population
|
572
566
|
#
|
573
567
|
# See also: xml_initialize
|
574
568
|
#
|
@@ -581,13 +575,19 @@ module ROXML # :nodoc:
|
|
581
575
|
end.map {|attr| attr.to_ref(self).value_in(xml) }
|
582
576
|
new(*args)
|
583
577
|
else
|
584
|
-
returning
|
578
|
+
returning new(*initialization_args) do |inst|
|
585
579
|
roxml_attrs.each do |attr|
|
586
|
-
|
580
|
+
value = attr.to_ref(inst).value_in(xml)
|
581
|
+
setter = :"#{attr.variable_name}="
|
582
|
+
inst.respond_to?(setter) \
|
583
|
+
? inst.send(setter, value) \
|
584
|
+
: inst.instance_variable_set("@#{attr.variable_name}", value)
|
587
585
|
end
|
588
|
-
inst.
|
586
|
+
inst.try(:after_parse)
|
589
587
|
end
|
590
588
|
end
|
589
|
+
rescue ArgumentError => e
|
590
|
+
raise e, e.message + " for class #{self}"
|
591
591
|
end
|
592
592
|
|
593
593
|
# Deprecated in favor of #from_xml
|