roxml 2.5.3 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/.gitignore +7 -0
  2. data/.gitmodules +3 -0
  3. data/History.txt +38 -1
  4. data/README.rdoc +8 -5
  5. data/Rakefile +35 -36
  6. data/TODO +12 -35
  7. data/VERSION +1 -0
  8. data/examples/amazon.rb +8 -6
  9. data/examples/posts.rb +1 -1
  10. data/examples/{active_record.rb → rails.rb} +2 -2
  11. data/examples/twitter.rb +1 -1
  12. data/lib/roxml.rb +86 -151
  13. data/lib/roxml/definition.rb +64 -152
  14. data/lib/roxml/hash_definition.rb +5 -40
  15. data/lib/roxml/xml.rb +12 -9
  16. data/lib/roxml/xml/parsers/libxml.rb +22 -17
  17. data/lib/roxml/xml/parsers/nokogiri.rb +77 -0
  18. data/lib/roxml/xml/references.rb +66 -57
  19. data/roxml.gemspec +170 -19
  20. data/spec/definition_spec.rb +121 -198
  21. data/spec/examples/active_record_spec.rb +2 -2
  22. data/spec/examples/amazon_spec.rb +3 -2
  23. data/spec/examples/current_weather_spec.rb +2 -2
  24. data/spec/examples/dashed_elements_spec.rb +2 -2
  25. data/spec/examples/library_spec.rb +11 -6
  26. data/spec/examples/post_spec.rb +3 -3
  27. data/spec/examples/twitter_spec.rb +2 -2
  28. data/spec/roxml_spec.rb +15 -15
  29. data/spec/shared_specs.rb +1 -1
  30. data/spec/spec_helper.rb +8 -27
  31. data/spec/support/libxml.rb +3 -0
  32. data/spec/support/nokogiri.rb +3 -0
  33. data/spec/xml/attributes_spec.rb +36 -0
  34. data/spec/xml/namespace_spec.rb +240 -0
  35. data/spec/xml/namespaces_spec.rb +32 -0
  36. data/spec/xml/parser_spec.rb +9 -30
  37. data/tasks/rdoc.rake +13 -0
  38. data/tasks/rspec.rake +21 -17
  39. data/tasks/test.rake +13 -20
  40. data/test/mocks/dictionaries.rb +8 -7
  41. data/test/mocks/mocks.rb +20 -20
  42. data/test/support/fixtures.rb +11 -0
  43. data/test/test_helper.rb +3 -14
  44. data/test/unit/definition_test.rb +21 -95
  45. data/test/unit/deprecations_test.rb +1 -74
  46. data/test/unit/to_xml_test.rb +3 -3
  47. data/test/unit/xml_attribute_test.rb +1 -1
  48. data/test/unit/xml_block_test.rb +3 -3
  49. data/test/unit/xml_bool_test.rb +4 -4
  50. data/test/unit/xml_convention_test.rb +3 -3
  51. data/test/unit/xml_hash_test.rb +5 -14
  52. data/test/unit/xml_initialize_test.rb +2 -6
  53. data/test/unit/xml_name_test.rb +5 -24
  54. data/test/unit/xml_namespace_test.rb +1 -46
  55. data/test/unit/xml_object_test.rb +6 -6
  56. data/test/unit/xml_required_test.rb +3 -2
  57. data/test/unit/xml_text_test.rb +2 -2
  58. data/website/index.html +1 -1
  59. metadata +68 -51
  60. data/Manifest.txt +0 -106
  61. data/lib/roxml/extensions.rb +0 -6
  62. data/lib/roxml/extensions/array.rb +0 -13
  63. data/lib/roxml/extensions/array/conversions.rb +0 -35
  64. data/lib/roxml/extensions/deprecation.rb +0 -33
  65. data/lib/roxml/extensions/string.rb +0 -21
  66. data/lib/roxml/extensions/string/conversions.rb +0 -43
  67. data/lib/roxml/extensions/string/iterators.rb +0 -12
  68. data/lib/roxml/xml/parsers/rexml.rb +0 -84
  69. data/spec/string_spec.rb +0 -15
  70. data/test/bugs/rexml_bugs.rb +0 -15
  71. data/test/release/dependencies_test.rb +0 -32
  72. data/test/unit/xml_construct_test.rb +0 -77
  73. data/vendor/override_rake_task/README +0 -30
  74. data/vendor/override_rake_task/init.rb +0 -1
  75. data/vendor/override_rake_task/install.rb +0 -46
  76. data/vendor/override_rake_task/lib/override_rake_task.rb +0 -16
