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 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
@@ -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 'array_notation'
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(duck)
19
- when Array then duck.map { |d| new_decorated_obj(d) }
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
- obj = if ( (xml.value !~ /\S/) && (xml.children.size > 1) &&
30
- xml.children.collect { |e| e.name }.uniq.size == 1 )
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.children[0].name.to_sym
32
+ CollectionProxy.new xml # This is an empty array wrap
33
33
  else
34
- # Teach our string to behave like and XML Element
35
- xml.value.extend Element
34
+ Element.new xml # This one is an actual element
36
35
  end
37
36
 
38
- obj.instance_variable_set :@__raw_xml, xml.raw
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
- xml.children.each { |child| add_child(obj, child.name, new(child)) }
41
- xml.attributes.each { |name, value| add_attribute(obj, name, value) }
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, attr_value) # :nodoc:
69
-
65
+ def self.add_attribute(obj, name, value) # :nodoc:
70
66
  attributes = obj.instance_variable_get :@__attributes
71
- attributes[(key = name.to_sym)] = attr_value.strip.gsub(/\s+/, ' ')
67
+ attributes[key = name.to_sym] = value.strip.gsub /\s+/, ' '
72
68
 
73
69
  obj.instance_variable_set :@__attributes, attributes
74
- attr_value
70
+ value
75
71
  end
76
72
  end
@@ -18,7 +18,7 @@ module XMLObject # :nodoc:
18
18
  private ###########################################################
19
19
 
20
20
  def text_value
21
- @text_nodes.reject { |n| n !~ /\S/ }.join
21
+ @text_value_memo ||= @text_nodes.reject { |n| n !~ /\S/ }.join
22
22
  end
23
23
 
24
24
  def cdata_value
@@ -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.is_a?(::Hpricot::Elem) then Element.new(duck)
11
- when duck.respond_to?(:read) then new(::Hpricot::XML(duck.read).root)
12
- when duck.respond_to?(:to_s) then new(::Hpricot::XML(duck.to_s).root)
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, @attributes = xml, xml.name, xml.attributes
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.collect { |child| child.to_s }
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.collect { |child| child.to_s }
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 ( (meth_str =~ /^__/) ||
7
- (meth_str =~ /^instance_/) ||
8
- (meth_sym == :extend) ||
9
- (meth_sym == :nil?) ||
10
- (meth_sym == :object_id) )
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(target_kid_key) # :nodoc:
14
- @__children, @__attributes, @__target_kid = {}, {}, target_kid_key
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.nil?
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
- dispatched.nil? ? raise(NameError.new(m.to_s)) : dispatched
34
+ (nil == dispatched) ? raise(NameError.new(m.to_s)) : dispatched
34
35
  end
35
36
  end
@@ -1,8 +1,10 @@
1
1
  module XMLObject::Element
2
- def self.extended(obj) # :nodoc:
3
- obj.instance_variable_set :@__children, {}
4
- obj.instance_variable_set :@__attributes, {}
5
- obj
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::ArrayNotation
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
@@ -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.name = 'xml-object'
5
- gem.homepage = 'http://github.com/jordi/xml-object'
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/method_missing_dispatchers.rb
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.8
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-10-23 00:00:00 -04:00
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/method_missing_dispatchers.rb
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://github.com/jordi/xml-object
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.0
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