roxml 2.5.3 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|