@@ -0,0 +1,7 @@
1
+ spec/**/*.xml
2
+ rdoc
3
+ build
4
+ doc
5
+ Rake.config
6
+ pkg
7
+ .project
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/override_rake_task"]
2
+ path = vendor/override_rake_task
3
+ url = git://github.com/Empact/override_rake_task.git
@@ -1,3 +1,40 @@
1
+ == 3.1 (October 16, 2009)
2
+
3
+ * major enhancements
4
+
5
+ * Add support for registering XML namespace prefixes via the xml_namespaces method
6
+
7
+ * bug fix
8
+
9
+ * References to arrays of attributes were only returning the first. No more.
10
+
11
+ == 3.0 (October 14, 2009)
12
+
13
+ * major enhancements
14
+
15
+ * Add Nokogiri support
16
+ * Remove previously deprecated functionality
17
+ * Remove REXML support
18
+ * Error on any unrecognized options
19
+ * Normalize hash declaration syntax:
20
+ * for :key => '@string', string is taken to be the :from argument
21
+ * for :key => {:from => '@string', :as => Type}, the arguments are just the same as a regular declaration
22
+
23
+ * minor enhancements
24
+
25
+ * Include 't' and 'f' in the list of possible boolean values, since rails uses them
26
+ * Remove :attrs hash syntax. Not particularly helpful & somewhat obfuscatory. Use :key, :value instead.
27
+ * Default attrs ending in '_at' to DateTime. This can be overriden via :as
28
+ * Default attrs ending in '_on' to Date. This can be overriden via :as
29
+ * Don't require rubygems within the library
30
+ * Don't mess with the load path
31
+
32
+ == 2.5.4 (October 4, 2009)
33
+
34
+ * bug fix
35
+
36
+ * Rely on REXML's #add_child and LibXML's <<, rather than #child_add which had been removed from REXML and deprecated from LibXML
37
+
1
38
  == 2.5.3 (March 22, 2009)
2
39
 
3
40
  * minor enhancement
@@ -27,7 +64,7 @@
27
64
 
28
65
  * major enhancements
29
66
 
30
- * support for mapping ActiveRecord classes. See examples/active_record.rb.
67
+ * support for mapping ActiveRecord classes. See examples/rails.rb.
31
68
  * .from_xml will now use the setter for the declared variable, if one is available,
32
69
  rather than directly setting the instance variable
33
70
  * All declaration type arguments are now supported via the :as parameter, e.g. :as => [MyType]. Other uses are deprecated.
@@ -6,10 +6,9 @@ For more information visit:
6
6
  http://empact.github.com/roxml/
7
7
  http://rubyforge.org/projects/roxml/
8
8
 
9
- Progress on this project is (more or less) tracked at:
10
-
11
- http://www.pivotaltracker.com/project/4109
9
+ Please submit bugs here:
12
10
 
11
+ http://github.com/Empact/roxml/issues
13
12
 
14
13
  =Quick Start Guide
15
14
 
@@ -94,6 +93,10 @@ Note: In the above example, _xml_name_ annotation tells ROXML to set the element
94
93
  name to "book" for mapping to XML. The default is XML element name is the class name in lowercase; "bookwithpublisher"
95
94
  in this case.
96
95
 
96
+ === Namespace Support
97
+
98
+ Namespaces are supported via the xml_namespace declaration and the :from and :namespace attr options. See spec/xml/namespace_spec.rb for usage.
99
+
97
100
  == Manipulation
98
101
 
99
102
  Extending the above examples, say you want to parse a book's page count and have it available as an Integer.
@@ -147,11 +150,11 @@ which may be used via _new_ construction as well as _from_xml_ construction.
147
150
 
148
151
  == Selecting a parser
149
152
 
150
- By default, ROXML will use LibXML if it is available, or otherwise REXML. If you'd like to
153
+ By default, ROXML will use Nokogiri if it is available, followed by LibXML. If you'd like to
151
154
  explicitly require one or the other, you may do the following:
152
155
 
153
156
  module ROXML
154
- XML_PARSER = 'libxml' # or 'rexml'
157
+ XML_PARSER = 'nokogiri' # or 'libxml'
155
158
  end
