legolin-happymapper 0.3.0

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.
Files changed (44) hide show
  1. data/HOW_TO_RELEASE +5 -0
  2. data/History +59 -0
  3. data/License +20 -0
  4. data/Manifest +42 -0
  5. data/README +61 -0
  6. data/Rakefile +43 -0
  7. data/TODO +0 -0
  8. data/examples/amazon.rb +34 -0
  9. data/examples/current_weather.rb +21 -0
  10. data/examples/dashed_elements.rb +20 -0
  11. data/examples/multi_street_address.rb +15 -0
  12. data/examples/post.rb +19 -0
  13. data/examples/twitter.rb +37 -0
  14. data/happymapper.gemspec +0 -0
  15. data/legolin-happymapper.gemspec +34 -0
  16. data/lib/happymapper.rb +161 -0
  17. data/lib/happymapper/attribute.rb +3 -0
  18. data/lib/happymapper/element.rb +3 -0
  19. data/lib/happymapper/item.rb +192 -0
  20. data/lib/happymapper/version.rb +3 -0
  21. data/spec/fixtures/address.xml +8 -0
  22. data/spec/fixtures/analytics.xml +61 -0
  23. data/spec/fixtures/commit.xml +52 -0
  24. data/spec/fixtures/current_weather.xml +89 -0
  25. data/spec/fixtures/family_tree.xml +7 -0
  26. data/spec/fixtures/multi_street_address.xml +9 -0
  27. data/spec/fixtures/multiple_namespaces.xml +170 -0
  28. data/spec/fixtures/nested_namespaces.xml +17 -0
  29. data/spec/fixtures/pita.xml +133 -0
  30. data/spec/fixtures/posts.xml +23 -0
  31. data/spec/fixtures/product_default_namespace.xml +10 -0
  32. data/spec/fixtures/product_no_namespace.xml +10 -0
  33. data/spec/fixtures/product_single_namespace.xml +10 -0
  34. data/spec/fixtures/radar.xml +21 -0
  35. data/spec/fixtures/statuses.xml +422 -0
  36. data/spec/happymapper_attribute_spec.rb +17 -0
  37. data/spec/happymapper_element_spec.rb +17 -0
  38. data/spec/happymapper_item_spec.rb +115 -0
  39. data/spec/happymapper_spec.rb +719 -0
  40. data/spec/spec.opts +1 -0
  41. data/spec/spec_helper.rb +13 -0
  42. data/website/css/common.css +47 -0
  43. data/website/index.html +98 -0
  44. metadata +129 -0
