jordi-xml-object 0.9.5

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/MIT-LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2008 Jordi Bunster <jordi@bunster.org>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,152 @@
1
+ = XMLObject
2
+
3
+ (This is inspired by Python's +xml_objectify+)
4
+
5
+ XMLObject attempts to make the accessing of small, well-formed XML structures
6
+ convenient, by using dot notation to represent both attributes and child
7
+ elements whenever possible.
8
+
9
+ XML parsing libraries (in general) have interfaces that are useful when
10
+ one is using XML for its intended purpose, but cumbersome when one always
11
+ sends the same XML structure, and always process all of it in the same
12
+ way. This one aims to be a bit different.
13
+
14
+ == Example usage
15
+
16
+ <recipe name="bread" prep_time="5 mins" cook_time="3 hours">
17
+ <title>Basic bread</title>
18
+ <ingredient amount="8" unit="dL">Flour</ingredient>
19
+ <ingredient amount="10" unit="grams">Yeast</ingredient>
20
+ <ingredient amount="4" unit="dL" state="warm">Water</ingredient>
21
+ <ingredient amount="1" unit="teaspoon">Salt</ingredient>
22
+ <instructions easy="yes" hard="false">
23
+ <step>Mix all ingredients together.</step>
24
+ <step>Knead thoroughly.</step>
25
+ <step>Cover with a cloth, and leave for one hour in warm room.</step>
26
+ <step>Knead again.</step>
27
+ <step>Place in a bread baking tin.</step>
28
+ <step>Cover with a cloth, and leave for one hour in warm room.</step>
29
+ <step>Bake in the oven at 180(degrees)C for 30 minutes.</step>
30
+ </instructions>
31
+ </recipe>
32
+
33
+ require 'xml-object'
34
+ recipe = XMLObject.new io_with_recipe_xml_shown_above
35
+
36
+ recipe.name => "bread"
37
+ recipe.title => "Basic bread"
38
+
39
+ recipe.ingredients.is_a?(Array) => true
40
+ recipe.ingredients.first.amount => "8" # Not a Fixnum. Too hard. :(
41
+
42
+ recipe.instructions.easy? => true
43
+
44
+ recipe.instructions.first.upcase => "MIX ALL INGREDIENTS TOGETHER."
45
+ recipe.instructions.steps.size => 7
46
+
47
+ == Installation instructions
48
+
49
+ sudo gem install jordi-xml-object --source http://gems.github.com
50
+
51
+ == Motivation
52
+
53
+ XML is an *extensible* markup language. It is extensible because it is
54
+ meant to define markup languages for *any* type of document, so new tags
55
+ are needed depending on the problem domain.
56
+
57
+ Sometimes, however, XML ends up being used to solve a much simpler problem:
58
+ the issue of passing a data-structure over the network, and/or between two
59
+ different languages. Tools like +JSON+ or +YAML+ are a much better fit for
60
+ this kind of job, but one doesn't always have that luxury.
61
+
62
+ == Caveats
63
+
64
+ The dot notation is used as follows. For the given file:
65
+
66
+ <outer id="root" name="foo">
67
+ <name>Outer Element</name>
68
+ </outer>
69
+
70
+ +outer.name+ is the +name+ *element*. Child elements are always looked up
71
+ first, then attributes. To access the attribute in the case of ambiguity,
72
+ use outer[:attr => 'name'].
73
+
74
+ +outer.id+ is really Object#id, because all of the object methods are
75
+ preserved (this is on purpose). To access the attribute +id+, use
76
+ outer[:attr => 'id'], or outer['id'] since there's no element/attribute
77
+ ambiguity.
78
+
79
+ == Features & Problems
80
+
81
+ === Collection auto-folding
82
+
83
+ Similar to XmlSimple, XMLObject folds same named elements at the same
84
+ level. For example:
85
+
86
+ <student>
87
+ <name>Bob</name>
88
+ <course>Math</course>
89
+ <course>Biology</course>
90
+ </student>
91
+
92
+ student = XMLObject.new(xml_file)
93
+
94
+ student.course.is_a? Array => true
95
+ student.course.first == 'Math' => true
96
+ student.course.last == 'Biology => true
97
+
98
+ === Collection pluralization
99
+
100
+ With the same file from the +Collection auto-folding+ section above, you
101
+ also get this (courtesy of +ActiveSupport+'s +Inflector+):
102
+
103
+ student.courses.first == student.course.first => true
104
+
105
+ === Collection proxy
106
+
107
+ Sometimes, collections are expressed with a container element in XML:
108
+
109
+ <student>
110
+ <name>Bob</name>
111
+ <courses>
112
+ <course>Math</course>
113
+ <course>Biology</course>
114
+ </courses>
115
+ </student>
116
+
117
+ In this case, since the container element +courses+ has no text element
118
+ of its own, and it only has elements of one name under it, it delegates
119
+ all methods it doesn't contain to the collection below, so you get:
120
+
121
+ student.courses.collect { |c| c.downcase.to_sym } => [:math, :biology]
122
+
123
+ === Question mark notation
124
+
125
+ Strings that look like booleans are "booleanized" if called by their
126
+ question mark names (such as +enabled?+)
127
+
128
+ === Adapters
129
+
130
+ XMLObject supports different adapters to do the actual XML parsing. It ships
131
+ with +REXML+ and +Hpricot+ adapters. If +Hpricot+ is detected it gets used,
132
+ otherwise +REXML+ is used as a fallback.
133
+
134
+ === Recursive
135
+
136
+ The design of the adapters assumes parsing of the objects recursively. Deep
137
+ files are bound to throw +SystemStackError+, but for the kinds of files I
138
+ need to read, things are working fine so far. In any case, stream parsing
139
+ is on the TODO list.
140
+
141
+ === Incomplete
142
+
143
+ It most likely doesn't work with a ton of features of complex XML files. I
144
+ will always try to accomodate those, as long as they don't make the basic
145
+ usage more complex. As usual, patches welcome.
146
+
147
+ == Legal
148
+
149
+ Copyright (c) 2008 Jordi Bunster, released under the MIT license
150
+
151
+
152
+
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ * Make use of libxml if it's available, then fallback to REXML
2
+ * Refactor so as to not do things recursively
3
+ * Remove ActiveSupport dependency
data/WHATSNEW ADDED
@@ -0,0 +1,38 @@
1
+ * 0.9.5 (2008-10-15):
2
+ - Project renamed to XMLObject, to match project name at Rubyforge.
3
+ The other names were taken. :(
4
+
5
+ * 0.9.0 (2008-10-15):
6
+ - Added support for plug-able adapters
7
+ - Backported REXML code as an adapter, added Hpricot adapter
8
+ - Performance: XMLStruct now decorates objects lazily
9
+ - Performance: XMLStruct uses the Hpricot adapter if possible, otherwise
10
+ REXML as a fallback
11
+ - API Change: XMLStruct.new is mostly delegated to the adapter, and both
12
+ included adapters behave the same: a String is considered to be
13
+ XML data, anything else is probed for #read and then #to_s
14
+
15
+ * 0.2.1 (2008-10-13):
16
+ - Fixed a bug where attributes with dashes would crash the party
17
+
18
+ * 0.2.0 (2008-10-13):
19
+ - Broke backwards compatibility
20
+ - XMLStruct.new now returns decorated String or Array objects, so that
21
+ access to elements, attributes, and "collection" values is consistent
22
+ - While Strings are no longer auto-typecast to float or int, they now
23
+ have, whenever possible, a question-mark form, which attemps to
24
+ returns booleans for strings like "Yes" and "false"
25
+ - XMLStruct.new can now take a filename or a file object
26
+ - Added more tests
27
+
28
+ * 0.1.3 (2008-10-10):
29
+ - Switched tests to use test/spec
30
+ - Added XMLStruct#to_obj to return the corresponding Ruby object value
31
+ - Added XMLStruct#to_raw_xml to return the REXML object
32
+ - Added documentation on auto-typecasting behaviour caveat
33
+
34
+ * 0.1.2 (2008-10-10):
35
+ - Documentation
36
+
37
+ * 0.1.1 (2008-10-10):
38
+ - First "release" ;)
@@ -0,0 +1 @@
1
+ require 'xml-object'
@@ -0,0 +1,47 @@
1
+ module XMLObject::Adapters::Hpricot
2
+
3
+ # Can take a String of XML data, or anything that responds to
4
+ # either +read+ or +to_s+.
5
+ def self.new(duck)
6
+ case
7
+ when duck.is_a?(::Hpricot::Elem) : Element.new(duck)
8
+ when duck.is_a?(::String) : new(::Hpricot::XML(duck).root)
9
+ when duck.respond_to?(:read) : new(duck.read)
10
+ when duck.respond_to?(:to_s) : new(duck.to_s)
11
+ else raise "Don't know how to deal with '#{duck.class}' object"
12
+ end
13
+ end
14
+
15
+ private ##################################################################
16
+
17
+ class Element # :nodoc:
18
+ attr_reader :raw, :name, :value, :attributes, :children
19
+
20
+ def text_value(raw)
21
+ raw.children.select do |e|
22
+ (e.class == ::Hpricot::Text) && !e.to_s.blank?
23
+ end.join.to_s
24
+ end
25
+
26
+ def cdata_value(raw)
27
+ raw.children.select do |e|
28
+ (e.class == ::Hpricot::CData) && !e.to_s.blank?
29
+ end.first.to_s
30
+ end
31
+
32
+ def initialize(xml)
33
+ @raw, @name, @attributes, @children = xml, xml.name, {}, []
34
+
35
+ @attributes = xml.attributes
36
+ xml.children.select { |e| e.elem? }.each do |e|
37
+ @children << self.class.new(e)
38
+ end
39
+
40
+ @value = case
41
+ when (not text_value(@raw).blank?) : text_value(@raw)
42
+ when (not cdata_value(@raw).blank?) : cdata_value(@raw)
43
+ else ''
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,34 @@
1
+ module XMLObject::Adapters::REXML
2
+ require 'rexml/document'
3
+
4
+ # Can take a String of XML data, or anything that responds to
5
+ # either +read+ or +to_s+.
6
+ def self.new(duck)
7
+ case
8
+ when duck.is_a?(::REXML::Element) : Element.new(duck)
9
+ when duck.is_a?(::String) : new(::REXML::Document.new(duck).root)
10
+ when duck.respond_to?(:read) : new(duck.read)
11
+ when duck.respond_to?(:to_s) : new(duck.to_s)
12
+ else raise "Don't know how to deal with '#{duck.class}' object"
13
+ end
14
+ end
15
+
16
+ private ##################################################################
17
+
18
+ class Element # :nodoc:
19
+ attr_reader :raw, :name, :value, :attributes, :children
20
+
21
+ def initialize(xml)
22
+ @raw, @name, @attributes, @children = xml, xml.name, {}, []
23
+
24
+ @attributes = xml.attributes
25
+ xml.each_element { |e| @children << self.class.new(e) }
26
+
27
+ @value = case
28
+ when (not xml.text.blank?) : xml.text.to_s
29
+ when (xml.cdatas.size >= 1) : xml.cdatas.first.to_s
30
+ else ''
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ module XMLObject::ArrayNotation
2
+ # Array-bracket (+[]+) notation access to elements and attributes. Use
3
+ # when the element or attribute you need to reach is not reachable via dot
4
+ # notation (because it's not a valid method name, or because the method
5
+ # exists, such as +id+ or +class+).
6
+ #
7
+ # It also supports a hash key, which is used to reach attributes named
8
+ # the same as elements in the same depth level (which otherwise go first)
9
+ #
10
+ # All of this is a lot easier to explain by example:
11
+ #
12
+ # <article id="main_article" author="j-random">
13
+ # <author>J. Random Hacker</author>
14
+ # </article>
15
+ #
16
+ # article.id => 9314390 # Object#id
17
+ # article[:id] => "main_article" # id attribute
18
+ # article[:author] => "J. Random Hacker" # <author> element
19
+ # article[:attr => 'author'] => "j-random" # author attribute
20
+ #
21
+ # Valid keys for the hash notation in the example above are +:attr+,
22
+ # +:attribute+, +:child+, and +:element+.
23
+ def [](name)
24
+ return @__target[name] if @__target && name.is_a?(Numeric)
25
+
26
+ unless name.is_a? Hash
27
+ key = name.to_sym
28
+
29
+ return @__children[key] if @__children.has_key?(key)
30
+ return @__attributes[key] if @__attributes.has_key?(key)
31
+ end
32
+
33
+ raise 'one and only one key allowed' if name.size != 1
34
+
35
+ case (param = name.keys.first.to_sym)
36
+ when :element : @__children[name.values.first.to_sym]
37
+ when :child : @__children[name.values.first.to_sym]
38
+ when :attr : @__attributes[name.values.first.to_sym]
39
+ when :attribute : @__attributes[name.values.first.to_sym]
40
+ else raise %{ Invalid key :#{param.to_s}.
41
+ Use one of :element, :child, :attr, or :attribute }.squish!
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,9 @@
1
+ class XMLObject::BlankishSlate # :nodoc:
2
+
3
+ instance_methods.each do |m|
4
+ undef_method m unless m =~ /^__/ ||
5
+ m == 'respond_to?' ||
6
+ m == 'extend' ||
7
+ m =~ /^instance_/
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ class XMLObject::CollectionProxy < XMLObject::BlankishSlate # :nodoc:
2
+ def initialize(target)
3
+ @__children, @__attributes, @__target = {}, {}, target
4
+ end
5
+
6
+ private ##################################################################
7
+
8
+ def method_missing(m, *a, &b) # :nodoc:
9
+ dp = __question_dispatch(m, *a, &b)
10
+ dp = __dot_notation_dispatch(m, *a, &b) if dp.nil?
11
+ dp = @__target.__send__(m, *a, &b) if @__target.respond_to?(m) && dp.nil?
12
+ dp
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ module XMLObject # :nodoc:
2
+ module Adapters # :nodoc:
3
+ ADAPTERS_PATH = File.join(File.dirname(__FILE__), 'adapters')
4
+
5
+ Default = begin
6
+ require 'hpricot'
7
+ require File.join(ADAPTERS_PATH, 'hpricot')
8
+ Hpricot
9
+ rescue LoadError
10
+ require File.join(ADAPTERS_PATH, 'rexml')
11
+ REXML
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,43 @@
1
+ module XMLObject::MethodMissingDispatchers # :nodoc:
2
+
3
+ private ##################################################################
4
+
5
+ def __question_dispatch(meth, *args, &block)
6
+ return 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).downcase
11
+ bool = case
12
+ when %w[ true yes t y ].include?(boolish) : true
13
+ when %w[ false no f n ].include?(boolish) : false
14
+ else nil
15
+ end
16
+
17
+ unless bool.nil? # Fun, eh?
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 unless args.empty? && block.nil?
27
+
28
+ if @__children.has_key?(singular = meth.to_s.singularize.to_sym) &&
29
+ @__children[singular].is_a?(Array)
30
+
31
+ instance_eval %{ def #{meth}; @__children[%s|#{singular}|]; end }
32
+ @__children[singular]
33
+
34
+ elsif @__children.has_key?(meth)
35
+ instance_eval %{ def #{meth}; @__children[%s|#{meth}|]; end }
36
+ @__children[meth]
37
+
38
+ elsif @__attributes.has_key?(meth)
39
+ instance_eval %{ def #{meth}; @__attributes[%s|#{meth}|]; end }
40
+ @__attributes[meth]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,35 @@
1
+ module XMLObject::String
2
+ def self.extended(obj) # :nodoc:
3
+ obj.instance_variable_set :@__children, {}
4
+ obj.instance_variable_set :@__attributes, {}
5
+ obj
6
+ end
7
+
8
+ # Attempts to detect wether this String is really an integer or float,
9
+ # and returns accordingly. If not, just returns the string.
10
+ def rb
11
+ @__rb ||= case
12
+ when (self !~ /\S/) : ''
13
+ when match(/[a-zA-Z]/) : ::String.new(self)
14
+ when match(/^[+-]?\d+$/) : self.to_i
15
+ when match(/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/) : self.to_f
16
+ else ::String.new(self)
17
+ end
18
+ end
19
+
20
+ # A decorated String is blank when it has a blank value, no child
21
+ # elements, and no attributes. For example:
22
+ #
23
+ # <blank_element></blank_element>
24
+ def blank?
25
+ (self !~ /\S/) && @__children.blank? && @__attributes.blank?
26
+ end
27
+
28
+ private ##################################################################
29
+
30
+ def method_missing(m, *a, &b) # :nodoc:
31
+ dp = __question_dispatch(m, *a, &b)
32
+ dp = __dot_notation_dispatch(m, *a, &b) if dp.nil?
33
+ dp
34
+ end
35
+ end
data/lib/xml-object.rb ADDED
@@ -0,0 +1,86 @@
1
+ require 'rubygems'
2
+ require 'activesupport'
3
+
4
+ module XMLObject
5
+
6
+ unless defined?(BASE_DIR) # Slow call
7
+ BASE_DIR = File.join(File.dirname(__FILE__), 'xml-object')
8
+ end
9
+
10
+ require File.join(BASE_DIR, 'default_adapter')
11
+ require File.join(BASE_DIR, 'method_missing_dispatchers')
12
+ require File.join(BASE_DIR, 'array_notation')
13
+ require File.join(BASE_DIR, 'blankish_slate')
14
+ require File.join(BASE_DIR, 'collection_proxy')
15
+ require File.join(BASE_DIR, 'string')
16
+
17
+ def self.adapter=(adapter_module)
18
+ @adapter = adapter_module
19
+ end
20
+
21
+ def self.adapter
22
+ @adapter ||= Adapters::Default
23
+ end
24
+
25
+ # Returns a String or Array object representing the given XML, decorated
26
+ # with methods to access attributes and/or child elements.
27
+ def self.new(duck)
28
+ case duck
29
+ when adapter::Element : new_decorated_obj(duck)
30
+ when Array : duck.map { |d| new_decorated_obj(d) }
31
+ else new adapter.new(duck)
32
+ end
33
+ end
34
+
35
+ private ##################################################################
36
+
37
+ # Takes any Element object, and converts it recursively into
38
+ # the corresponding tree of decorated objects.
39
+ def self.new_decorated_obj(xml)
40
+ obj = if xml.value.blank? &&
41
+ xml.children.collect { |e| e.name }.uniq.size == 1
42
+
43
+ CollectionProxy.new new(xml.children)
44
+ else
45
+ xml.value.extend String # Teach our string to behave like XML
46
+ end
47
+
48
+ obj.instance_variable_set :@__raw_xml, xml
49
+
50
+ xml.children.each { |child| add_child(obj, child.name, new(child)) }
51
+ xml.attributes.each { |name, value| add_attribute(obj, name, value) }
52
+
53
+ # Let's teach our object some new tricks:
54
+ obj.extend(ArrayNotation).extend(MethodMissingDispatchers)
55
+ end
56
+
57
+ # Decorates the given object 'obj' with a method 'name' that returns the
58
+ # given 'element'. If 'name' is already taken, takes care of the array
59
+ # folding behaviour.
60
+ def self.add_child(obj, name, element)
61
+ key = name.to_sym
62
+ children = obj.instance_variable_get :@__children
63
+
64
+ children[key] = if children[key]
65
+
66
+ children[key] = [ children[key] ] unless children[key].is_a? Array
67
+ children[key] << element
68
+ else
69
+ element
70
+ end
71
+
72
+ obj.instance_variable_set :@__children, children
73
+ element
74
+ end
75
+
76
+ # Decorates the given object 'obj' with a method 'name' that returns the
77
+ # given 'attr_value'.
78
+ def self.add_attribute(obj, name, attr_value) # :nodoc:
79
+
80
+ attributes = obj.instance_variable_get :@__attributes
81
+ attributes[(key = name.to_sym)] = attr_value.squish.extend String
82
+
83
+ obj.instance_variable_set :@__attributes, attributes
84
+ attr_value
85
+ end
86
+ end
@@ -0,0 +1,43 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.add_dependency 'activesupport'
3
+
4
+ gem.name = 'xml-object'
5
+ gem.version = '0.9.5'
6
+ gem.date = '2008-10-15'
7
+
8
+ gem.author = 'Jordi Bunster'
9
+ gem.email = 'jordi@bunster.org'
10
+ gem.homepage = 'http://github.com/jordi/xml-object'
11
+
12
+ gem.summary = "The Rubyista's way to do quick XML sit-ups"
13
+ gem.description = %{ XMLObject is a library for reading (not writing) XML.
14
+ It is particularly suited for cases where one is dealing with small
15
+ documents of a known structure. While not devoid of caveats, it does
16
+ have a very pleasant, idiomatic Ruby syntax. }.strip!.gsub! /\s+/, ' '
17
+
18
+ gem.files = %w[
19
+ MIT-LICENSE
20
+ README.rdoc
21
+ TODO
22
+ WHATSNEW
23
+ lib
24
+ lib/jordi-xml-object.rb
25
+ lib/xml-object
26
+ lib/xml-object/adapters
27
+ lib/xml-object/adapters/hpricot.rb
28
+ lib/xml-object/adapters/rexml.rb
29
+ lib/xml-object/array_notation.rb
30
+ lib/xml-object/blankish_slate.rb
31
+ lib/xml-object/collection_proxy.rb
32
+ lib/xml-object/default_adapter.rb
33
+ lib/xml-object/method_missing_dispatchers.rb
34
+ lib/xml-object/string.rb
35
+ lib/xml-object.rb
36
+ xml-object.gemspec
37
+ ]
38
+
39
+ gem.has_rdoc = !!(gem.extra_rdoc_files = %w[ README.rdoc ])
40
+ gem.rdoc_options << '--title' << 'XMLObject' <<
41
+ '--main' << 'README.rdoc' <<
42
+ '--inline-source'
43
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jordi-xml-object
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.5
5
+ platform: ruby
6
+ authors:
7
+ - Jordi Bunster
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-10-15 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ description: XMLObject is a library for reading (not writing) XML. It is particularly suited for cases where one is dealing with small documents of a known structure. While not devoid of caveats, it does have a very pleasant, idiomatic Ruby syntax.
25
+ email: jordi@bunster.org
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - README.rdoc
32
+ files:
33
+ - MIT-LICENSE
34
+ - README.rdoc
35
+ - TODO
36
+ - WHATSNEW
37
+ - lib
38
+ - lib/jordi-xml-object.rb
39
+ - lib/xml-object
40
+ - lib/xml-object/adapters
41
+ - lib/xml-object/adapters/hpricot.rb
42
+ - lib/xml-object/adapters/rexml.rb
43
+ - lib/xml-object/array_notation.rb
44
+ - lib/xml-object/blankish_slate.rb
45
+ - lib/xml-object/collection_proxy.rb
46
+ - lib/xml-object/default_adapter.rb
47
+ - lib/xml-object/method_missing_dispatchers.rb
48
+ - lib/xml-object/string.rb
49
+ - lib/xml-object.rb
50
+ - xml-object.gemspec
51
+ has_rdoc: true
52
+ homepage: http://github.com/jordi/xml-object
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --title
56
+ - XMLObject
57
+ - --main
58
+ - README.rdoc
59
+ - --inline-source
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.2.0
78
+ signing_key:
79
+ specification_version: 2
80
+ summary: The Rubyista's way to do quick XML sit-ups
81
+ test_files: []
82
+