156
159
  require 'roxml'
157
160
 
data/Rakefile CHANGED
@@ -1,51 +1,55 @@
1
- module Enumerable
2
- undef_method(:one?)
3
- end if [].respond_to?(:one?)
1
+ require 'rake'
4
2
 
5
3
  ENV['RUBY_FLAGS'] = '-W1'
6
4
 
7
- %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
8
- require File.expand_path(File.dirname(__FILE__) + '/lib/roxml')
9
-
10
5
  # Generate all the Rake tasks
11
6
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
12
- $hoe = Hoe.new('roxml', ROXML::VERSION) do |p|
13
- p.author = ["Ben Woosley", "Zak Mandhro", "Anders Engstrom", "Russ Olsen"]
14
- p.email = "ben.woosley@gmail.com"
15
- p.url = "http://roxml.rubyforge.org"
16
- p.changes = File.read("History.txt").split(/^==/)[1].strip
17
- p.rubyforge_name = p.name
18
- p.extra_deps = [
19
- ['activesupport','>= 2.1.0'],
20
- ['libxml-ruby', '>= 1.0.0']
21
- ]
22
- p.extra_dev_deps = [
23
- ['newgem', ">= #{::Newgem::VERSION}"],
24
- ['sqlite3-ruby', '>= 1.2.4' ],
25
- ['activerecord', '>= 2.2.2' ]
26
- ]
27
-
28
- p.summary = "Ruby Object to XML mapping library"
29
- p.description = <<EOF
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = 'roxml'
10
+ gem.rubyforge_project = "roxml"
11
+ gem.summary = "Ruby Object to XML mapping library"
12
+ gem.description = <<EOF
30
13
  ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML.
31
14
  Using simple annotations, it enables Ruby classes to be mapped to XML. ROXML takes care
32
15
  of the marshalling and unmarshalling of mapped attributes so that developers can focus on
33
16
  building first-class Ruby classes. As a result, ROXML simplifies the development of
34
17
  RESTful applications, Web Services, and XML-RPC.
35
18
  EOF
19
+ gem.email = "ben.woosley@gmail.com"
20
+ gem.homepage = "http://roxml.rubyforge.org"
21
+ gem.authors = ["Ben Woosley", "Zak Mandhro", "Anders Engstrom", "Russ Olsen"]
36
22
 
37
- p.test_globs = 'test/unit/*_test.rb'
38
- p.clean_globs |= %w[**/.DS_Store tmp *.log]
39
- path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
40
- p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
41
- p.rsync_args = '-av --delete --ignore-errors'
42
- end
23
+ gem.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc"]
43
24
 
44
- require 'newgem/tasks' # load /tasks/*.rake
25
+ gem.add_dependency 'activesupport', '>= 2.1.0'
26
+ gem.add_dependency 'nokogiri', '>= 1.3.3'
27
+
28
+ gem.add_development_dependency "rspec"
29
+ gem.add_development_dependency "sqlite3-ruby", '>= 1.2.4'
30
+ gem.add_development_dependency "activerecord", '>= 2.2.2'
31
+ end
32
+ Jeweler::GemcutterTasks.new
33
+ Jeweler::RubyforgeTasks.new do |rubyforge|
34
+ rubyforge.doc_task = "rdoc"
35
+ end
45
36
 
46
37
  Dir['tasks/**/*.rake'].each { |t| load t }
47
38
 
48
39
  task :default => [:test, :spec]
40
+ task :all => [:libxml, :nokogiri]
41
+ task :libxml => ['test:libxml', 'spec:libxml']
42
+ task :nokogiri => ['test:nokogiri', 'spec:nokogiri']
43
+
44
+ # $hoe = Hoe.new('roxml', ROXML::VERSION) do |p|
45
+ # p.changes = File.read("History.txt").split(/^==/)[1].strip
46
+ #
47
+ # p.test_globs = 'test/unit/*_test.rb'
48
+ # p.clean_globs |= %w[**/.DS_Store tmp *.log]
49
+ # path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
50
+ # p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
51
+ # p.rsync_args = '-av --delete --ignore-errors'
52
+ # end
49
53
 
50
54
  ## Provide the username used to upload website etc.
51
55
  #RubyForgeConfig = {
@@ -73,11 +77,6 @@ task :default => [:test, :spec]
73
77
  # pub.upload()
74
78
  #end
75
79
  #
