roxml 2.5.3 → 3.1.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/.gitignore +7 -0
- data/.gitmodules +3 -0
- data/History.txt +38 -1
- data/README.rdoc +8 -5
- data/Rakefile +35 -36
- data/TODO +12 -35
- data/VERSION +1 -0
- data/examples/amazon.rb +8 -6
- data/examples/posts.rb +1 -1
- data/examples/{active_record.rb → rails.rb} +2 -2
- data/examples/twitter.rb +1 -1
- data/lib/roxml.rb +86 -151
- data/lib/roxml/definition.rb +64 -152
- data/lib/roxml/hash_definition.rb +5 -40
- data/lib/roxml/xml.rb +12 -9
- data/lib/roxml/xml/parsers/libxml.rb +22 -17
- data/lib/roxml/xml/parsers/nokogiri.rb +77 -0
- data/lib/roxml/xml/references.rb +66 -57
- data/roxml.gemspec +170 -19
- data/spec/definition_spec.rb +121 -198
- data/spec/examples/active_record_spec.rb +2 -2
- data/spec/examples/amazon_spec.rb +3 -2
- data/spec/examples/current_weather_spec.rb +2 -2
- data/spec/examples/dashed_elements_spec.rb +2 -2
- data/spec/examples/library_spec.rb +11 -6
- data/spec/examples/post_spec.rb +3 -3
- data/spec/examples/twitter_spec.rb +2 -2
- data/spec/roxml_spec.rb +15 -15
- data/spec/shared_specs.rb +1 -1
- data/spec/spec_helper.rb +8 -27
- data/spec/support/libxml.rb +3 -0
- data/spec/support/nokogiri.rb +3 -0
- data/spec/xml/attributes_spec.rb +36 -0
- data/spec/xml/namespace_spec.rb +240 -0
- data/spec/xml/namespaces_spec.rb +32 -0
- data/spec/xml/parser_spec.rb +9 -30
- data/tasks/rdoc.rake +13 -0
- data/tasks/rspec.rake +21 -17
- data/tasks/test.rake +13 -20
- data/test/mocks/dictionaries.rb +8 -7
- data/test/mocks/mocks.rb +20 -20
- data/test/support/fixtures.rb +11 -0
- data/test/test_helper.rb +3 -14
- data/test/unit/definition_test.rb +21 -95
- data/test/unit/deprecations_test.rb +1 -74
- data/test/unit/to_xml_test.rb +3 -3
- data/test/unit/xml_attribute_test.rb +1 -1
- data/test/unit/xml_block_test.rb +3 -3
- data/test/unit/xml_bool_test.rb +4 -4
- data/test/unit/xml_convention_test.rb +3 -3
- data/test/unit/xml_hash_test.rb +5 -14
- data/test/unit/xml_initialize_test.rb +2 -6
- data/test/unit/xml_name_test.rb +5 -24
- data/test/unit/xml_namespace_test.rb +1 -46
- data/test/unit/xml_object_test.rb +6 -6
- data/test/unit/xml_required_test.rb +3 -2
- data/test/unit/xml_text_test.rb +2 -2
- data/website/index.html +1 -1
- metadata +68 -51
- data/Manifest.txt +0 -106
- data/lib/roxml/extensions.rb +0 -6
- data/lib/roxml/extensions/array.rb +0 -13
- data/lib/roxml/extensions/array/conversions.rb +0 -35
- data/lib/roxml/extensions/deprecation.rb +0 -33
- data/lib/roxml/extensions/string.rb +0 -21
- data/lib/roxml/extensions/string/conversions.rb +0 -43
- data/lib/roxml/extensions/string/iterators.rb +0 -12
- data/lib/roxml/xml/parsers/rexml.rb +0 -84
- data/spec/string_spec.rb +0 -15
- data/test/bugs/rexml_bugs.rb +0 -15
- data/test/release/dependencies_test.rb +0 -32
- data/test/unit/xml_construct_test.rb +0 -77
- data/vendor/override_rake_task/README +0 -30
- data/vendor/override_rake_task/init.rb +0 -1
- data/vendor/override_rake_task/install.rb +0 -46
- data/vendor/override_rake_task/lib/override_rake_task.rb +0 -16
data/.gitignore
ADDED
data/.gitmodules
ADDED
data/History.txt
CHANGED
@@ -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/
|
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.
|
data/README.rdoc
CHANGED
@@ -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
|
-
|
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
|
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 = '
|
157
|
+
XML_PARSER = 'nokogiri' # or 'libxml'
|
155
158
|
end
|
156
159
|
require 'roxml'
|
157
160
|
|
data/Rakefile
CHANGED
@@ -1,51 +1,55 @@
|
|
1
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
5
|
+
* Add xml_namespaces to allow declaration of distinct prefx/url namespace pairs
|
29
6
|
|
30
|
-
|
7
|
+
* Consider class_inheritable_attribute rather than superclass.try stuff.
|
31
8
|
|
32
|
-
|
9
|
+
* Do some benchmarking
|
33
10
|
|
34
|
-
|
11
|
+
* Back with http://xml-object.rubyforge.org/doc/ to minimize need for specifications?
|
35
12
|
|
36
|
-
|
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
|
-
|
18
|
+
* :self => true for sending method_missing to this attribute?
|
42
19
|
|
43
|
-
|
20
|
+
* :attributes extensions ala HappyMapper?
|
44
21
|
|
45
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/examples/amazon.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require
|
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, :
|
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
|
-
|
30
|
-
|
31
|
-
|
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
|
data/examples/posts.rb
CHANGED
@@ -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 :
|
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
|
2
|
+
require 'spec/spec_helper'
|
3
3
|
require 'sqlite3'
|
4
4
|
require 'activerecord'
|
5
5
|
|
6
|
-
DB_PATH =
|
6
|
+
DB_PATH = 'spec/examples/rails.sqlite3'
|
7
7
|
ActiveRecord::Base.establish_connection(
|
8
8
|
:adapter => 'sqlite3',
|
9
9
|
:database => DB_PATH
|
data/examples/twitter.rb
CHANGED
@@ -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
|
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
|
data/lib/roxml.rb
CHANGED
@@ -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
|
-
|
7
|
-
|
8
|
-
end
|
4
|
+
require 'lib/roxml/definition'
|
5
|
+
require 'lib/roxml/xml'
|
9
6
|
|
10
7
|
module ROXML # :nodoc:
|
11
|
-
VERSION = '
|
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
|
-
|
19
|
-
|
20
|
-
|
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
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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 => '
|
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
|
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
|
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]
|
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
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
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(
|
471
|
-
|
472
|
-
|
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(
|
481
|
-
|
482
|
-
|
483
|
-
|
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(
|
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
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
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
|