xml-object 0.9.8 → 0.9.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|