76
- #desc "Install the gem"
77
- #task :install => [:package] do
78
- # sh %{sudo gem install pkg/#{spec.name}-#{spec.version}}
79
- #end
80
-
81
80
  #desc "Create the ZIP package"
82
81
  #Rake::PackageTask.new(spec.name, spec.version) do |p|
83
82
  # p.need_zip = true
data/TODO CHANGED
@@ -1,62 +1,39 @@
1
1
  Planned:
2
2
 
3
- v 3.0
4
- * remove deprecated functionality
5
-
6
- * Automatically use Date or DateTime for accessors ending in '_on' and '_at', respectively
7
-
8
- * Clarify API via seperation of concerns. :as for Type, :from and :in for location,
9
- All other options as named options, e.g. :cdata => true rather than :as => :cdata.
10
- A few not so great examples...:
11
-
12
- xml_reader :some_objce, MyObject
13
- xml_reader :size, :attr, :as => Integer
14
- xml_reader :count, :attr, :as => Integer
15
-
16
- become:
17
-
18
- xml_reader :some_object, :as => MyObject
19
- xml_reader :count, :size, :as => Integer, :from => :attr
20
-
21
- This will significantly simplify the internals and will also cleanly split
22
- element type, location, name and options, for a more predictable API.
23
-
24
- It also enables multiple declarations on a single call, ala attr_*
25
-
26
- xml_reader :count, :size, :number, :as => Integer, :from => :attr
3
+ v 3.1
27
4
 
28
- * Consider class_inheritable_attribute rather than superclass.try stuff.
5
+ * Add xml_namespaces to allow declaration of distinct prefx/url namespace pairs
29
6
 
30
- * Do some benchmarking
7
+ * Consider class_inheritable_attribute rather than superclass.try stuff.
31
8
 
32
- v 3.1
9
+ * Do some benchmarking
33
10
 
34
- * Back with http://xml-object.rubyforge.org/doc/ to minimize need for specifications?
11
+ * Back with http://xml-object.rubyforge.org/doc/ to minimize need for specifications?
35
12
 
36
- * Commandeer #parse to use opposite #from_xml, but in an unrooted, collection-friendly fashion,
13
+ * Commandeer #parse to use opposite #from_xml, but in an unrooted, collection-friendly fashion,
37
14
  ala HappyMapper's parse
38
15
 
39
16
  v 3.x
40
17
 
41
- * :self => true for sending method_missing to this attribute?
18
+ * :self => true for sending method_missing to this attribute?
42
19
 
43
- * :attributes extensions ala HappyMapper?
20
+ * :attributes extensions ala HappyMapper?
44
21
 
45
- * Add xml_attrs helper to share :in declarations between several attributes. E.g.:
22
+ * Add xml_attrs helper to share :in declarations between several attributes. E.g.:
46
23
 
47
24
  xml_reader :count, :in => 'Attributes', :as => Integer
48
25
  xml_reader :something_else, :in => 'Attributes', :as => Date
49
26
 
50
- becomes:
27
+ becomes:
51
28
 
52
29
  xml_attrs :in => 'Attributes' do |xml|
53
30
  xml.reader :count, :as => Integer
54
31
  xml.reader :something_else, :as => Date
55
32
  end
56
33
 
57
- * Ensure (perhaps optionally) that references are unambiguous. That is error/warn
34
+ * Ensure (perhaps optionally) that references are unambiguous. That is error/warn
58
35
  a singular specification has multiple possible node references
59
36
 
60
- * Use lazy evaluation to minimize parsing time for large files
37
+ * Use lazy evaluation to minimize parsing time for large files
61
38
 
62
39
 
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 3.1.0
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- require File.expand_path(File.dirname(__FILE__) + '/../spec/spec_helper')
2
+ require 'spec/spec_helper'
3
3
 
4
4
  # The document `pita.xml` contains both a default namespace and the 'georss'
5
5
  # namespace (for the 'point' xml_reader).
@@ -12,10 +12,10 @@ module PITA
12
12
  class Item < Base
13
13
  xml_reader :asin, :from => 'ASIN'
14
14
  xml_reader :detail_page_url, :from => 'DetailPageURL'
15
- xml_reader :manufacturer, :in => './'
15
+ xml_reader :manufacturer, :in => 'ItemAttributes'
16
16
  # this is the only xml_reader that exists in a different namespace, so it
