xml-object 0.9.8 → 0.9.9
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/WHATSNEW +3 -0
- data/lib/xml-object.rb +18 -22
- data/lib/xml-object/adapters.rb +1 -1
- data/lib/xml-object/adapters/hpricot.rb +8 -6
- data/lib/xml-object/adapters/libxml.rb +4 -5
- data/lib/xml-object/adapters/rexml.rb +4 -5
- data/lib/xml-object/collection_proxy.rb +10 -9
- data/lib/xml-object/element.rb +6 -4
- data/lib/xml-object/{array_notation.rb → properties.rb} +52 -1
- data/xml-object.gemspec +10 -14
- metadata +5 -6
- data/lib/xml-object/method_missing_dispatchers.rb +0 -52
data/WHATSNEW
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
* 0.9.9 (2008-12-18):
|
2
|
+
- Bugfix for the new faster-than-nokogiri Hpricot version (broke the API)
|
3
|
+
|
1
4
|
* 0.9.8 (2008-10-23):
|
2
5
|
- Much improved test suite. More granular, better coverage, much faster
|
3
6
|
- The collection proxy behaviour is now a lot faster when called in a loop
|
data/lib/xml-object.rb
CHANGED
@@ -5,43 +5,40 @@ $:.unshift File.join(File.dirname(__FILE__), 'xml-object')
|
|
5
5
|
|
6
6
|
require 'adapters'
|
7
7
|
require 'adapters/rexml'
|
8
|
-
require '
|
8
|
+
require 'properties'
|
9
9
|
require 'collection_proxy'
|
10
10
|
require 'element'
|
11
|
-
require 'method_missing_dispatchers'
|
12
11
|
|
13
12
|
module XMLObject
|
14
13
|
# Returns a String or Array object representing the given XML, decorated
|
15
14
|
# with methods to access attributes and/or child elements.
|
16
|
-
def self.new(duck)
|
15
|
+
def self.new(duck) # :nodoc:
|
17
16
|
case duck
|
18
|
-
when adapter::Element then new_decorated_obj
|
19
|
-
when Array
|
20
|
-
else new adapter.new(duck)
|
17
|
+
when @adapter::Element then new_decorated_obj duck
|
18
|
+
when Array then duck.map! { |d| new_decorated_obj d }
|
19
|
+
else new @adapter.new(duck)
|
21
20
|
end
|
22
21
|
end
|
23
22
|
|
24
23
|
private ##################################################################
|
25
24
|
|
26
|
-
# Takes any Element object, and converts it recursively into
|
25
|
+
# Takes any adapter Element object, and converts it recursively into
|
27
26
|
# the corresponding tree of decorated objects.
|
28
27
|
def self.new_decorated_obj(xml) # :nodoc:
|
29
|
-
|
30
|
-
|
28
|
+
# More than one child, empty value, and all children with the same name?
|
29
|
+
obj = if xml.children.size > 1 && xml.value !~ /\S/ &&
|
30
|
+
xml.children.map { |c| c.name }.uniq.size == 1
|
31
31
|
|
32
|
-
CollectionProxy.new xml
|
32
|
+
CollectionProxy.new xml # This is an empty array wrap
|
33
33
|
else
|
34
|
-
|
35
|
-
xml.value.extend Element
|
34
|
+
Element.new xml # This one is an actual element
|
36
35
|
end
|
37
36
|
|
38
|
-
|
37
|
+
xml.children.each { |child| add_child obj, child.name, new(child) }
|
38
|
+
xml.attributes.each { |name, value| add_attribute obj, name, value }
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
# Let's teach our object some new tricks:
|
44
|
-
obj.extend ArrayNotation, MethodMissingDispatchers
|
40
|
+
# Let's teach our object how to access its XML elements and attributes
|
41
|
+
obj.extend Properties
|
45
42
|
end
|
46
43
|
|
47
44
|
# Decorates the given object 'obj' with a method 'name' that returns the
|
@@ -65,12 +62,11 @@ module XMLObject
|
|
65
62
|
|
66
63
|
# Decorates the given object 'obj' with a method 'name' that returns the
|
67
64
|
# given 'attr_value'.
|
68
|
-
def self.add_attribute(obj, name,
|
69
|
-
|
65
|
+
def self.add_attribute(obj, name, value) # :nodoc:
|
70
66
|
attributes = obj.instance_variable_get :@__attributes
|
71
|
-
attributes[
|
67
|
+
attributes[key = name.to_sym] = value.strip.gsub /\s+/, ' '
|
72
68
|
|
73
69
|
obj.instance_variable_set :@__attributes, attributes
|
74
|
-
|
70
|
+
value
|
75
71
|
end
|
76
72
|
end
|
data/lib/xml-object/adapters.rb
CHANGED
@@ -7,9 +7,10 @@ module XMLObject::Adapters::Hpricot
|
|
7
7
|
# either +read+ or +to_s+.
|
8
8
|
def self.new(duck)
|
9
9
|
case
|
10
|
-
when duck.
|
11
|
-
|
12
|
-
when duck.respond_to?(:to_s)
|
10
|
+
when duck.respond_to?(:read)
|
11
|
+
then Element.new(::Hpricot::XML(duck.read).root)
|
12
|
+
when duck.respond_to?(:to_s)
|
13
|
+
then Element.new(::Hpricot::XML(duck.to_s).root)
|
13
14
|
else raise "Don't know how to deal with '#{duck.class}' object"
|
14
15
|
end
|
15
16
|
end
|
@@ -18,17 +19,18 @@ module XMLObject::Adapters::Hpricot
|
|
18
19
|
|
19
20
|
class Element < XMLObject::Adapters::Base::Element # :nodoc:
|
20
21
|
def initialize(xml)
|
21
|
-
@raw, @name
|
22
|
+
@raw, @name = xml, xml.name
|
23
|
+
@attributes = xml.attributes || {}
|
22
24
|
|
23
25
|
@element_nodes = xml.children.select { |c| c.elem? }
|
24
26
|
|
25
27
|
@text_nodes = xml.children.select do |c|
|
26
28
|
c.text? && !c.is_a?(::Hpricot::CData)
|
27
|
-
end.map { |c| c.to_s }
|
29
|
+
end.map! { |c| c.to_s }
|
28
30
|
|
29
31
|
@cdata_nodes = xml.children.select do |c|
|
30
32
|
c.is_a? ::Hpricot::CData
|
31
|
-
end.map { |c| c.to_s }
|
33
|
+
end.map! { |c| c.to_s }
|
32
34
|
|
33
35
|
super
|
34
36
|
end
|
@@ -6,11 +6,10 @@ module XMLObject::Adapters::LibXML
|
|
6
6
|
# either +read+ or +to_s+.
|
7
7
|
def self.new(duck)
|
8
8
|
case
|
9
|
-
when duck.is_a?(::LibXML::XML::Node) then Element.new(duck)
|
10
9
|
when duck.respond_to?(:read)
|
11
|
-
then new(::LibXML::XML::Parser.string(duck.read).parse.root)
|
10
|
+
then Element.new(::LibXML::XML::Parser.string(duck.read).parse.root)
|
12
11
|
when duck.respond_to?(:to_s)
|
13
|
-
then new(::LibXML::XML::Parser.string(duck.to_s).parse.root)
|
12
|
+
then Element.new(::LibXML::XML::Parser.string(duck.to_s).parse.root)
|
14
13
|
else raise "Don't know how to deal with '#{duck.class}' object"
|
15
14
|
end
|
16
15
|
end
|
@@ -23,8 +22,8 @@ module XMLObject::Adapters::LibXML
|
|
23
22
|
|
24
23
|
@element_nodes = xml.children.select { |c| c.element? }
|
25
24
|
|
26
|
-
@text_nodes = xml.children.select { |c| c.text? }.map { |c| c.to_s }
|
27
|
-
@cdata_nodes = xml.children.select { |c| c.cdata? }.map do |c|
|
25
|
+
@text_nodes = xml.children.select { |c| c.text? }.map! { |c| c.to_s }
|
26
|
+
@cdata_nodes = xml.children.select { |c| c.cdata? }.map! do |c|
|
28
27
|
c.to_s.chomp(']]>').sub('<![CDATA[', '')
|
29
28
|
end
|
30
29
|
|
@@ -6,11 +6,10 @@ module XMLObject::Adapters::REXML
|
|
6
6
|
# either +read+ or +to_s+.
|
7
7
|
def self.new(duck)
|
8
8
|
case
|
9
|
-
when duck.is_a?(::REXML::Element) then Element.new(duck)
|
10
9
|
when duck.respond_to?(:read)
|
11
|
-
then new(::REXML::Document.new(duck.read).root)
|
10
|
+
then Element.new(::REXML::Document.new(duck.read).root)
|
12
11
|
when duck.respond_to?(:to_s)
|
13
|
-
then new(::REXML::Document.new(duck.to_s).root)
|
12
|
+
then Element.new(::REXML::Document.new(duck.to_s).root)
|
14
13
|
else raise "Don't know how to deal with '#{duck.class}' object"
|
15
14
|
end
|
16
15
|
end
|
@@ -25,11 +24,11 @@ module XMLObject::Adapters::REXML
|
|
25
24
|
|
26
25
|
@text_nodes = xml.children.select do |child|
|
27
26
|
child.class == ::REXML::Text
|
28
|
-
end.
|
27
|
+
end.map! { |child| child.to_s }
|
29
28
|
|
30
29
|
@cdata_nodes = xml.children.select do |child|
|
31
30
|
child.class == ::REXML::CData
|
32
|
-
end.
|
31
|
+
end.map! { |child| child.to_s }
|
33
32
|
|
34
33
|
super
|
35
34
|
end
|
@@ -3,15 +3,16 @@ class XMLObject::CollectionProxy # :nodoc:
|
|
3
3
|
instance_methods.each do |m|
|
4
4
|
meth_str, meth_sym = m.to_s, m.to_sym # Ruby 1.8 and 1.9 differ, so...
|
5
5
|
|
6
|
-
undef_method meth_sym unless
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
undef_method meth_sym unless meth_str =~ /^__/ ||
|
7
|
+
meth_str =~ /^instance_/ ||
|
8
|
+
meth_sym == :extend ||
|
9
|
+
meth_sym == :nil? ||
|
10
|
+
meth_sym == :object_id
|
11
11
|
end
|
12
12
|
|
13
|
-
def initialize(
|
14
|
-
@__children, @__attributes
|
13
|
+
def initialize(xml) # :nodoc:
|
14
|
+
@__children, @__attributes = {}, {}
|
15
|
+
@__target_kid = xml.children[0].name.to_sym
|
15
16
|
end
|
16
17
|
|
17
18
|
private ##################################################################
|
@@ -23,13 +24,13 @@ class XMLObject::CollectionProxy # :nodoc:
|
|
23
24
|
if dispatched.nil? && @__children[@__target_kid].respond_to?(m)
|
24
25
|
dispatched = @__children[@__target_kid].__send__(m, *a, &b)
|
25
26
|
|
26
|
-
unless dispatched
|
27
|
+
unless nil == dispatched
|
27
28
|
# All is fair in Love and War. And 100% coverage.
|
28
29
|
instance_eval \
|
29
30
|
%{ def #{m}(*a, &b); @__children[@__target_kid].#{m}(*a, &b); end }
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
+
(nil == dispatched) ? raise(NameError.new(m.to_s)) : dispatched
|
34
35
|
end
|
35
36
|
end
|
data/lib/xml-object/element.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
module XMLObject::Element
|
2
|
-
def self.
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
def self.new(xml) # :nodoc:
|
3
|
+
element = xml.value
|
4
|
+
element.instance_variable_set :@__raw_xml, xml.raw
|
5
|
+
element.instance_variable_set :@__children, {}
|
6
|
+
element.instance_variable_set :@__attributes, {}
|
7
|
+
element.extend self
|
6
8
|
end
|
7
9
|
|
8
10
|
# The raw, unadapted XML object. Whatever this is, it really depends on
|
@@ -1,4 +1,5 @@
|
|
1
|
-
module XMLObject::
|
1
|
+
module XMLObject::Properties
|
2
|
+
|
2
3
|
# Array-bracket (+[]+) notation access to elements and attributes. Use
|
3
4
|
# when the element or attribute you need to reach is not reachable via dot
|
4
5
|
# notation (because it's not a valid method name, or because the method
|
@@ -42,4 +43,54 @@ module XMLObject::ArrayNotation
|
|
42
43
|
end
|
43
44
|
end
|
44
45
|
end
|
46
|
+
|
47
|
+
private ##################################################################
|
48
|
+
|
49
|
+
def __question_dispatch(meth, *args, &block)
|
50
|
+
return nil unless meth.to_s.match(/\?$/) && args.empty? && block.nil?
|
51
|
+
|
52
|
+
method_sans_question = meth.to_s.chomp('?').to_sym
|
53
|
+
|
54
|
+
if boolish = __send__(method_sans_question)
|
55
|
+
bool = case
|
56
|
+
when %w[ true yes t y ].include?(boolish.downcase) then true
|
57
|
+
when %w[ false no f n ].include?(boolish.downcase) then false
|
58
|
+
else nil
|
59
|
+
end
|
60
|
+
|
61
|
+
unless bool.nil?
|
62
|
+
instance_eval %{ def #{meth}; #{bool ? 'true' : 'false'}; end }
|
63
|
+
end
|
64
|
+
|
65
|
+
bool
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def __dot_notation_dispatch(meth, *args, &block)
|
70
|
+
return nil unless args.empty? && block.nil?
|
71
|
+
|
72
|
+
if @__children.has_key?(meth)
|
73
|
+
instance_eval %{ def #{meth}; @__children[%s|#{meth}|]; end }
|
74
|
+
@__children[meth]
|
75
|
+
|
76
|
+
elsif @__attributes.has_key?(meth)
|
77
|
+
instance_eval %{ def #{meth}; @__attributes[%s|#{meth}|]; end }
|
78
|
+
@__attributes[meth]
|
79
|
+
|
80
|
+
elsif @__children.has_key?(naive_sing = meth.to_s.chomp('s').to_sym) &&
|
81
|
+
@__children[naive_sing].is_a?(Array)
|
82
|
+
|
83
|
+
instance_eval %{ def #{meth}; @__children[%s|#{naive_sing}|]; end }
|
84
|
+
@__children[naive_sing]
|
85
|
+
|
86
|
+
elsif defined?(ActiveSupport::Inflector) &&
|
87
|
+
@__children.has_key?(singular = meth.to_s.singularize.to_sym) &&
|
88
|
+
@__children[singular].is_a?(Array)
|
89
|
+
|
90
|
+
instance_eval %{ def #{meth}; @__children[%s|#{singular}|]; end }
|
91
|
+
@__children[singular]
|
92
|
+
else
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
end
|
45
96
|
end
|
data/xml-object.gemspec
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
Gem::Specification.new do |gem|
|
2
|
-
gem.rubyforge_project = 'xml-object'
|
1
|
+
XMLOBJECT_GEMSPEC = Gem::Specification.new do |gem|
|
2
|
+
gem.name = gem.rubyforge_project = 'xml-object'
|
3
|
+
gem.homepage = 'http://xml-object.rubyforge.org'
|
3
4
|
|
4
|
-
gem.
|
5
|
-
gem.
|
6
|
-
|
7
|
-
gem.version, gem.date = '0.9.8', '2008-10-23'
|
8
|
-
gem.author, gem.email = 'Jordi Bunster', 'jordi@bunster.org'
|
5
|
+
gem.version, gem.date = '0.9.9', '2008-12-18'
|
6
|
+
gem.author, gem.email = 'Jordi Bunster', 'jordi@bunster.org'
|
9
7
|
|
10
8
|
gem.summary = "The Rubyista's way to do quick XML sit-ups"
|
11
9
|
gem.description = %{ XMLObject is a library for reading (not writing) XML.
|
@@ -13,6 +11,10 @@ Gem::Specification.new do |gem|
|
|
13
11
|
documents of a known structure. While not devoid of caveats, it does
|
14
12
|
have a very pleasant, idiomatic Ruby syntax. }.strip!.gsub! /\s+/, ' '
|
15
13
|
|
14
|
+
gem.has_rdoc = !!(gem.extra_rdoc_files = %w[ README.rdoc ])
|
15
|
+
gem.rdoc_options += %w[
|
16
|
+
--title XMLObject --main README.rdoc --inline-source ]
|
17
|
+
|
16
18
|
gem.files = %w[
|
17
19
|
MIT-LICENSE
|
18
20
|
README.rdoc
|
@@ -26,16 +28,10 @@ Gem::Specification.new do |gem|
|
|
26
28
|
lib/xml-object/adapters/libxml.rb
|
27
29
|
lib/xml-object/adapters/rexml.rb
|
28
30
|
lib/xml-object/adapters.rb
|
29
|
-
lib/xml-object/array_notation.rb
|
30
31
|
lib/xml-object/collection_proxy.rb
|
31
32
|
lib/xml-object/element.rb
|
32
|
-
lib/xml-object/
|
33
|
+
lib/xml-object/properties.rb
|
33
34
|
lib/xml-object.rb
|
34
35
|
xml-object.gemspec
|
35
36
|
]
|
36
|
-
|
37
|
-
gem.has_rdoc = !!(gem.extra_rdoc_files = %w[ README.rdoc ])
|
38
|
-
gem.rdoc_options << '--title' << 'XMLObject' <<
|
39
|
-
'--main' << 'README.rdoc' <<
|
40
|
-
'--inline-source'
|
41
37
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xml-object
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordi Bunster
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-12-18 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -34,14 +34,13 @@ files:
|
|
34
34
|
- lib/xml-object/adapters/libxml.rb
|
35
35
|
- lib/xml-object/adapters/rexml.rb
|
36
36
|
- lib/xml-object/adapters.rb
|
37
|
-
- lib/xml-object/array_notation.rb
|
38
37
|
- lib/xml-object/collection_proxy.rb
|
39
38
|
- lib/xml-object/element.rb
|
40
|
-
- lib/xml-object/
|
39
|
+
- lib/xml-object/properties.rb
|
41
40
|
- lib/xml-object.rb
|
42
41
|
- xml-object.gemspec
|
43
42
|
has_rdoc: true
|
44
|
-
homepage: http://
|
43
|
+
homepage: http://xml-object.rubyforge.org
|
45
44
|
post_install_message:
|
46
45
|
rdoc_options:
|
47
46
|
- --title
|
@@ -66,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
65
|
requirements: []
|
67
66
|
|
68
67
|
rubyforge_project: xml-object
|
69
|
-
rubygems_version: 1.3.
|
68
|
+
rubygems_version: 1.3.1
|
70
69
|
signing_key:
|
71
70
|
specification_version: 2
|
72
71
|
summary: The Rubyista's way to do quick XML sit-ups
|
@@ -1,52 +0,0 @@
|
|
1
|
-
module XMLObject::MethodMissingDispatchers # :nodoc:
|
2
|
-
|
3
|
-
private ##################################################################
|
4
|
-
|
5
|
-
def __question_dispatch(meth, *args, &block)
|
6
|
-
return nil unless meth.to_s.match(/\?$/) && args.empty? && block.nil?
|
7
|
-
|
8
|
-
method_sans_question = meth.to_s.chomp('?').to_sym
|
9
|
-
|
10
|
-
if boolish = __send__(method_sans_question)
|
11
|
-
bool = case
|
12
|
-
when %w[ true yes t y ].include?(boolish.downcase) then true
|
13
|
-
when %w[ false no f n ].include?(boolish.downcase) then false
|
14
|
-
else nil
|
15
|
-
end
|
16
|
-
|
17
|
-
unless bool.nil?
|
18
|
-
instance_eval %{ def #{meth}; #{bool ? 'true' : 'false'}; end }
|
19
|
-
end
|
20
|
-
|
21
|
-
bool
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def __dot_notation_dispatch(meth, *args, &block)
|
26
|
-
return nil unless args.empty? && block.nil?
|
27
|
-
|
28
|
-
if @__children.has_key?(meth)
|
29
|
-
instance_eval %{ def #{meth}; @__children[%s|#{meth}|]; end }
|
30
|
-
@__children[meth]
|
31
|
-
|
32
|
-
elsif @__attributes.has_key?(meth)
|
33
|
-
instance_eval %{ def #{meth}; @__attributes[%s|#{meth}|]; end }
|
34
|
-
@__attributes[meth]
|
35
|
-
|
36
|
-
elsif @__children.has_key?(naive_sing = meth.to_s.chomp('s').to_sym) &&
|
37
|
-
@__children[naive_sing].is_a?(Array)
|
38
|
-
|
39
|
-
instance_eval %{ def #{meth}; @__children[%s|#{naive_sing}|]; end }
|
40
|
-
@__children[naive_sing]
|
41
|
-
|
42
|
-
elsif defined?(ActiveSupport::Inflector) &&
|
43
|
-
@__children.has_key?(singular = meth.to_s.singularize.to_sym) &&
|
44
|
-
@__children[singular].is_a?(Array)
|
45
|
-
|
46
|
-
instance_eval %{ def #{meth}; @__children[%s|#{singular}|]; end }
|
47
|
-
@__children[singular]
|
48
|
-
else
|
49
|
-
nil
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|