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.
- data/HOW_TO_RELEASE +5 -0
- data/History +59 -0
- data/License +20 -0
- data/Manifest +42 -0
- data/README +61 -0
- data/Rakefile +43 -0
- data/TODO +0 -0
- data/examples/amazon.rb +34 -0
- data/examples/current_weather.rb +21 -0
- data/examples/dashed_elements.rb +20 -0
- data/examples/multi_street_address.rb +15 -0
- data/examples/post.rb +19 -0
- data/examples/twitter.rb +37 -0
- data/happymapper.gemspec +0 -0
- data/legolin-happymapper.gemspec +34 -0
- data/lib/happymapper.rb +161 -0
- data/lib/happymapper/attribute.rb +3 -0
- data/lib/happymapper/element.rb +3 -0
- data/lib/happymapper/item.rb +192 -0
- data/lib/happymapper/version.rb +3 -0
- data/spec/fixtures/address.xml +8 -0
- data/spec/fixtures/analytics.xml +61 -0
- data/spec/fixtures/commit.xml +52 -0
- data/spec/fixtures/current_weather.xml +89 -0
- data/spec/fixtures/family_tree.xml +7 -0
- data/spec/fixtures/multi_street_address.xml +9 -0
- data/spec/fixtures/multiple_namespaces.xml +170 -0
- data/spec/fixtures/nested_namespaces.xml +17 -0
- data/spec/fixtures/pita.xml +133 -0
- data/spec/fixtures/posts.xml +23 -0
- data/spec/fixtures/product_default_namespace.xml +10 -0
- data/spec/fixtures/product_no_namespace.xml +10 -0
- data/spec/fixtures/product_single_namespace.xml +10 -0
- data/spec/fixtures/radar.xml +21 -0
- data/spec/fixtures/statuses.xml +422 -0
- data/spec/happymapper_attribute_spec.rb +17 -0
- data/spec/happymapper_element_spec.rb +17 -0
- data/spec/happymapper_item_spec.rb +115 -0
- data/spec/happymapper_spec.rb +719 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +13 -0
- data/website/css/common.css +47 -0
- data/website/index.html +98 -0
- metadata +129 -0
data/HOW_TO_RELEASE
ADDED
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.
|
data/Manifest
ADDED
@@ -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
|
data/Rakefile
ADDED
@@ -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
|
data/examples/amazon.rb
ADDED
@@ -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
|
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, '' }
|
data/examples/twitter.rb
ADDED
@@ -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
|
data/happymapper.gemspec
ADDED
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
|
data/lib/happymapper.rb
ADDED
@@ -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')
|