17
17
  # must be explicitly specified
18
- xml_reader :point, :from => 'georss:point'
18
+ xml_reader :point, :namespace => 'georss'
19
19
  end
20
20
 
21
21
  class ItemSearchResponse < Base
@@ -26,8 +26,10 @@ module PITA
26
26
  end
27
27
 
28
28
  unless defined?(Spec)
29
- item = PITA::ItemSearchResponse.from_xml(xml_for('amazon'))
30
- item.items.each do |i|
31
- puts i.asin, i.detail_page_url, i.manufacturer, ''
29
+ response = PITA::ItemSearchResponse.from_xml(xml_for('amazon'))
30
+ p response.total_results
31
+ p response.total_pages
32
+ response.items.each do |i|
33
+ puts i.asin, i.detail_page_url, i.manufacturer, i.point, ''
32
34
  end
33
35
  end
@@ -8,7 +8,7 @@ class Post
8
8
  xml_reader :hash, :from => :attr
9
9
  xml_reader :description, :from => :attr
10
10
  xml_reader :tag, :from => :attr
11
- xml_reader :time, :from => :attr, :as => DateTime
11
+ xml_reader :created_at, :from => '@time'
12
12
  xml_reader :others, :from => :attr, :as => Integer
13
13
  xml_reader :extended, :from => :attr
14
14
  end
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
- require File.expand_path(File.dirname(__FILE__) + '/../spec/spec_helper')
2
+ require 'spec/spec_helper'
3
3
  require 'sqlite3'
4
4
  require 'activerecord'
5
5
 
6
- DB_PATH = File.join(File.dirname(__FILE__), 'active_record.sqlite3')
6
+ DB_PATH = 'spec/examples/rails.sqlite3'
7
7
  ActiveRecord::Base.establish_connection(
8
8
  :adapter => 'sqlite3',
9
9
  :database => DB_PATH
@@ -21,7 +21,7 @@ class Status
21
21
 
22
22
  xml_reader :id, :as => Integer
23
23
  xml_reader :text
24
- xml_reader :created_at, :as => Time
24
+ xml_reader :created_at # This defaults to :as => DateTime, due to the '_at'
25
25
  xml_reader :source
26
26
  xml_reader :truncated?
27
27
  xml_reader :in_reply_to_status_id, :as => Integer
@@ -1,91 +1,30 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__)) unless
2
- $LOAD_PATH.include?(File.dirname(__FILE__)) || $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
3
-
4
1
  require 'uri'
2
+ require 'active_support'
5
3
 
6
- %w(extensions definition xml).each do |file|
7
- require File.join('roxml', file)
8
- end
4
+ require 'lib/roxml/definition'
5
+ require 'lib/roxml/xml'
9
6
 
10
7
  module ROXML # :nodoc:
11
- VERSION = '2.5.3'
8
+ VERSION = '3.1.0'
12
9
 
13
10
  def self.included(base) # :nodoc:
14
- base.extend ClassMethods::Accessors,
15
- ClassMethods::Declarations,
16
- ClassMethods::Operations
17
11
  base.class_eval do
18
- include InstanceMethods::Accessors,
19
- InstanceMethods::Construction,
20
- InstanceMethods::Conversions
12
+ extend ClassMethods::Accessors,
13
+ ClassMethods::Declarations,
14
+ ClassMethods::Operations
15
+ include InstanceMethods
21
16
  end
22
17
  end
23
18
 
24
19
  module InstanceMethods # :nodoc:
