acdc 0.2.5 → 0.5.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/README +20 -48
- data/Rakefile +6 -7
- data/lib/acdc/attribute.rb +1 -16
- data/lib/acdc/body.rb +6 -201
- data/lib/acdc/element.rb +2 -79
- data/lib/acdc/item.rb +144 -0
- data/lib/acdc/parse.rb +65 -0
- data/lib/acdc.rb +57 -23
- metadata +6 -14
data/README
CHANGED
@@ -9,22 +9,9 @@ This is a little XML-to-object-to-XML library that gets Dirty Deeds Done Dirt Ch
|
|
9
9
|
* Take XML string objects and convert them to real Ruby objects from your library
|
10
10
|
* Take real Ruby objects and convert them to XML strings
|
11
11
|
* Declare XML elements/attributes easily and with type enforcement
|
12
|
-
* Coerce objects to XML strings automatically (see JAIL_BREAK)
|
13
12
|
|
14
13
|
== Usage
|
15
14
|
|
16
|
-
=== Element
|
17
|
-
|
18
|
-
A basic XML element is created with the use of the following constructor
|
19
|
-
|
20
|
-
require 'acdc'
|
21
|
-
elem = Element("Hells Bells")
|
22
|
-
puts elem.acdc
|
23
|
-
=> "<Element>Hells Bells</Element>"
|
24
|
-
elem = Element("Hells Bells", {}, "BackInBlack")
|
25
|
-
puts elem.acdc
|
26
|
-
=> "<BackInBlack>Hells Bells</BackInBlack>"
|
27
|
-
|
28
15
|
=== It's A Long Way To The Top, If You Want To Rock n Roll
|
29
16
|
|
30
17
|
AcDc::Body assists you with declaring XML objects with ease. And #acdc makes
|
@@ -32,45 +19,30 @@ marshaling those objects from XML a breeze.
|
|
32
19
|
|
33
20
|
require 'acdc'
|
34
21
|
class TheJack < AcDc::Body
|
35
|
-
attribute :shes_got,
|
36
|
-
element :big_balls
|
22
|
+
attribute :shes_got, String
|
23
|
+
element :big_balls, String
|
37
24
|
end
|
38
|
-
rosie = TheJack.new(:big_balls => "I've got big balls")
|
39
|
-
puts rosie.big_balls
|
40
|
-
=> "I've got big balls"
|
41
|
-
puts rosie.acdc
|
42
|
-
=> "<TheJack shes_got="the jack"><BigBalls>I've got big balls</BigBalls></TheJack>"
|
43
|
-
who_made_who = acdc("<TheJack><BigBalls>Biggest Balls of them all</BigBalls></TheJack>")
|
44
|
-
puts who_made_who.class
|
45
|
-
=> TheJack
|
46
|
-
puts who_made_who.big_balls
|
47
|
-
=> "Biggest Balls of them all"
|
48
|
-
|
49
|
-
=== JAIL_BREAK
|
50
|
-
|
51
|
-
JAIL_BREAK will determine whether or not you need to explicitly coerce your
|
52
|
-
objects to XML using Element#acdc or Body#acdc. It's may not be the smartest
|
53
|
-
feature in the world, but we're gonna Ride On.
|
54
|
-
|
55
|
-
==== Without JAIL_BREAK
|
56
25
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
==== With JAIL_BREAK
|
65
|
-
|
66
|
-
JAIL_BREAK = true
|
67
|
-
require 'acdc'
|
68
|
-
XML_element = Element("TNT")
|
69
|
-
puts XML_element
|
70
|
-
=> "<Element>TNT</Element>"
|
26
|
+
jack = acdc("<thejack shes_got='big-balls'><big_balls>I've got big balls</big_balls></thejack>")
|
27
|
+
puts jack.shes_got
|
28
|
+
=> "big_balls"
|
29
|
+
puts jack.big_balls
|
30
|
+
=> "I've got big balls"
|
31
|
+
puts jack.acdc
|
32
|
+
=> "<?xml version='1.0' encoding='UTF-8'?><thejack shes_got='big-balls'><big_balls>I've got big balls</big_balls></thejack>"
|
71
33
|
|
72
34
|
== Contact
|
73
35
|
|
74
36
|
- Author:: Clint Hill clint.hill@h3osoftware.com
|
75
37
|
- Home Page:: http://h3osoftware.com/acdc
|
76
|
-
- GitHub:: git://github.com/clinth3o/acdc.git
|
38
|
+
- GitHub:: git://github.com/clinth3o/acdc.git
|
39
|
+
|
40
|
+
== Special Thanks
|
41
|
+
|
42
|
+
I want to thank John Nunemaker for his HappyMapper gem. I stole quite a bit
|
43
|
+
of code from that gem.
|
44
|
+
http://railstips.org/2008/11/17/happymapper-making-xml-fun-again
|
45
|
+
http://github.com/jnunemaker/happymapper/
|
46
|
+
|
47
|
+
And if you might ask why not just use his library? Well - that's the acdc part
|
48
|
+
of this story. He had the AC - I added the DC.
|
data/Rakefile
CHANGED
@@ -28,25 +28,24 @@ spec = Gem::Specification.new do |s|
|
|
28
28
|
"lib/acdc.rb",
|
29
29
|
"lib/acdc/attribute.rb",
|
30
30
|
"lib/acdc/body.rb",
|
31
|
-
"lib/acdc/element.rb"
|
31
|
+
"lib/acdc/element.rb",
|
32
|
+
"lib/acdc/item.rb",
|
33
|
+
"lib/acdc/parse.rb"
|
32
34
|
]
|
33
35
|
if s.respond_to? :specification_version then
|
34
36
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
35
37
|
s.specification_version = 3
|
36
38
|
|
37
39
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
38
|
-
s.add_runtime_dependency(%q<
|
40
|
+
s.add_runtime_dependency(%q<libxml-ruby>, [">= 1.1.3"])
|
39
41
|
s.add_runtime_dependency(%q<builder>, [">= 2.1.2"])
|
40
|
-
s.add_runtime_dependency(%q<hpricot>, [">= 0.8"])
|
41
42
|
else
|
42
|
-
s.add_dependency(%q<
|
43
|
+
s.add_dependency(%q<libxml-ruby>, [">= 1.1.3"])
|
43
44
|
s.add_dependency(%q<builder>, [">= 2.1.2"])
|
44
|
-
s.add_dependency(%q<hpricot>, [">= 0.8"])
|
45
45
|
end
|
46
46
|
else
|
47
|
-
s.add_dependency(%q<
|
47
|
+
s.add_dependency(%q<libxml-ruby>, [">= 1.1.3"])
|
48
48
|
s.add_dependency(%q<builder>, [">= 2.1.2"])
|
49
|
-
s.add_dependency(%q<hpricot>, [">= 0.8"])
|
50
49
|
end
|
51
50
|
end
|
52
51
|
|
data/lib/acdc/attribute.rb
CHANGED
@@ -1,20 +1,5 @@
|
|
1
1
|
module AcDc
|
2
|
-
|
3
|
-
# Attribute object used in Element and Body.
|
4
|
-
# Not often used outside of these.
|
5
|
-
class Attribute
|
6
|
-
|
7
|
-
attr_accessor :name, :value
|
8
|
-
|
9
|
-
def initialize(name,value)
|
10
|
-
@name = name
|
11
|
-
@value = value
|
12
|
-
end
|
13
|
-
|
14
|
-
# Returns the values of this attribute in hash form
|
15
|
-
def to_hash
|
16
|
-
{@name => @value}
|
17
|
-
end
|
2
|
+
class Attribute < Item
|
18
3
|
|
19
4
|
end
|
20
5
|
end
|
data/lib/acdc/body.rb
CHANGED
@@ -1,205 +1,10 @@
|
|
1
1
|
module AcDc
|
2
|
-
class Body
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
# Populates the attributes and elements declared for this object.
|
7
|
-
#@option values [Hash] :attributes Hash list of attributes to populate
|
8
|
-
#@example Filling the values and attributes
|
9
|
-
# class ThunderStruck < Body
|
10
|
-
# attribute :thunder
|
11
|
-
# element :lightning
|
12
|
-
# end
|
13
|
-
# kaboom = ThunderStruck.new({:attributes => {:thunder => "boom"}, :lightning => "crash"})
|
14
|
-
def initialize(values = {})
|
15
|
-
@attributes ||= {}
|
16
|
-
@elements ||= {}
|
17
|
-
@sequence = values[:sequence] || 0
|
18
|
-
# catch default values for attributes
|
19
|
-
unless self.class.declared_attributes.values.all?{|val| val.nil?}
|
20
|
-
self.class.declared_attributes.each do |key,val|
|
21
|
-
attributes.update(key => Attribute(key,val)) unless val.nil?
|
22
|
-
end
|
23
|
-
end
|
24
|
-
# now set initialized attribute values
|
25
|
-
if values.has_key?(:attributes)
|
26
|
-
values.delete(:attributes).each do |key,val|
|
27
|
-
if self.class.declared_attributes.has_key?(key)
|
28
|
-
attributes.update(key => Attribute(key,val))
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
# and finally set values
|
33
|
-
values.each do |key,val|
|
34
|
-
if self.class.declared_elements.has_key?(key)
|
35
|
-
type = options_for(key)[:type]
|
36
|
-
validate(type,key,val)
|
37
|
-
if type and type.ancestors.include?(Body)
|
38
|
-
elements.update(key => type.new(val.to_hash.merge(:sequence => options_for(key)[:sequence])))
|
39
|
-
elsif type
|
40
|
-
# if it's an Element we want the value (avoids recursive value)
|
41
|
-
value = (val.respond_to?(:value)) ? val.value : val
|
42
|
-
elements.update(key => type.new(value, options_for(key)))
|
43
|
-
else
|
44
|
-
elements.update(key => Element(val, options_for(key)))
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
2
|
+
class Body
|
3
|
+
def self.inherited(child)
|
4
|
+
child.instance_variable_set("@attributes", {})
|
5
|
+
child.instance_variable_set("@elements",{})
|
48
6
|
end
|
49
|
-
|
50
|
-
|
51
|
-
def acdc
|
52
|
-
xml = Builder::XmlMarkup.new
|
53
|
-
attrs = attributes.inject({}){|acc,attr| acc.update(attr[1].to_hash)}
|
54
|
-
xml.tag!(tag_name,attrs){ |body|
|
55
|
-
elements.sort{|a,b| a[1].sequence <=> b[1].sequence}.each do |key, elem|
|
56
|
-
body << elem.acdc
|
57
|
-
end
|
58
|
-
}
|
59
|
-
xml.target!
|
60
|
-
end
|
61
|
-
|
62
|
-
# Calls #acdc then matches
|
63
|
-
def match(pattern)
|
64
|
-
acdc.match(pattern)
|
65
|
-
end
|
66
|
-
|
67
|
-
def to_hash
|
68
|
-
elements
|
69
|
-
end
|
70
|
-
|
71
|
-
# The name to use for the tag
|
72
|
-
def tag_name
|
73
|
-
self.class.to_s.split("::").last
|
74
|
-
end
|
75
|
-
|
76
|
-
def method_missing(method_id, *args, &block)
|
77
|
-
key = method_id.to_s.gsub(/\=/,"").to_sym
|
78
|
-
if elements.has_key?(key) or attributes.has_key?(key)
|
79
|
-
(method_id.to_s.match(/\=$/)) ? write(method_id, *args, &block) : read(method_id)
|
80
|
-
else
|
81
|
-
super
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
class << self
|
86
|
-
def inherited(child)
|
87
|
-
child.instance_variable_set('@declared_elements', @declared_elements)
|
88
|
-
child.instance_variable_set('@declared_attributes', @declared_attributes)
|
89
|
-
child.instance_variable_set('@element_sequence', @element_sequence)
|
90
|
-
end
|
91
|
-
|
92
|
-
# Declare an Element for this Body
|
93
|
-
# Sequence of elements (XML Schema sequence) is taken care of by the order
|
94
|
-
# the elements are declared in the class definition.
|
95
|
-
#@param [Symbol] name A name to assign the Element (tag name)
|
96
|
-
#@param [Class] type A type to use for the element (use this for type enforcement)
|
97
|
-
#@option options [Boolean] :single False if object is a collection
|
98
|
-
#@option options [String] :tag String determining the name to use in the XML tag
|
99
|
-
def element(*options)
|
100
|
-
name = options.first
|
101
|
-
type = options.second || nil unless options.second.is_a?(Hash)
|
102
|
-
opts = options.extract_options!
|
103
|
-
opts.merge!(:tag => name) if opts[:tag].nil?
|
104
|
-
declared_elements.update(name => opts.merge(:type => type, :sequence => next_sequence))
|
105
|
-
end
|
106
|
-
|
107
|
-
# Declare an attribute for this Body
|
108
|
-
def attribute(name, value = nil)
|
109
|
-
declared_attributes.update(name => value)
|
110
|
-
end
|
111
|
-
|
112
|
-
# Returns the Hash list of Elements declared
|
113
|
-
def declared_elements
|
114
|
-
@elements ||= {}
|
115
|
-
@declared_elements ||= @elements[to_s] ||= {}
|
116
|
-
end
|
117
|
-
|
118
|
-
# Returns a Hash list of Attributes declared
|
119
|
-
def declared_attributes
|
120
|
-
@attributes ||= {}
|
121
|
-
@declared_attributes ||= @attributes[to_s] ||= {}
|
122
|
-
end
|
123
|
-
|
124
|
-
# Converts the XML to a Class object found in the library
|
125
|
-
def acdc(xml)
|
126
|
-
doc = Hpricot.XML(xml)
|
127
|
-
klass = doc.root.name.constantize
|
128
|
-
attributes = doc.root.attributes.inject({}){|acc,attr| acc.update(attr[0].to_sym => attr[1])}
|
129
|
-
values = doc.root.children.inject({}) do |acc, node|
|
130
|
-
name = node.name.underscore.to_sym
|
131
|
-
value = value_from_node(node)
|
132
|
-
attrs = node.attributes
|
133
|
-
acc.merge!({name => value, :attributes => attrs})
|
134
|
-
end
|
135
|
-
klass.new(values.merge(:attributes => attributes))
|
136
|
-
end
|
137
|
-
|
138
|
-
private
|
139
|
-
def value_from_node(node)
|
140
|
-
if node.respond_to?(:children) and node.children
|
141
|
-
values = node.children.collect do |child|
|
142
|
-
return child.inner_text if child.text?
|
143
|
-
instantiate(child)
|
144
|
-
end
|
145
|
-
(values.size == 1) ? values.first : values
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def instantiate(node)
|
150
|
-
name = node.name
|
151
|
-
attrs = node.attributes
|
152
|
-
klass = name.constantize
|
153
|
-
klass.new(value_from_node(node), :attributes => attrs)
|
154
|
-
end
|
155
|
-
|
156
|
-
def next_sequence
|
157
|
-
@element_sequence ||= 0
|
158
|
-
@element_sequence = @element_sequence +=1
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
private
|
163
|
-
|
164
|
-
def validate(type, key, val)
|
165
|
-
if type
|
166
|
-
if val.respond_to?(:each)
|
167
|
-
val.each {|v| raise ArgumentError.new("#{val.class} type is invalid. #{self.class} #{key} requires #{type}.") unless v.is_a?(type)}
|
168
|
-
else
|
169
|
-
unless val.is_a?(type)
|
170
|
-
raise ArgumentError.new("#{val.class} type is invalid. #{self.class} #{key} requires #{type}.")
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def options_for(key)
|
177
|
-
self.class.declared_elements[key]
|
178
|
-
end
|
179
|
-
|
180
|
-
def read(method_id)
|
181
|
-
if elements.has_key?(method_id)
|
182
|
-
elements[method_id]
|
183
|
-
else
|
184
|
-
attributes[method_id].value
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
def write(method_id, *args, &block)
|
189
|
-
key = method_id.to_s.gsub(/\=$/,"").to_sym
|
190
|
-
if elements.has_key?(key)
|
191
|
-
type = options_for(key)[:type]
|
192
|
-
if type and type.ancestors.include?(Body)
|
193
|
-
elements.update(key => type.new(args.first.to_hash, options_for(key)))
|
194
|
-
elsif type
|
195
|
-
elements.update(key => type.new(args.first, options_for(key)))
|
196
|
-
else
|
197
|
-
elements.update(key => Element(args.first, options_for(key)))
|
198
|
-
end
|
199
|
-
else
|
200
|
-
attributes.update(key => Attribute(key,args.first))
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
7
|
+
extend(ClassMethods)
|
8
|
+
extend(Parsing)
|
204
9
|
end
|
205
10
|
end
|
data/lib/acdc/element.rb
CHANGED
@@ -1,82 +1,5 @@
|
|
1
1
|
module AcDc
|
2
|
-
|
3
|
-
|
4
|
-
class Element
|
5
|
-
|
6
|
-
attr_accessor :value, :tag, :attributes, :options
|
7
|
-
|
8
|
-
# Constructor with the following:
|
9
|
-
#@param [Object] value Any value to place in the tags
|
10
|
-
#@option options [Boolean] :single False if object is a collection
|
11
|
-
#@option options [String] :tag A tag name to use if not Element
|
12
|
-
def initialize(value=nil, options={})
|
13
|
-
@tag = options[:tag] ||= self.class.to_s.split("::").last
|
14
|
-
@value = value
|
15
|
-
@options = options
|
16
|
-
@attributes = options.delete(:attributes)
|
17
|
-
end
|
18
|
-
|
19
|
-
# Converts the object to XML
|
20
|
-
def acdc
|
21
|
-
xml = Builder::XmlMarkup.new
|
22
|
-
if value.nil?
|
23
|
-
xml.tag!(tag_content)
|
24
|
-
else
|
25
|
-
has_many? ? render_many(xml) : xml.tag!(tag_content) {|elem| elem << content}
|
26
|
-
end
|
27
|
-
xml.target!
|
28
|
-
end
|
29
|
-
|
30
|
-
# Calls #acdc then matches
|
31
|
-
def match(pattern)
|
32
|
-
acdc.match(pattern)
|
33
|
-
end
|
34
|
-
|
35
|
-
# True if object has a collection of values
|
36
|
-
def has_many?
|
37
|
-
options.has_key?(:single) and !options[:single] and value.size > 1
|
38
|
-
end
|
39
|
-
|
40
|
-
# The name to use for the tag
|
41
|
-
def tag_name
|
42
|
-
tag.to_s
|
43
|
-
end
|
44
|
-
|
45
|
-
# Overridden to compare the values and not the whole object
|
46
|
-
def eql?(other)
|
47
|
-
return false if other.nil?
|
48
|
-
return false unless other.kind_of?(self.class)
|
49
|
-
value.eql?(other.value)
|
50
|
-
end
|
51
|
-
|
52
|
-
def sequence
|
53
|
-
@options[:sequence]
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
def tag_content
|
58
|
-
(attributes.nil? or attributes.empty?) ? tag_name : [tag_name,attributes]
|
59
|
-
end
|
60
|
-
|
61
|
-
def content
|
62
|
-
if has_many?
|
63
|
-
value.inject(""){|xml,val| xml << (val.is_a?(Element) ? val.acdc : val.to_s)}
|
64
|
-
else
|
65
|
-
value.respond_to?(:acdc) ? value.acdc : value.to_s
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def render_many(xml)
|
70
|
-
if value.respond_to?(:each)
|
71
|
-
xml.tag!(tag_content){|elem|
|
72
|
-
value.each{|val|
|
73
|
-
raise Exception.new("Can't render non-Element multiple times.") unless val.respond_to?(:acdc)
|
74
|
-
elem << val.acdc
|
75
|
-
}
|
76
|
-
}
|
77
|
-
else
|
78
|
-
xml.tag!(tag_content) {|elem| elem << content}
|
79
|
-
end
|
80
|
-
end
|
2
|
+
class Element < Item
|
3
|
+
|
81
4
|
end
|
82
5
|
end
|
data/lib/acdc/item.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
module AcDc
|
2
|
+
class Item
|
3
|
+
|
4
|
+
Types = [String, Float, Time, Date, DateTime, Integer, Boolean]
|
5
|
+
attr_accessor :name, :type, :tag, :options, :namespace
|
6
|
+
|
7
|
+
def initialize(name, type, options={})
|
8
|
+
@name = name.to_s
|
9
|
+
@type = type
|
10
|
+
@tag = options.delete(:tag) || name.to_s
|
11
|
+
@options = options
|
12
|
+
@xml_type = self.class.to_s.split('::').last.downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_name
|
16
|
+
@method_name ||= name.tr('-','_')
|
17
|
+
end
|
18
|
+
|
19
|
+
def constant
|
20
|
+
@constant ||= constantize(type)
|
21
|
+
end
|
22
|
+
|
23
|
+
def element?
|
24
|
+
@xml_type == 'element'
|
25
|
+
end
|
26
|
+
|
27
|
+
def attribute?
|
28
|
+
!element?
|
29
|
+
end
|
30
|
+
|
31
|
+
def value_from_xml(node, namespace)
|
32
|
+
if primitive?
|
33
|
+
find(node, namespace) do |n|
|
34
|
+
value = n.respond_to?(:content) ? n.content : n.to_s
|
35
|
+
typecast(value)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
constant.parse(node, options)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def primitive?
|
43
|
+
Types.include?(constant)
|
44
|
+
end
|
45
|
+
|
46
|
+
def xpath(namespace = self.namespace)
|
47
|
+
xpath = ''
|
48
|
+
xpath += "#{DEFAULT_NAMESPACE}:" if namespace
|
49
|
+
xpath += tag
|
50
|
+
xpath
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def constantize(type)
|
55
|
+
if type.is_a?(String)
|
56
|
+
names = type.split('::')
|
57
|
+
constant = Object
|
58
|
+
names.each do |name|
|
59
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
60
|
+
end
|
61
|
+
constant
|
62
|
+
else
|
63
|
+
type
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def find(node, namespace, &block)
|
68
|
+
if options[:namespace] == false
|
69
|
+
namespace = nil
|
70
|
+
elsif options[:namespace]
|
71
|
+
# from an element definition
|
72
|
+
namespace = "#{DEFAULT_NAMESPACE}:#{options[:namespace]}"
|
73
|
+
elsif self.namespace
|
74
|
+
# this node has a custom namespace (that is present in the doc)
|
75
|
+
namespace = "#{DEFAULT_NAMESPACE}:#{self.namespace}"
|
76
|
+
end
|
77
|
+
|
78
|
+
if element?
|
79
|
+
if(options[:single].nil? || options[:single])
|
80
|
+
result = node.find_first(xpath(namespace), namespace)
|
81
|
+
else
|
82
|
+
result = node.find(xpath(namespace))
|
83
|
+
end
|
84
|
+
|
85
|
+
if result
|
86
|
+
if(options[:single].nil? || options[:single])
|
87
|
+
value = yield(result)
|
88
|
+
else
|
89
|
+
value = []
|
90
|
+
result.each do |res|
|
91
|
+
value << yield(res)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
if options[:attributes].is_a?(Hash)
|
95
|
+
result.attributes.each do |xml_attribute|
|
96
|
+
if attribute_options = options[:attributes][xml_attribute.name.to_sym]
|
97
|
+
attribute_value = Attribute.new(xml_attribute.name.to_sym, *attribute_options).from_xml_node(result, namespace)
|
98
|
+
result.instance_eval <<-EOV
|
99
|
+
def value.#{xml_attribute.name}
|
100
|
+
#{attribute_value.inspect}
|
101
|
+
end
|
102
|
+
EOV
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
value
|
107
|
+
else
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
else
|
111
|
+
yield(node[tag])
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def typecast(value)
|
116
|
+
return value if value.kind_of?(constant) || value.nil?
|
117
|
+
begin
|
118
|
+
if constant == String then value.to_s
|
119
|
+
elsif constant == Float then value.to_f
|
120
|
+
elsif constant == Time then Time.parse(value.to_s)
|
121
|
+
elsif constant == Date then Date.parse(value.to_s)
|
122
|
+
elsif constant == DateTime then DateTime.parse(value.to_s)
|
123
|
+
elsif constant == Boolean then ['true', 't', '1'].include?(value.to_s.downcase)
|
124
|
+
elsif constant == Integer
|
125
|
+
value_to_i = value.to_i
|
126
|
+
if value_to_i == 0 && value != '0'
|
127
|
+
value_to_s = value.to_s
|
128
|
+
begin
|
129
|
+
Integer(value_to_s =~ /^(\d+)/ ? $1 : value_to_s)
|
130
|
+
rescue ArgumentError
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
else
|
134
|
+
value_to_i
|
135
|
+
end
|
136
|
+
else
|
137
|
+
value
|
138
|
+
end
|
139
|
+
rescue
|
140
|
+
value
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
data/lib/acdc/parse.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module AcDc
|
2
|
+
module Parsing
|
3
|
+
|
4
|
+
def acdc(xml, options={})
|
5
|
+
|
6
|
+
if xml.is_a?(XML::Node)
|
7
|
+
node = xml
|
8
|
+
else
|
9
|
+
if xml.is_a?(XML::Document)
|
10
|
+
node = xml.root
|
11
|
+
else
|
12
|
+
node = XML::Parser.string(xml).parse.root
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
klass = constantize(node.name)
|
17
|
+
|
18
|
+
root = node.name.downcase == klass.tag_name
|
19
|
+
|
20
|
+
namespace = node.namespaces.default
|
21
|
+
namespace = "#{DEFAULT_NAMESPACE}:#{namespace}" if namespace
|
22
|
+
|
23
|
+
xpath = root ? '/' : './/'
|
24
|
+
xpath += "#{DEFAULT_NAMESPACE}:" if namespace
|
25
|
+
xpath += node.name
|
26
|
+
|
27
|
+
nodes = node.find(xpath, Array(namespace))
|
28
|
+
|
29
|
+
collection = nodes.collect do |n|
|
30
|
+
obj = klass.new
|
31
|
+
klass.attributes.each do |attr|
|
32
|
+
obj.send("#{attr.method_name}=", attr.value_from_xml(n, namespace))
|
33
|
+
end
|
34
|
+
klass.elements.each do |elem|
|
35
|
+
obj.send("#{elem.method_name}=", elem.value_from_xml(n, namespace))
|
36
|
+
end
|
37
|
+
obj
|
38
|
+
end
|
39
|
+
|
40
|
+
nodes = nil
|
41
|
+
|
42
|
+
if options[:single] || root
|
43
|
+
collection.first
|
44
|
+
else
|
45
|
+
collection
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def constantize(type)
|
52
|
+
if type.is_a?(String)
|
53
|
+
names = type.split('::')
|
54
|
+
constant = Object
|
55
|
+
names.each do |name|
|
56
|
+
constant = const_defined?(name) ? const_get(name) : const_missing(name)
|
57
|
+
end
|
58
|
+
constant
|
59
|
+
else
|
60
|
+
type
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
data/lib/acdc.rb
CHANGED
@@ -1,35 +1,69 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'time'
|
1
3
|
require 'rubygems'
|
4
|
+
gem 'libxml-ruby', '= 1.1.3'
|
5
|
+
require 'xml'
|
6
|
+
gem 'builder'
|
2
7
|
require 'builder'
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
require File.join(File.dirname(__FILE__),"acdc","attribute")
|
7
|
-
require File.join(File.dirname(__FILE__),"acdc","element")
|
8
|
-
require File.join(File.dirname(__FILE__),"acdc","body")
|
8
|
+
|
9
|
+
class Boolean; end
|
9
10
|
|
10
11
|
module AcDc
|
11
12
|
|
12
|
-
|
13
|
+
DEFAULT_NAMESPACE = "example" unless defined?(AcDc::DEFAULT_NAMESPACE)
|
14
|
+
VERSION = [0,5,0] unless defined?(AcDc::VERSION)
|
13
15
|
|
14
16
|
if defined?(JAIL_BREAK)
|
15
|
-
|
16
|
-
Body.class_eval{ alias :to_s :acdc }
|
17
|
+
puts "AcDc is live -- Dirty Deeds!"
|
17
18
|
end
|
18
|
-
|
19
|
-
end
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
def self.included(base)
|
21
|
+
base.instance_variable_set("@attributes",{})
|
22
|
+
base.instance_variable_set("@elements",{})
|
23
|
+
base.extend(ClassMethods)
|
24
|
+
base.extend(Parsing)
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
|
29
|
+
def attributes
|
30
|
+
@attributes[to_s] || []
|
31
|
+
end
|
25
32
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
33
|
+
def elements
|
34
|
+
@elements[to_s] || []
|
35
|
+
end
|
36
|
+
|
37
|
+
def attribute(name, type, options={})
|
38
|
+
attribute = Attribute.new(name,type,options)
|
39
|
+
@attributes[to_s] ||= []
|
40
|
+
@attributes[to_s] << attribute
|
41
|
+
attr_accessor attribute.method_name.intern
|
42
|
+
end
|
43
|
+
|
44
|
+
def element(name, type, options={})
|
45
|
+
element = Element.new(name,type,options)
|
46
|
+
@elements[to_s] ||= []
|
47
|
+
@elements[to_s] << element
|
48
|
+
attr_accessor element.method_name.intern
|
49
|
+
end
|
50
|
+
|
51
|
+
def tag_name(name = nil)
|
52
|
+
@tag_name = name.to_s if name
|
53
|
+
@tag_name ||= to_s.split('::')[-1].downcase
|
54
|
+
end
|
30
55
|
|
31
|
-
|
32
|
-
|
33
|
-
|
56
|
+
def namespace(namespace = nil)
|
57
|
+
@namespace = namespace if namespace
|
58
|
+
@namespace
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
34
63
|
end
|
35
|
-
|
64
|
+
require File.join(File.dirname(__FILE__), 'acdc/build')
|
65
|
+
require File.join(File.dirname(__FILE__), 'acdc/parse')
|
66
|
+
require File.join(File.dirname(__FILE__), 'acdc/item')
|
67
|
+
require File.join(File.dirname(__FILE__), 'acdc/attribute')
|
68
|
+
require File.join(File.dirname(__FILE__), 'acdc/element')
|
69
|
+
require File.join(File.dirname(__FILE__), 'acdc/body')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acdc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Clint Hill
|
@@ -9,18 +9,18 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-11-18 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
16
|
+
name: libxml-ruby
|
17
17
|
type: :runtime
|
18
18
|
version_requirement:
|
19
19
|
version_requirements: !ruby/object:Gem::Requirement
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version:
|
23
|
+
version: 1.1.3
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: builder
|
@@ -32,16 +32,6 @@ dependencies:
|
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 2.1.2
|
34
34
|
version:
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: hpricot
|
37
|
-
type: :runtime
|
38
|
-
version_requirement:
|
39
|
-
version_requirements: !ruby/object:Gem::Requirement
|
40
|
-
requirements:
|
41
|
-
- - ">="
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: "0.8"
|
44
|
-
version:
|
45
35
|
description: " This is a little xml-to-object-to-xml library that gets Dirty Deeds Done Dirt Cheap. \n"
|
46
36
|
email: clint.hill@h3osoftware.com
|
47
37
|
executables: []
|
@@ -58,6 +48,8 @@ files:
|
|
58
48
|
- lib/acdc/attribute.rb
|
59
49
|
- lib/acdc/body.rb
|
60
50
|
- lib/acdc/element.rb
|
51
|
+
- lib/acdc/item.rb
|
52
|
+
- lib/acdc/parse.rb
|
61
53
|
has_rdoc: true
|
62
54
|
homepage: http://h3osoftware.com/acdc
|
63
55
|
licenses: []
|