@@ -0,0 +1,5 @@
1
+ * Change lib/happymapper/version to new version.
2
+ * rake prepare
3
+ * git commit version bump
4
+ * git push for github
5
+ * rake release for rubyforge
data/History ADDED
@@ -0,0 +1,59 @@
1
+ == 0.2.5
2
+ * 1 minor tweak
3
+ * Classes can now be strings instead of constants so you don't have to worry about class definition order (this was all for technicalpickles, enjoy!)
4
+
5
+ == 0.2.4
6
+ * 1 minor tweak
7
+ * Added a patch that allows even crazy namespaces to work
8
+
9
+ == 0.2.3
10
+ * 1 minor tweak
11
+ * bumped the version of libxml-ruby to 1.1.3
12
+
13
+ == 0.2.2
14
+ * 2 minor tweaks
15
+ * removed GC.start (libxml recommended this) as setting nodes to nil should be enough, specs run 3-4x faster (Brandon Keepers)
16
+ * renamed get_tag_name to tag_name (Brandon Keepers)
17
+ * removed libxml helpers as they are no longer needed
18
+
19
+ == 0.2.1
20
+ * 1 minor fix, 3 major enhancements
21
+ * fixed warnings about using XML::Parser (mojodna)
22
+ * Improved namespace support, now handles multiple namespaces and allows namespaces to be set item wide or on a per element basis (mojodna)
23
+ * Auto detect root nodes (mojodna)
24
+ * Type coercion (mojodna)
25
+
26
+ == 0.2.0
27
+ * 1 major enhancement, 2 minor ehancements
28
+ * Automatic handling of namespaces (part by Robert Lowrey and rest by John Nunemaker)
29
+ * 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
30
+ * Now defaulting tag names for classes in modules to last constant downcased
31
+
32
+ == 0.1.7 2009-01-29
33
+ * 1 minor enhancement
34
+ * Support dashes in elements (Josh Nichols)
35
+
36
+ == 0.1.6 2009-01-17
37
+ * 1 minor enhancement:
38
+ * added support for nested collection elements (Justin Marney)
39
+
40
+ == 0.1.5 2009-01-05
41
+ * 1 major enhancement:
42
+ * Updated to latest version of libxml-ruby (lightningdb)
43
+
44
+ == 0.1.4 2009-01-05
45
+ * 1 major enhancement:
46
+ * Fixed parsing when the object is the root node. (Garret Alfert)
47
+
48
+ == 0.1.3 2008-12-31
49
+ * 1 major enhancement:
50
+ * Added parsing of attributes of elements that are also mapped, see current_weather.rb for example (jeremyf)
51
+
52
+ == 0.1.2 2008-12-12
53
+ * 1 major enhancement:
54
+ * Fixed that :deep only worked for first item (dvrensk)
55
+
56
+ == 0.1.0 2008-11-16
57
+
58
+ * 1 major enhancement:
59
+ * 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.
@@ -0,0 +1,42 @@
1
+ examples/amazon.rb
2
+ examples/current_weather.rb
3
+ examples/dashed_elements.rb
4
+ examples/multi_street_address.rb
5
+ examples/post.rb
6
+ examples/twitter.rb
7
+ happymapper.gemspec
8
+ History
9
+ HOW_TO_RELEASE
10
+ lib/happymapper/attribute.rb
11
+ lib/happymapper/element.rb
12
+ lib/happymapper/item.rb
13
+ lib/happymapper/version.rb
14
+ lib/happymapper.rb
15
+ License
16
+ Manifest
17
+ Rakefile
18
+ README
19
+ spec/fixtures/address.xml
20
+ spec/fixtures/analytics.xml
21
+ spec/fixtures/commit.xml
22
+ spec/fixtures/current_weather.xml
23
+ spec/fixtures/family_tree.xml
24
+ spec/fixtures/multi_street_address.xml
25
+ spec/fixtures/multiple_namespaces.xml
26
+ spec/fixtures/nested_namespaces.xml
27
+ spec/fixtures/pita.xml
28
+ spec/fixtures/posts.xml
29
+ spec/fixtures/product_default_namespace.xml
30
+ spec/fixtures/product_no_namespace.xml
31
+ spec/fixtures/product_single_namespace.xml
32
+ spec/fixtures/radar.xml
33
+ spec/fixtures/statuses.xml
34
+ spec/happymapper_attribute_spec.rb
35
+ spec/happymapper_element_spec.rb
36
+ spec/happymapper_item_spec.rb
37
+ spec/happymapper_spec.rb
38
+ spec/spec.opts
39
+ spec/spec_helper.rb
40
+ TODO
41
+ website/css/common.css
42
+ website/index.html
data/README ADDED
@@ -0,0 +1,61 @@
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
+ == EXAMPLES:
15
+
16
+ Here is a simple example that maps Twitter statuses and users.
17
+
18
+ class User
19
+ include HappyMapper
20
+
21
+ element :id, Integer
22
+ element :name, String
23
+ element :screen_name, String
24
+ element :location, String
25
+ element :description, String
26
+ element :profile_image_url, String
27
+ element :url, String
28
+ element :protected, Boolean
29
+ element :followers_count, Integer
30
+ end
31
+
32
+ class Status
33
+ include HappyMapper
34
+
35
+ element :id, Integer
36
+ element :text, String
37
+ element :created_at, Time
38
+ element :source, String
39
+ element :truncated, Boolean
40
+ element :in_reply_to_status_id, Integer
41
+ element :in_reply_to_user_id, Integer
42
+ element :favorited, Boolean
43
+ has_one :user, User
44
+ end
45
+
46
+ See examples directory in the gem for more examples.
47
+
48
+ http://github.com/jnunemaker/happymapper/tree/master/examples/
49
+
50
+ == INSTALL:
51
+
52
+ * sudo gem install jnunemaker-happymapper -s http://gems.github.com
53
+ * sudo gem install happymapper (when rubyforge approves and i release there)
54
+
55
+ == TICKETS:
56
+
57
+ http://github.com/jnunemaker/happymapper/issues/
58
+
59
+ == DOCS:
60
+
61
+ http://rdoc.info/projects/jnunemaker/happymapper
@@ -0,0 +1,43 @@
1
+ ProjectName = 'legolin-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/happymapper/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', '= 1.1.3']]
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,15 @@
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/address_multi_street.xml')
5
+
6
+ class MultiStreetAddress
7
+ include HappyMapper
8
+
9
+ # allow primitive type to be collection
10
+ has_many :street_address, String, :tag => "streetaddress"
11
+ element :city, String
12
+ element :state_or_providence, String, :tag => "stateOfProvidence"
13
+ element :zip, String
14
+ element :country, String
15
+ end
@@ -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
File without changes
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{legolin-happymapper}
5
+ s.version = "0.3.0"
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{2010-03-25}
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/multi_street_address.rb", "examples/post.rb", "examples/twitter.rb", "happymapper.gemspec", "History", "HOW_TO_RELEASE", "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/analytics.xml", "spec/fixtures/commit.xml", "spec/fixtures/current_weather.xml", "spec/fixtures/family_tree.xml", "spec/fixtures/multi_street_address.xml", "spec/fixtures/multiple_namespaces.xml", "spec/fixtures/nested_namespaces.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", "TODO", "website/css/common.css", "website/index.html", "legolin-happymapper.gemspec"]
14
+ s.homepage = %q{http://legolin-happymapper.rubyforge.org}
15
+ s.post_install_message = %q{May you have many happy mappings!}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Legolin-happymapper", "--main", "README"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{legolin-happymapper}
19
+ s.rubygems_version = %q{1.3.6}
20
+ s.summary = %q{object to xml mapping library}
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<libxml-ruby>, ["= 1.1.3"])
28
+ else
29
+ s.add_dependency(%q<libxml-ruby>, ["= 1.1.3"])
30
+ end
31
+ else
32
+ s.add_dependency(%q<libxml-ruby>, ["= 1.1.3"])
33
+ end
34
+ end
@@ -0,0 +1,161 @@
1
+ dir = File.dirname(__FILE__)
2
+
3
+ require 'date'
4
+ require 'time'
5
+ require 'rubygems'
6
+ gem 'libxml-ruby', '= 1.1.3'
7
+ require 'xml'
8
+
9
+ class Boolean; end
10
+
11
+ module HappyMapper
12
+
13
+ DEFAULT_NS = "happymapper"
14
+
15
+ def self.included(base)
16
+ base.instance_variable_set("@attributes", {})
17
+ base.instance_variable_set("@elements", {})
18
+ base.extend ClassMethods
19
+ end
20
+
21
+ module ClassMethods
22
+ def attribute(name, type, options={})
23
+ attribute = Attribute.new(name, type, options)
24
+ @attributes[to_s] ||= []
25
+ @attributes[to_s] << attribute
26
+ attr_accessor attribute.method_name.intern
27
+ end
28
+
29
+ def attributes
30
+ @attributes[to_s] || []
31
+ end
32
+
33
+ def element(name, type, options={})
34
+ element = Element.new(name, type, options)
35
+ @elements[to_s] ||= []
36
+ @elements[to_s] << element
37
+ attr_accessor element.method_name.intern
38
+ end
39
+
40
+ def elements
41
+ @elements[to_s] || []
42
+ end
43
+
44
+ def has_one(name, type, options={})
45
+ element name, type, {:single => true}.merge(options)
46
+ end
47
+
48
+ def has_many(name, type, options={})
49
+ element name, type, {:single => false}.merge(options)
50
+ end
51
+
52
+ # Specify a namespace if a node and all its children are all namespaced
53
+ # elements. This is simpler than passing the :namespace option to each
54
+ # defined element.
55
+ def namespace(namespace = nil)
56
+ @namespace = namespace if namespace
57
+ @namespace
58
+ end
59
+
60
+ def tag(new_tag_name)
61
+ @tag_name = new_tag_name.to_s
62
+ end
63
+
64
+ def tag_name
65
+ @tag_name ||= to_s.split('::')[-1].downcase
66
+ end
67
+
68
+ def parse(xml, options = {})
69
+ if xml.is_a?(XML::Node)
70
+ node = xml
71
+ else
72
+ if xml.is_a?(XML::Document)
73
+ node = xml.root
74
+ else
75
+ node = XML::Parser.string(xml).parse.root
76
+ end
77
+
78
+ root = node.name == tag_name
79
+ end
80
+
81
+ namespace = @namespace || (node.namespaces && node.namespaces.default)
82
+ namespace = "#{DEFAULT_NS}:#{namespace}" if namespace
83
+
84
+ xpath = root ? '/' : './/'
85
+ xpath += "#{DEFAULT_NS}:" if namespace
86
+ xpath += tag_name
87
+
88
+ nodes = node.find(xpath, Array(namespace))
89
+ collection = nodes.collect do |n|
90
+ obj = new
91
+
92
+ attributes.each do |attr|
93
+ obj.send("#{attr.method_name}=",
94
+ attr.from_xml_node(n, namespace))
95
+ end
96
+
97
+ elements.each do |elem|
98
+ obj.send("#{elem.method_name}=",
99
+ elem.from_xml_node(n, namespace))
100
+ end
101
+
102
+ obj
103
+ end
104
+
105
+ # per http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354
106
+ nodes = nil
107
+
108
+ if options[:single] || root
109
+ collection.first
110
+ else
111
+ collection
112
+ end
113
+ end
114
+ end
115
+
116
+ def to_xml_node
117
+ node = XML::Node.new(self.class.tag_name)
118
+
119
+ self.class.attributes.each do |attribute|
120
+ value = self.send(attribute.method_name)
121
+ node.attributes[attribute.name] = value.to_s unless value.nil?
122
+ end
123
+
124
+ self.class.elements.each do |element|
125
+ value = self.send(element.method_name)
126
+ has_one_and_has_many_to_xml(node, element, value) unless value.nil?
127
+ end
128
+
129
+ node
130
+ end
131
+
132
+ def to_xml
133
+ document = XML::Document.new
134
+ document.root = to_xml_node
135
+ document.to_s
136
+ end
137
+
138
+ private
139
+
140
+ def has_one_and_has_many_to_xml(node, element, value)
141
+ node << XML::Node.new(element.tag || element.name, value) and return unless element.options.include?(:single)
142
+
143
+ if element.options[:single]
144
+ node << value.to_xml_node
145
+ else
146
+ current_node = element.group_tag ? XML::Node.new(element.group_tag) : node;
147
+
148
+ value.each do |value_item|
149
+ child_node = value_item.to_xml_node
150
+ current_node << child_node if child_node.attributes? or child_node.children?
151
+ end
152
+
153
+ node << current_node if element.group_tag and (current_node.attributes? or current_node.children?)
154
+ end
155
+ end
156
+
157
+ end
158
+
159
+ require File.join(dir, 'happymapper/item')
160
+ require File.join(dir, 'happymapper/attribute')
161
+ require File.join(dir, 'happymapper/element')