25
- # Instance method equivalents of the Class method accessors
26
- module Accessors # :nodoc:all
27
- # Provides access to ROXML::ClassMethods::Accessors::tag_name directly from an instance of a ROXML class
28
- def tag_name
29
- self.class.tag_name
30
- end
31
- deprecate :tag_name => 'use class.tag_name instead'
32
-
33
- # Provides access to ROXML::ClassMethods::Accessors::tag_refs directly from an instance of a ROXML class
34
- def tag_refs
35
- self.class.tag_refs_without_deprecation
36
- end
37
- deprecate :tag_refs => :roxml_attrs
38
- end
39
-
40
- module Construction
41
- # xml_initialize is called at the end of the #from_xml operation on objects
42
- # where xml_construct is not in place. Override xml_initialize in order to establish
43
- # post-import behavior. For example, you can use xml_initialize to map xml attribute
44
- # values into the object standard initialize function, thus enabling a ROXML object
45
- # to freely be either xml-backed or instantiated directly via #new.
46
- # An example of this follows:
47
- #
48
- # class Measurement
49
- # include ROXML
50
- #
51
- # xml_reader :units, :from => :attr
52
- # xml_reader :value, :from => :content
53
- #
54
- # def xml_initialize
55
- # # the object is instantiated, and all xml attributes are imported
56
- # # and available, i.e., value and units below are the same value and units
57
- # # found in the xml via the xml_reader declarations above.
58
- # initialize(value, units)
59
- # end
60
- #
61
- # def initialize(value, units = 'pixels')
62
- # @value = Float(value)
63
- # @units = units.to_s
64
- # if @units.starts_with? 'hundredths-'
65
- # @value /= 100
66
- # @units = @units.split('hundredths-')[1]
67
- # end
68
- # end
69
- # end
70
- #
71
- # #xml_initialize may be written to take arguments, in which case extra arguments
72
- # from from_xml will be passed into the function.
73
- #
74
- def xml_initialize # :nodoc:
75
- end
76
- deprecate :xml_initialize => :after_parse
77
- end
78
-
79
- module Conversions
80
- # Returns a LibXML::XML::Node or a REXML::Element representing this object
81
- def to_xml(name = nil)
82
- returning XML::Node.new((name || self.class.tag_name).to_s) do |root|
83
- self.class.roxml_attrs.each do |attr|
84
- ref = attr.to_ref(self)
85
- v = ref.to_xml
86
- unless v.nil?
87
- ref.update_xml(root, v)
88
- end
20
+ # Returns an XML object representing this object
21
+ def to_xml(name = self.class.tag_name)
22
+ XML::Node.create(name.to_s).tap do |root|
23
+ self.class.roxml_attrs.each do |attr|
24
+ ref = attr.to_ref(self)
25
+ value = ref.to_xml(self)
26
+ unless value.nil?
27
+ ref.update_xml(root, value)
89
28
  end
90
29
  end
91
30
  end
@@ -123,7 +62,7 @@ module ROXML # :nodoc:
123
62
  #
124
63
  # xml_reader :default_namespace
125
64
  # xml_reader :different_namespace, :from => 'different:namespace'
126
- # xml_reader :no_namespace, :from => ':no_namespace'
65
+ # xml_reader :no_namespace, :from => 'no_namespace', :namespace => false
127
66
  # end
128
67
  #
129
68
  # <aws:book xmlns:aws="http://www.aws.com/aws" xmlns:different="http://www.aws.com/different">
@@ -135,6 +74,44 @@ module ROXML # :nodoc:
135
74
  def xml_namespace(namespace)
136
75
  @roxml_namespace = namespace.to_s
137
76
  end
77
+
78
+ # Sets up a mapping of namespace prefixes to hrefs, to be used by this class.
79
+ # These namespace prefixes are independent of what appears in the xml, only
80
+ # the namespace hrefs themselves need to match
81
+ #
82
+ # Example:
83
+ # class Tires
84
+ # include ROXML
85
+ #
86
+ # xml_namespaces \
87
+ # :bobsbike => 'http://bobsbikes.example.com',
88
+ # :alicesauto => 'http://alicesautosupply.example.com/'
89
+ #
90
+ # xml_reader :bike_tires, :as => [], :from => '@name', :in => 'bobsbike:tire'
91
+ # xml_reader :car_tires, :as => [], :from => '@name', :in => 'alicesauto:tire'
92
+ # end
93
+ #
94
+ # >> xml = %{
95
+ # <?xml version="1.0"?>
96
+ # <inventory xmlns="http://alicesautosupply.example.com/" xmlns:bike="http://bobsbikes.example.com">
97
+ # <tire name="super slick racing tire" />
98
+ # <tire name="all weather tire" />
99
+ # <bike:tire name="skinny street" />
100
+ # </inventory>
101
+ # }
102
+ # >> Tires.from_xml(xml).bike_tires
103
+ # => ['skinny street']
104
+ #
105
+ def xml_namespaces(namespaces)
106
+ @roxml_namespaces = namespaces.inject({}) do |all, (prefix, href)|
107
+ all[prefix.to_s] = href.to_s
108
+ all
109
+ end
110
+ end
111
+
112
+ def roxml_namespaces # :nodoc:
113
+ @roxml_namespaces || {}
114
+ end
138
115
 
