kdonovan-happymapper 0.3.4
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 +77 -0
- data/License +20 -0
- data/Manifest +40 -0
- data/README +10 -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/family_tree.rb +55 -0
- data/examples/post.rb +19 -0
- data/examples/twitter.rb +37 -0
- data/happymapper.gemspec +35 -0
- data/lib/happymapper/attribute.rb +3 -0
- data/lib/happymapper/element.rb +3 -0
- data/lib/happymapper/item.rb +175 -0
- data/lib/happymapper/version.rb +3 -0
- data/lib/happymapper.rb +220 -0
- data/spec/fixtures/address.xml +8 -0
- data/spec/fixtures/commit.xml +52 -0
- data/spec/fixtures/current_weather.xml +89 -0
- data/spec/fixtures/family_tree.xml +23 -0
- data/spec/fixtures/multiple_namespaces.xml +170 -0
- data/spec/fixtures/partial_posts.xml +5 -0
- data/spec/fixtures/pita.xml +133 -0
- data/spec/fixtures/posts.xml +23 -0
- data/spec/fixtures/product_default_namespace.xml +17 -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 +94 -0
- data/spec/happymapper_spec.rb +694 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/xml_helper.rb +115 -0
- data/website/css/common.css +47 -0
- data/website/index.html +98 -0
- metadata +113 -0
data/History
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
== 0.3.4
|
2
|
+
* 1 major enhancement, 1 minor enhancement
|
3
|
+
* Allow Marshaling HappyMapper objects
|
4
|
+
* Store raw xml when parsing objects (to_xml doesn't always retain same attributes)
|
5
|
+
|
6
|
+
== 0.3.3
|
7
|
+
* 1 bug fix 2 minor enhancements
|
8
|
+
* Don't serialize nil elements of primitive type (jimmyz)
|
9
|
+
* Added the xml version/encoding header to serialized xml string on to_xml (jimmyz)
|
10
|
+
* Bug fix: Don't parse deep on non-primitive elements unless :deep => true (jimmyz)
|
11
|
+
|
12
|
+
== 0.3.2
|
13
|
+
* 1 bug fix
|
14
|
+
* to_xml_node was blowing up if a non-primitive element was nil. Fixed (jimmyz)
|
15
|
+
|
16
|
+
== 0.3.1
|
17
|
+
* 1 minor tweak
|
18
|
+
* Added to_xml and namespace_url code to the family_tree.rb example
|
19
|
+
|
20
|
+
== 0.3.0
|
21
|
+
* 5 major enhancements, 2 minor enhancements, 1 bug fixes
|
22
|
+
* to_xml methods attach namespaces to the root element and add the namespaces to the elements (if a namespace_url is specified)
|
23
|
+
* Modified namespace method to accept a hash {'prefix' => 'http://example.com/v1'} OR 'prefix'
|
24
|
+
* Added namespace_url method to set and read a full namespace URL. This adds much better stability in case prefixes change.
|
25
|
+
* Added to_xml method to HappyMapper Module to serialize objects to string
|
26
|
+
* Added to_xml_node method to HappyMapper Module to serialize objects to LibXML::XML::Node
|
27
|
+
* Full support for creating happymapper elements from scratch. has_many instance vars default to []
|
28
|
+
* Support for has_many with a primitive type (String, Boolean, etc.)
|
29
|
+
* fix for issue #8: http://jnunemaker.lighthouseapp.com/projects/20014-happy-mapper/tickets/8
|
30
|
+
|
31
|
+
== 0.2.2
|
32
|
+
* 2 minor tweaks
|
33
|
+
* removed GC.start (libxml recommended this) as setting nodes to nil should be enough, specs run 3-4x faster (Brandon Keepers)
|
34
|
+
* renamed get_tag_name to tag_name (Brandon Keepers)
|
35
|
+
* removed libxml helpers as they are no longer needed
|
36
|
+
|
37
|
+
== 0.2.1
|
38
|
+
* 1 minor fix, 3 major enhancements
|
39
|
+
* fixed warnings about using XML::Parser (mojodna)
|
40
|
+
* Improved namespace support, now handles multiple namespaces and allows namespaces to be set item wide or on a per element basis (mojodna)
|
41
|
+
* Auto detect root nodes (mojodna)
|
42
|
+
* Type coercion (mojodna)
|
43
|
+
|
44
|
+
== 0.2.0
|
45
|
+
* 1 major enhancement, 2 minor ehancements
|
46
|
+
* Automatic handling of namespaces (part by Robert Lowrey and rest by John Nunemaker)
|
47
|
+
* 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
|
48
|
+
* Now defaulting tag names for classes in modules to last constant downcased
|
49
|
+
|
50
|
+
== 0.1.7 2009-01-29
|
51
|
+
* 1 minor enhancement
|
52
|
+
* Support dashes in elements (Josh Nichols)
|
53
|
+
|
54
|
+
== 0.1.6 2009-01-17
|
55
|
+
* 1 minor enhancement:
|
56
|
+
* added support for nested collection elements (Justin Marney)
|
57
|
+
|
58
|
+
== 0.1.5 2009-01-05
|
59
|
+
* 1 major enhancement:
|
60
|
+
* Updated to latest version of libxml-ruby (lightningdb)
|
61
|
+
|
62
|
+
== 0.1.4 2009-01-05
|
63
|
+
* 1 major enhancement:
|
64
|
+
* Fixed parsing when the object is the root node. (Garret Alfert)
|
65
|
+
|
66
|
+
== 0.1.3 2008-12-31
|
67
|
+
* 1 major enhancement:
|
68
|
+
* Added parsing of attributes of elements that are also mapped, see current_weather.rb for example (jeremyf)
|
69
|
+
|
70
|
+
== 0.1.2 2008-12-12
|
71
|
+
* 1 major enhancement:
|
72
|
+
* Fixed that :deep only worked for first item (dvrensk)
|
73
|
+
|
74
|
+
== 0.1.0 2008-11-16
|
75
|
+
|
76
|
+
* 1 major enhancement:
|
77
|
+
* 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,10 @@
|
|
1
|
+
= happymapper
|
2
|
+
|
3
|
+
== DESCRIPTION:
|
4
|
+
|
5
|
+
An extension of jimmyz-happymapper (which adds to_xml to happymapper) adding in the ability to Marshal happymapper classes.
|
6
|
+
|
7
|
+
Parents:
|
8
|
+
* http://github.com/jimmyz/happymapper/tree/master
|
9
|
+
* http://github.com/jnunemaker/happymapper/tree/master
|
10
|
+
|
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
|
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,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, '' }
|
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
@@ -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.4"
|
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-21}
|
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,175 @@
|
|
1
|
+
module HappyMapper
|
2
|
+
class Item
|
3
|
+
attr_accessor :name, :type, :tag, :options, :namespace
|
4
|
+
|
5
|
+
Types = [String, Float, Time, Date, DateTime, Integer, Boolean]
|
6
|
+
|
7
|
+
# options:
|
8
|
+
# :deep => Boolean False to only parse element's children, True to include
|
9
|
+
# grandchildren and all others down the chain (// in expath)
|
10
|
+
# :namespace => String Element's namespace if it's not the global or inherited
|
11
|
+
# default
|
12
|
+
# :parser => Symbol Class method to use for type coercion.
|
13
|
+
# :raw => Boolean Use raw node value (inc. tags) when parsing.
|
14
|
+
# :single => Boolean False if object should be collection, True for single object
|
15
|
+
# :tag => String Element name if it doesn't match the specified name.
|
16
|
+
def initialize(name, type, o={})
|
17
|
+
self.name = name.to_s
|
18
|
+
self.type = type
|
19
|
+
self.tag = o.delete(:tag) || name.to_s
|
20
|
+
self.namespace = o.delete(:namespace)
|
21
|
+
self.options = {:single => true }.merge o
|
22
|
+
|
23
|
+
@xml_type = self.class.to_s.split('::').last.downcase
|
24
|
+
end
|
25
|
+
|
26
|
+
def from_xml_node(node, namespace)
|
27
|
+
if primitive?
|
28
|
+
find(node, namespace) do |n|
|
29
|
+
if n.respond_to?(:content)
|
30
|
+
typecast(n.content)
|
31
|
+
else
|
32
|
+
typecast(n.to_s)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
else
|
36
|
+
if options[:parser]
|
37
|
+
find(node, namespace) do |n|
|
38
|
+
if n.respond_to?(:content) && !options[:raw]
|
39
|
+
value = n.content
|
40
|
+
else
|
41
|
+
value = n.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
begin
|
45
|
+
type.send(options[:parser].to_sym, value)
|
46
|
+
rescue
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
else
|
51
|
+
type.parse(node, options)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_xml_node(value, root_node = nil)
|
57
|
+
if primitive?
|
58
|
+
node = XML::Node.new(@tag)
|
59
|
+
node << value.to_s
|
60
|
+
# assign a namespace
|
61
|
+
if @namespace && root_node
|
62
|
+
namespace_object = root_node.namespaces.find_by_prefix @namespace
|
63
|
+
node.namespaces.namespace = namespace_object
|
64
|
+
end
|
65
|
+
node
|
66
|
+
else
|
67
|
+
value.to_xml_node(root_node) unless value.nil?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def xpath(namespace = self.namespace)
|
72
|
+
xpath = ''
|
73
|
+
xpath += './/' if options[:deep]
|
74
|
+
xpath += "#{namespace}:" if namespace
|
75
|
+
xpath += tag
|
76
|
+
# puts "xpath: #{xpath}"
|
77
|
+
xpath
|
78
|
+
end
|
79
|
+
|
80
|
+
def primitive?
|
81
|
+
Types.include?(type)
|
82
|
+
end
|
83
|
+
|
84
|
+
def element?
|
85
|
+
@xml_type == 'element'
|
86
|
+
end
|
87
|
+
|
88
|
+
def attribute?
|
89
|
+
!element?
|
90
|
+
end
|
91
|
+
|
92
|
+
def method_name
|
93
|
+
@method_name ||= name.tr('-', '_')
|
94
|
+
end
|
95
|
+
|
96
|
+
def typecast(value)
|
97
|
+
return value if value.kind_of?(type) || value.nil?
|
98
|
+
begin
|
99
|
+
if type == String then value.to_s
|
100
|
+
elsif type == Float then value.to_f
|
101
|
+
elsif type == Time then Time.parse(value.to_s)
|
102
|
+
elsif type == Date then Date.parse(value.to_s)
|
103
|
+
elsif type == DateTime then DateTime.parse(value.to_s)
|
104
|
+
elsif type == Boolean then ['true', 't', '1'].include?(value.to_s.downcase)
|
105
|
+
elsif type == Integer
|
106
|
+
# ganked from datamapper
|
107
|
+
value_to_i = value.to_i
|
108
|
+
if value_to_i == 0 && value != '0'
|
109
|
+
value_to_s = value.to_s
|
110
|
+
begin
|
111
|
+
Integer(value_to_s =~ /^(\d+)/ ? $1 : value_to_s)
|
112
|
+
rescue ArgumentError
|
113
|
+
nil
|
114
|
+
end
|
115
|
+
else
|
116
|
+
value_to_i
|
117
|
+
end
|
118
|
+
else
|
119
|
+
value
|
120
|
+
end
|
121
|
+
rescue
|
122
|
+
value
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
def find(node, namespace, &block)
|
128
|
+
# this node has a custom namespace (that is present in the doc)
|
129
|
+
if self.namespace && node.namespaces.find_by_prefix(self.namespace)
|
130
|
+
# from the class definition
|
131
|
+
namespace = self.namespace
|
132
|
+
elsif options[:namespace] && node.namespaces.find_by_prefix(options[:namespace])
|
133
|
+
# from an element definition
|
134
|
+
namespace = options[:namespace]
|
135
|
+
end
|
136
|
+
|
137
|
+
if element?
|
138
|
+
if options[:single]
|
139
|
+
result = node.find_first(xpath(namespace))
|
140
|
+
if result
|
141
|
+
value = yield(result)
|
142
|
+
handle_attributes_option(result,value)
|
143
|
+
value
|
144
|
+
else
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
else
|
148
|
+
results = node.find(xpath(namespace)).collect do |result|
|
149
|
+
value = yield(result)
|
150
|
+
handle_attributes_option(result,value)
|
151
|
+
value
|
152
|
+
end
|
153
|
+
results
|
154
|
+
end
|
155
|
+
else
|
156
|
+
yield(node[tag]) unless node[tag].nil?
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def handle_attributes_option(result, value)
|
161
|
+
if options[:attributes].is_a?(Hash)
|
162
|
+
result.attributes.each do |xml_attribute|
|
163
|
+
if attribute_options = options[:attributes][xml_attribute.name.to_sym]
|
164
|
+
attribute_value = Attribute.new(xml_attribute.name.to_sym, *attribute_options).from_xml_node(result, namespace)
|
165
|
+
result.instance_eval <<-EOV
|
166
|
+
def value.#{xml_attribute.name}
|
167
|
+
#{attribute_value.inspect}
|
168
|
+
end
|
169
|
+
EOV
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|