jimmyz-happymapper 0.3.1

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/History ADDED
@@ -0,0 +1,62 @@
1
+ == 0.3.1
2
+ * 1 minor tweak
3
+ * Added to_xml and namespace_url code to the family_tree.rb example
4
+
5
+ == 0.3.0
6
+ * 5 major enhancements, 2 minor enhancements, 1 bug fixes
7
+ * to_xml methods attach namespaces to the root element and add the namespaces to the elements (if a namespace_url is specified)
8
+ * Modified namespace method to accept a hash {'prefix' => 'http://example.com/v1'} OR 'prefix'
9
+ * Added namespace_url method to set and read a full namespace URL. This adds much better stability in case prefixes change.
10
+ * Added to_xml method to HappyMapper Module to serialize objects to string
11
+ * Added to_xml_node method to HappyMapper Module to serialize objects to LibXML::XML::Node
12
+ * Full support for creating happymapper elements from scratch. has_many instance vars default to []
13
+ * Support for has_many with a primitive type (String, Boolean, etc.)
14
+ * fix for issue #8: http://jnunemaker.lighthouseapp.com/projects/20014-happy-mapper/tickets/8
15
+
16
+ == 0.2.2
17
+ * 2 minor tweaks
18
+ * removed GC.start (libxml recommended this) as setting nodes to nil should be enough, specs run 3-4x faster (Brandon Keepers)
19
+ * renamed get_tag_name to tag_name (Brandon Keepers)
20
+ * removed libxml helpers as they are no longer needed
21
+
22
+ == 0.2.1
23
+ * 1 minor fix, 3 major enhancements
24
+ * fixed warnings about using XML::Parser (mojodna)
25
+ * Improved namespace support, now handles multiple namespaces and allows namespaces to be set item wide or on a per element basis (mojodna)
26
+ * Auto detect root nodes (mojodna)
27
+ * Type coercion (mojodna)
28
+
29
+ == 0.2.0
30
+ * 1 major enhancement, 2 minor ehancements
31
+ * Automatic handling of namespaces (part by Robert Lowrey and rest by John Nunemaker)
32
+ * Added :root option to tag method. This allows setting an object as the root element, which sets xpath to use / and sets single to true
33
+ * Now defaulting tag names for classes in modules to last constant downcased
34
+
35
+ == 0.1.7 2009-01-29
36
+ * 1 minor enhancement
37
+ * Support dashes in elements (Josh Nichols)
38
+
39
+ == 0.1.6 2009-01-17
40
+ * 1 minor enhancement:
41
+ * added support for nested collection elements (Justin Marney)
42
+
43
+ == 0.1.5 2009-01-05
44
+ * 1 major enhancement:
45
+ * Updated to latest version of libxml-ruby (lightningdb)
46
+
47
+ == 0.1.4 2009-01-05
48
+ * 1 major enhancement:
49
+ * Fixed parsing when the object is the root node. (Garret Alfert)
50
+
51
+ == 0.1.3 2008-12-31
52
+ * 1 major enhancement:
53
+ * Added parsing of attributes of elements that are also mapped, see current_weather.rb for example (jeremyf)
54
+
55
+ == 0.1.2 2008-12-12
56
+ * 1 major enhancement:
57
+ * Fixed that :deep only worked for first item (dvrensk)
58
+
59
+ == 0.1.0 2008-11-16
60
+
61
+ * 1 major enhancement:
62
+ * Initial release
data/License ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 John Nunemaker
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,40 @@
1
+ examples/amazon.rb
2
+ examples/current_weather.rb
3
+ examples/dashed_elements.rb
4
+ examples/family_tree.rb
5
+ examples/post.rb
6
+ examples/twitter.rb
7
+ happymapper.gemspec
8
+ History
9
+ lib/happymapper/attribute.rb
10
+ lib/happymapper/element.rb
11
+ lib/happymapper/item.rb
12
+ lib/happymapper/version.rb
13
+ lib/happymapper.rb
14
+ License
15
+ Manifest
16
+ Rakefile
17
+ README
18
+ spec/fixtures/address.xml
19
+ spec/fixtures/commit.xml
20
+ spec/fixtures/current_weather.xml
21
+ spec/fixtures/family_tree.xml
22
+ spec/fixtures/multiple_namespaces.xml
23
+ spec/fixtures/partial_posts.xml
24
+ spec/fixtures/pita.xml
25
+ spec/fixtures/posts.xml
26
+ spec/fixtures/product_default_namespace.xml
27
+ spec/fixtures/product_no_namespace.xml
28
+ spec/fixtures/product_single_namespace.xml
29
+ spec/fixtures/radar.xml
30
+ spec/fixtures/statuses.xml
31
+ spec/happymapper_attribute_spec.rb
32
+ spec/happymapper_element_spec.rb
33
+ spec/happymapper_item_spec.rb
34
+ spec/happymapper_spec.rb
35
+ spec/spec.opts
36
+ spec/spec_helper.rb
37
+ spec/xml_helper.rb
38
+ TODO
39
+ website/css/common.css
40
+ website/index.html
data/README ADDED
@@ -0,0 +1,26 @@
1
+ = happymapper
2
+
3
+ == DESCRIPTION:
4
+
5
+ Object to xml mapping library. I have included examples to help get you going. The specs
6
+ should also point you in the right direction.
7
+
8
+ == FEATURES:
9
+
10
+ * Easy to define xml attributes and elements for an object
11
+ * Fast because it uses libxml-ruby under the hood
12
+ * Automatic conversion of xml to defined objects
13
+
14
+ == SYNOPSIS:
15
+
16
+ See examples directory in the gem to get a feel for how it works.
17
+
18
+ == INSTALL:
19
+
20
+ * add github to your sources if you haven't gem sources -a http://gems.github.com
21
+ * sudo gem install jnunemaker-happymapper
22
+ * sudo gem install happymapper (when rubyforge approves and i release there)
23
+
24
+ == TICKETS:
25
+
26
+ http://jnunemaker.lighthouseapp.com/projects/20014-happy-mapper/overview
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ ProjectName = 'happymapper'
2
+ WebsitePath = "jnunemaker@rubyforge.org:/var/www/gforge-projects/#{ProjectName}"
3
+
4
+ require 'rubygems'
5
+ require 'rake'
6
+ require 'echoe'
7
+ require 'spec/rake/spectask'
8
+ require "lib/#{ProjectName}/version"
9
+
10
+ Echoe.new(ProjectName, HappyMapper::Version) do |p|
11
+ p.description = "object to xml mapping library"
12
+ p.install_message = "May you have many happy mappings!"
13
+ p.url = "http://#{ProjectName}.rubyforge.org"
14
+ p.author = "John Nunemaker"
15
+ p.email = "nunemaker@gmail.com"
16
+ p.extra_deps = [['libxml-ruby', '= 0.9.8']]
17
+ p.need_tar_gz = false
18
+ p.docs_host = WebsitePath
19
+ end
20
+
21
+ desc 'Upload website files to rubyforge'
22
+ task :website do
23
+ sh %{rsync -av website/ #{WebsitePath}}
24
+ Rake::Task['website_docs'].invoke
25
+ end
26
+
27
+ task :website_docs do
28
+ Rake::Task['redocs'].invoke
29
+ sh %{rsync -av doc/ #{WebsitePath}/docs}
30
+ end
31
+
32
+ desc 'Preps the gem for a new release'
33
+ task :prepare do
34
+ %w[manifest build_gemspec].each do |task|
35
+ Rake::Task[task].invoke
36
+ end
37
+ end
38
+
39
+ Rake::Task[:default].prerequisites.clear
40
+ task :default => :spec
41
+ Spec::Rake::SpecTask.new do |t|
42
+ t.spec_files = FileList["spec/**/*_spec.rb"]
43
+ end
data/TODO ADDED
File without changes
@@ -0,0 +1,34 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'happymapper')
3
+
4
+ file_contents = File.read(dir + '/../spec/fixtures/pita.xml')
5
+
6
+ # The document `pita.xml` contains both a default namespace and the 'georss'
7
+ # namespace (for the 'point' element).
8
+ module PITA
9
+ class Item
10
+ include HappyMapper
11
+
12
+ tag 'Item' # if you put class in module you need tag
13
+ element :asin, String, :tag => 'ASIN'
14
+ element :detail_page_url, String, :tag => 'DetailPageURL'
15
+ element :manufacturer, String, :tag => 'Manufacturer', :deep => true
16
+ # this is the only element that exists in a different namespace, so it
17
+ # must be explicitly specified
18
+ element :point, String, :tag => 'point', :namespace => 'georss'
19
+ end
20
+
21
+ class Items
22
+ include HappyMapper
23
+
24
+ tag 'Items' # if you put class in module you need tag
25
+ element :total_results, Integer, :tag => 'TotalResults'
26
+ element :total_pages, Integer, :tag => 'TotalPages'
27
+ has_many :items, Item
28
+ end
29
+ end
30
+
31
+ item = PITA::Items.parse(file_contents, :single => true)
32
+ item.items.each do |i|
33
+ puts i.asin, i.detail_page_url, i.manufacturer, ''
34
+ end
@@ -0,0 +1,21 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'happymapper')
3
+
4
+ file_contents = File.read(dir + '/../spec/fixtures/current_weather.xml')
5
+
6
+ class CurrentWeather
7
+ include HappyMapper
8
+
9
+ tag 'ob'
10
+ namespace 'aws'
11
+ element :temperature, Integer, :tag => 'temp'
12
+ element :feels_like, Integer, :tag => 'feels-like'
13
+ element :current_condition, String, :tag => 'current-condition', :attributes => {:icon => String}
14
+ end
15
+
16
+ CurrentWeather.parse(file_contents).each do |current_weather|
17
+ puts "temperature: #{current_weather.temperature}"
18
+ puts "feels_like: #{current_weather.feels_like}"
19
+ puts "current_condition: #{current_weather.current_condition}"
20
+ puts "current_condition.icon: #{current_weather.current_condition.icon}"
21
+ end
@@ -0,0 +1,20 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'happymapper')
3
+
4
+ file_contents = File.read(dir + '/../spec/fixtures/commit.xml')
5
+
6
+ module GitHub
7
+ class Commit
8
+ include HappyMapper
9
+
10
+ tag "commit"
11
+ element :url, String
12
+ element :tree, String
13
+ element :message, String
14
+ element :id, String
15
+ element :'committed-date', Date
16
+ end
17
+ end
18
+
19
+ commit = GitHub::Commit.parse(file_contents)
20
+ puts commit.committed_date, commit.url, commit.id
@@ -0,0 +1,55 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'happymapper')
3
+
4
+ file_contents = File.read(dir + '/../spec/fixtures/family_tree.xml')
5
+
6
+ module FamilySearch
7
+ class AlternateIds
8
+ include HappyMapper
9
+
10
+ tag 'alternateIds'
11
+ namespace 'fsapi-v1' => 'http://api.familysearch.org/v1'
12
+ has_many :ids, String, :tag => 'id'
13
+ end
14
+
15
+ class Information
16
+ include HappyMapper
17
+
18
+ namespace 'fsapi-v1' => 'http://api.familysearch.org/v1'
19
+ has_one :alternateIds, AlternateIds
20
+ end
21
+
22
+ class Person
23
+ include HappyMapper
24
+
25
+ namespace_url 'http://api.familysearch.org/familytree/v1'
26
+ attribute :version, String
27
+ attribute :modified, Time
28
+ attribute :id, String
29
+ has_one :information, Information
30
+ end
31
+
32
+ class Persons
33
+ include HappyMapper
34
+
35
+ namespace_url 'http://api.familysearch.org/familytree/v1'
36
+ has_many :person, Person
37
+ end
38
+
39
+ class FamilyTree
40
+ include HappyMapper
41
+
42
+ tag 'familytree'
43
+ namespace_url 'http://api.familysearch.org/familytree/v1'
44
+ attribute :version, String
45
+ attribute :status_message, String, :tag => 'statusMessage'
46
+ attribute :status_code, String, :tag => 'statusCode'
47
+ has_one :persons, Persons
48
+ end
49
+ end
50
+
51
+ familytree = FamilySearch::FamilyTree.parse(file_contents)
52
+ familytree.persons.person.each do |p|
53
+ puts p.id, p.information.alternateIds.ids, ''
54
+ end
55
+ puts familytree.to_xml
data/examples/post.rb ADDED
@@ -0,0 +1,19 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'happymapper')
3
+
4
+ file_contents = File.read(dir + '/../spec/fixtures/posts.xml')
5
+
6
+ class Post
7
+ include HappyMapper
8
+
9
+ attribute :href, String
10
+ attribute :hash, String
11
+ attribute :description, String
12
+ attribute :tag, String
13
+ attribute :time, DateTime
14
+ attribute :others, Integer
15
+ attribute :extended, String
16
+ end
17
+
18
+ posts = Post.parse(file_contents)
19
+ posts.each { |post| puts post.description, post.href, post.extended, '' }
@@ -0,0 +1,37 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'happymapper')
3
+
4
+ file_contents = File.read(dir + '/../spec/fixtures/statuses.xml')
5
+
6
+ class User
7
+ include HappyMapper
8
+
9
+ element :id, Integer
10
+ element :name, String
11
+ element :screen_name, String
12
+ element :location, String
13
+ element :description, String
14
+ element :profile_image_url, String
15
+ element :url, String
16
+ element :protected, Boolean
17
+ element :followers_count, Integer
18
+ end
19
+
20
+ class Status
21
+ include HappyMapper
22
+
23
+ element :id, Integer
24
+ element :text, String
25
+ element :created_at, Time
26
+ element :source, String
27
+ element :truncated, Boolean
28
+ element :in_reply_to_status_id, Integer
29
+ element :in_reply_to_user_id, Integer
30
+ element :favorited, Boolean
31
+ has_one :user, User
32
+ end
33
+
34
+ statuses = Status.parse(file_contents)
35
+ statuses.each do |status|
36
+ puts status.user.name, status.user.screen_name, status.text, status.source, ''
37
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{happymapper}
5
+ s.version = "0.3.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["John Nunemaker"]
9
+ s.date = %q{2009-02-19}
10
+ s.description = %q{object to xml mapping library}
11
+ s.email = %q{nunemaker@gmail.com}
12
+ s.extra_rdoc_files = ["lib/happymapper/attribute.rb", "lib/happymapper/element.rb", "lib/happymapper/item.rb", "lib/happymapper/version.rb", "lib/happymapper.rb", "README", "TODO"]
13
+ s.files = ["examples/amazon.rb", "examples/current_weather.rb", "examples/dashed_elements.rb", "examples/family_tree.rb", "examples/post.rb", "examples/twitter.rb", "happymapper.gemspec", "History", "lib/happymapper/attribute.rb", "lib/happymapper/element.rb", "lib/happymapper/item.rb", "lib/happymapper/version.rb", "lib/happymapper.rb", "License", "Manifest", "Rakefile", "README", "spec/fixtures/address.xml", "spec/fixtures/commit.xml", "spec/fixtures/current_weather.xml", "spec/fixtures/family_tree.xml", "spec/fixtures/multiple_namespaces.xml", "spec/fixtures/partial_posts.xml", "spec/fixtures/pita.xml", "spec/fixtures/posts.xml", "spec/fixtures/product_default_namespace.xml", "spec/fixtures/product_no_namespace.xml", "spec/fixtures/product_single_namespace.xml", "spec/fixtures/radar.xml", "spec/fixtures/statuses.xml", "spec/happymapper_attribute_spec.rb", "spec/happymapper_element_spec.rb", "spec/happymapper_item_spec.rb", "spec/happymapper_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/xml_helper.rb", "TODO", "website/css/common.css", "website/index.html"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://happymapper.rubyforge.org}
16
+ s.post_install_message = %q{May you have many happy mappings!}
17
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Happymapper", "--main", "README"]
18
+ s.require_paths = ["lib"]
19
+ s.rubyforge_project = %q{happymapper}
20
+ s.rubygems_version = %q{1.3.1}
21
+ s.summary = %q{object to xml mapping library}
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_runtime_dependency(%q<libxml-ruby>, ["= 0.9.8"])
29
+ else
30
+ s.add_dependency(%q<libxml-ruby>, ["= 0.9.8"])
31
+ end
32
+ else
33
+ s.add_dependency(%q<libxml-ruby>, ["= 0.9.8"])
34
+ end
35
+ end
@@ -0,0 +1,191 @@
1
+ dir = File.dirname(__FILE__)
2
+ $:.unshift(dir) unless $:.include?(dir) || $:.include?(File.expand_path(dir))
3
+
4
+ require 'date'
5
+ require 'time'
6
+ require 'rubygems'
7
+ gem 'libxml-ruby', '= 0.9.8'
8
+ require 'xml'
9
+
10
+ class Boolean; end
11
+
12
+ module HappyMapper
13
+
14
+ DEFAULT_NS = "happymapper"
15
+
16
+ def self.included(base)
17
+ base.instance_variable_set("@attributes", {})
18
+ base.instance_variable_set("@elements", {})
19
+ base.extend ClassMethods
20
+ end
21
+
22
+ def to_xml
23
+ node = to_xml_node
24
+ node.to_s
25
+ end
26
+
27
+ def to_xml_node(root_node = nil)
28
+ node = XML::Node.new(self.class.tag_name)
29
+ root_node ||= node
30
+ if self.class.namespace_url
31
+ if root_node
32
+ namespace_object = root_node.namespaces.find_by_href(self.class.namespace_url)
33
+ namespace_object ||= XML::Namespace.new root_node, self.class.namespace, self.class.namespace_url
34
+ node.namespaces.namespace = namespace_object
35
+ end
36
+ else
37
+ nil
38
+ end
39
+ self.class.elements.each do |e|
40
+ if e.options[:single] == false
41
+ self.send("#{e.method_name}").each do |array_element|
42
+ node << e.to_xml_node(array_element,root_node)
43
+ end
44
+ else
45
+ node << e.to_xml_node(self.send("#{e.method_name}"),root_node)
46
+ end
47
+ end
48
+ self.class.attributes.each do |a|
49
+ attribute_value = self.send("#{a.method_name}")
50
+ node.attributes[a.tag] = attribute_value.to_s unless attribute_value.nil?
51
+ end
52
+ node
53
+ end
54
+
55
+ module ClassMethods
56
+ def attribute(name, type, options={})
57
+ attribute = Attribute.new(name, type, options)
58
+ @attributes[to_s] ||= []
59
+ @attributes[to_s] << attribute
60
+ attr_accessor attribute.method_name.intern
61
+ end
62
+
63
+ def attributes
64
+ @attributes[to_s] || []
65
+ end
66
+
67
+ def element(name, type, options={})
68
+ options = {:namespace => @namespace}.merge(options)
69
+ element = Element.new(name, type, options)
70
+ @elements[to_s] ||= []
71
+ @elements[to_s] << element
72
+ attr_accessor element.method_name.intern
73
+
74
+ # set the default value of a collection instance variable to [] instead of nil
75
+ if options[:single] == false
76
+ module_eval <<-eof
77
+ def #{element.method_name}
78
+ @#{element.method_name} ||= []
79
+ end
80
+ eof
81
+ end
82
+ end
83
+
84
+ def elements
85
+ @elements[to_s] || []
86
+ end
87
+
88
+ def has_one(name, type, options={})
89
+ element name, type, {:single => true}.merge(options)
90
+ end
91
+
92
+ def has_many(name, type, options={})
93
+ element name, type, {:single => false}.merge(options)
94
+ end
95
+
96
+ # Specify a namespace if a node and all its children are all namespaced
97
+ # elements. This is simpler than passing the :namespace option to each
98
+ # defined element.
99
+ #
100
+ # namespace can either be a string for the prefix or a hash with 'prefix' => 'url'
101
+ def namespace(namespace = nil)
102
+ if namespace
103
+ if namespace.is_a? Hash
104
+ namespace.each_pair do |k,v|
105
+ @namespace = k.to_s
106
+ @namespace_url = v
107
+ end
108
+ else
109
+ @namespace = namespace
110
+ end
111
+ end
112
+ @namespace
113
+ end
114
+
115
+ def namespace_url(url = nil)
116
+ @namespace_url = url if url
117
+ @namespace_url
118
+ end
119
+
120
+ def tag(new_tag_name)
121
+ @tag_name = new_tag_name.to_s
122
+ end
123
+
124
+ def tag_name
125
+ @tag_name ||= to_s.split('::')[-1].downcase
126
+ end
127
+
128
+ def parse(xml, options = {})
129
+ # locally scoped copy of namespace for this parse run
130
+ namespace = @namespace
131
+
132
+ if xml.is_a?(XML::Node)
133
+ node = xml
134
+ else
135
+ if xml.is_a?(XML::Document)
136
+ node = xml.root
137
+ else
138
+ node = XML::Parser.string(xml).parse.root
139
+ end
140
+
141
+ root = node.name == tag_name
142
+ end
143
+
144
+ # This is the entry point into the parsing pipeline, so the default
145
+ # namespace prefix registered here will propagate down
146
+ namespaces = node.namespaces
147
+ if @namespace_url && namespaces.default.href != @namespace_url
148
+ namespace = namespaces.find_by_href(@namespace_url).prefix
149
+ elsif namespaces && namespaces.default
150
+ # don't assign the default_prefix if it has already been assigned
151
+ namespaces.default_prefix = DEFAULT_NS unless namespaces.find_by_prefix(DEFAULT_NS)
152
+ namespace ||= DEFAULT_NS
153
+ end
154
+
155
+ xpath = root ? '/' : './/'
156
+ xpath += "#{namespace}:" if namespace
157
+ xpath += tag_name
158
+ # puts "parse: #{xpath}"
159
+
160
+ nodes = node.find(xpath)
161
+ collection = nodes.collect do |n|
162
+ obj = new
163
+
164
+ attributes.each do |attr|
165
+ obj.send("#{attr.method_name}=",
166
+ attr.from_xml_node(n, namespace))
167
+ end
168
+
169
+ elements.each do |elem|
170
+ obj.send("#{elem.method_name}=",
171
+ elem.from_xml_node(n, namespace))
172
+ end
173
+
174
+ obj
175
+ end
176
+
177
+ # per http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354
178
+ nodes = nil
179
+
180
+ if options[:single] || root
181
+ collection.first
182
+ else
183
+ collection
184
+ end
185
+ end
186
+ end
187
+ end
188
+
189
+ require 'happymapper/item'
190
+ require 'happymapper/attribute'
191
+ require 'happymapper/element'