139
116
  # Most xml documents have a consistent naming convention, for example, the node and
140
117
  # and attribute names might appear in CamelCase. xml_convention enables you to adapt
@@ -275,7 +252,7 @@ module ROXML # :nodoc:
275
252
  #
276
253
  # xml_reader :counts, :as => [Integer]
277
254
  #
278
- # Even an array of :text nodes can be specified with :as => []
255
+ # Even an array of text nodes can be specified with :as => []
279
256
  #
280
257
  # xml_reader :quotes, :as => []
281
258
  #
@@ -326,7 +303,7 @@ module ROXML # :nodoc:
326
303
  # a collection of key-value pairs represented in your xml. You create a hash declaration by
327
304
  # passing a hash mapping as the type argument. A few examples:
328
305
  #
329
- # ===== Hash of :texts
306
+ # ===== Hash of element contents
330
307
  # For xml such as this:
331
308
  #
332
309
  # <dictionary>
@@ -409,11 +386,11 @@ module ROXML # :nodoc:
409
386
  # as in the examples below.
410
387
  #
411
388
  # :text is equivalent to :from => accessor_name, and you should specify the
412
- # actual node name if it differs, as in the case of :author below.
389
+ # actual node name (and, optionally, a namespace) if it differs, as in the case of :author below.
413
390
  #
414
391
  # Example:
415
392
  # class Book
416
- # xml_reader :author, :from => 'Author
393
+ # xml_reader :author, :from => 'Author'
417
394
  # xml_accessor :description, :cdata => true
418
395
  # xml_reader :title
419
396
  # end
@@ -445,31 +422,31 @@ module ROXML # :nodoc:
445
422
  # [:else] Default value for attribute, if missing from the xml on .from_xml
446
423
  # [:required] If true, throws RequiredElementMissing when the element isn't present
447
424
  # [:frozen] If true, all results are frozen (using #freeze) at parse-time.
448
- # [:cdata] True for values which should be input from or output as cdata elements
425
+ # [:cdata] true for values which should be input from or output as cdata elements
449
426
  # [:to_xml] this proc is applied to the attributes value outputting the instance via #to_xml
450
- #
451
- def xml_attr(sym, type_and_or_opts = nil, opts = nil, &block)
452
- returning Definition.new(sym, *[type_and_or_opts, opts].compact, &block) do |attr|
453
- if roxml_attrs.map(&:accessor).include? attr.accessor
454
- raise "Accessor #{attr.accessor} is already defined as XML accessor in class #{self.name}"
427
+ # [:namespace] (false) disables or (string) overrides the default namespace declared with xml_namespace
428
+ #
429
+ def xml_attr(*syms, &block)
430
+ opts = syms.extract_options!
431
+ syms.map do |sym|
432
+ Definition.new(sym, opts, &block).tap do |attr|
433
+ if roxml_attrs.map(&:accessor).include? attr.accessor
434
+ raise "Accessor #{attr.accessor} is already defined as XML accessor in class #{self.name}"
435
+ end
436
+ @roxml_attrs << attr
455
437
  end
456
- @roxml_attrs << attr
457
438
  end
458
439
  end
459
440
 
460
- def xml(sym, writable = false, type_and_or_opts = nil, opts = nil, &block) #:nodoc:
461
- send(writable ? :xml_accessor : :xml_reader, sym, type_and_or_opts, opts, &block)
462
- end
463
- deprecate :xml => "use xml_attr, xml_reader, or xml_accessor instead"
464
-
465
441
  # Declares a read-only xml reference. See xml_attr for details.
466
442
  #
467
443
  # Note that while xml_reader does not create a setter for this attribute,
468
444
  # its value can be modified indirectly via methods. For more complete
469
445
  # protection, consider the :frozen option.
470
- def xml_reader(sym, type_and_or_opts = nil, opts = nil, &block)
471
- attr = xml_attr sym, type_and_or_opts, opts, &block
472
- add_reader(attr)
446
+ def xml_reader(*syms, &block)
447
+ xml_attr(*syms, &block).each do |attr|
448
+ add_reader(attr)
449
+ end
473
450
  end
474
451
 
475
452
  # Declares a writable xml reference. See xml_attr for details.
@@ -477,45 +454,22 @@ module ROXML # :nodoc:
477
454
  # Note that while xml_accessor does create a setter for this attribute,
