legolin-happymapper 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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')