-
Notifications
You must be signed in to change notification settings - Fork 111
/
happymapper.rb
117 lines (93 loc) · 2.78 KB
/
happymapper.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
require 'rubygems'
gem 'libxml-ruby', '=1.1.3'
require 'date'
require 'time'
require 'xml'
class Boolean; end
module HappyMapper
DEFAULT_NS = "happymapper"
def self.included(base)
base.instance_variable_set("@attributes", {})
base.instance_variable_set("@elements", {})
base.extend ClassMethods
end
module ClassMethods
def attribute(name, type, options={})
attribute = Attribute.new(name, type, options)
@attributes[to_s] ||= []
@attributes[to_s] << attribute
attr_accessor attribute.method_name.intern
end
def attributes
@attributes[to_s] || []
end
def element(name, type, options={})
element = Element.new(name, type, options)
@elements[to_s] ||= []
@elements[to_s] << element
attr_accessor element.method_name.intern
end
def elements
@elements[to_s] || []
end
def has_one(name, type, options={})
element name, type, {:single => true}.merge(options)
end
def has_many(name, type, options={})
element name, type, {:single => false}.merge(options)
end
# Specify a namespace if a node and all its children are all namespaced
# elements. This is simpler than passing the :namespace option to each
# defined element.
def namespace(namespace = nil)
@namespace = namespace if namespace
@namespace
end
def tag(new_tag_name)
@tag_name = new_tag_name.to_s
end
def tag_name
@tag_name ||= to_s.split('::')[-1].downcase
end
def parse(xml, options = {})
if xml.is_a?(XML::Node)
node = xml
else
if xml.is_a?(XML::Document)
node = xml.root
else
node = XML::Parser.string(xml).parse.root
end
root = node.name == tag_name
end
namespace = @namespace || (node.namespaces && node.namespaces.default)
namespace = "#{DEFAULT_NS}:#{namespace}" if namespace
xpath = root ? '/' : './/'
xpath += "#{DEFAULT_NS}:" if namespace
xpath += tag_name
nodes = node.find(xpath, Array(namespace))
collection = nodes.collect do |n|
obj = new
attributes.each do |attr|
obj.send("#{attr.method_name}=",
attr.from_xml_node(n, namespace))
end
elements.each do |elem|
obj.send("#{elem.method_name}=",
elem.from_xml_node(n, namespace))
end
obj
end
# per http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354
nodes = nil
if options[:single] || root
collection.first
else
collection
end
end
end
end
require 'happymapper/item'
require 'happymapper/attribute'
require 'happymapper/element'