478
455
  # you can use the :frozen option to prevent its value from being
479
456
  # modified indirectly via methods.
480
- def xml_accessor(sym, type_and_or_opts = nil, opts = nil, &block)
481
- attr = xml_attr sym, type_and_or_opts, opts, &block
482
- add_reader(attr)
483
- attr_writer(attr.variable_name)
484
- end
485
-
486
- # This method is deprecated, please use xml_initialize instead
487
- def xml_construct(*args) # :nodoc:
488
- present_tags = tag_refs_without_deprecation.map(&:accessor)
489
- missing_tags = args - present_tags
490
- unless missing_tags.empty?
491
- raise ArgumentError, "All construction tags must be declared first using xml, " +
492
- "xml_reader, or xml_accessor. #{missing_tags.join(', ')} is missing. " +
493
- "#{present_tags.join(', ')} are declared."
457
+ def xml_accessor(*syms, &block)
458
+ xml_attr(*syms, &block).each do |attr|
459
+ add_reader(attr)
460
+ attr_writer(attr.attr_name)
494
461
  end
495
- @xml_construction_args = args
496
462
  end
497
- deprecate :xml_construct => :xml_initialize
498
463
 
499
464
  private
500
465
  def add_reader(attr)
501
466
  define_method(attr.accessor) do
502
- instance_variable_get("@#{attr.variable_name}")
467
+ instance_variable_get(attr.instance_variable_name)
503
468
  end
504
469
  end
505
470
  end
506
471
 
507
472
  module Accessors
508
- def xml_construction_args # :nodoc:
509
- @xml_construction_args ||= []
510
- end
511
- deprecate :xml_construction_args
512
-
513
- # A helper which enables us to detect when the xml_name has been explicitly set
514
- def xml_name? #:nodoc:
515
- @roxml_tag_name
516
- end
517
- deprecate :xml_name?
518
-
519
473
  # Returns the tag name (also known as xml_name) of the class.
520
474
  # If no tag name is set with xml_name method, returns default class name
521
475
  # in lowercase.
@@ -550,11 +504,6 @@ module ROXML # :nodoc:
550
504
  @roxml_attrs ||= []
551
505
  (@roxml_attrs + (superclass.respond_to?(:roxml_attrs) ? superclass.roxml_attrs : [])).freeze
552
506
  end
553
-
554
- def tag_refs # :nodoc:
555
- roxml_attrs.map {|a| a.to_ref(nil) }
556
- end
557
- deprecate :tag_refs => :roxml_attrs
558
507
  end
559
508
 
560
509
  module Operations
@@ -580,32 +529,18 @@ module ROXML # :nodoc:
580
529
  def from_xml(data, *initialization_args)
581
530
  xml = XML::Node.from(data)
582
531
 
583
- unless xml_construction_args_without_deprecation.empty?
584
- args = xml_construction_args_without_deprecation.map do |arg|
585
- roxml_attrs.find {|attr| attr.accessor == arg }
586
- end.map {|attr| attr.to_ref(self).value_in(xml) }
587
- new(*args)
588
- else
589
- returning new(*initialization_args) do |inst|
590
- roxml_attrs.each do |attr|
591
- value = attr.to_ref(inst).value_in(xml)
592
- setter = :"#{attr.variable_name}="
593
- inst.respond_to?(setter) \
594
- ? inst.send(setter, value) \
595
- : inst.instance_variable_set("@#{attr.variable_name}", value)
596
- end
597
- inst.send(:after_parse) if inst.respond_to?(:after_parse, true)
532
+ new(*initialization_args).tap do |inst|
533
+ roxml_attrs.each do |attr|
534
+ value = attr.to_ref(inst).value_in(xml)
535
+ inst.respond_to?(attr.setter) \
536
+ ? inst.send(attr.setter, value) \
537
+ : inst.instance_variable_set(attr.instance_variable_name, value)
598
538
  end
539
+ inst.send(:after_parse) if inst.respond_to?(:after_parse, true)
599
540
  end
600
541
  rescue ArgumentError => e
601
542
  raise e, e.message + " for class #{self}"
602
543
  end
603
-
604
- # Deprecated in favor of #from_xml
605
- def parse(data) # :nodoc:
606
- from_xml(data)
607
- end
608
- deprecate :parse => :from_xml
609
544
  end
610
545
  end
611
546
  end