acdc 0.2.2
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/LICENSE +20 -0
- data/README +76 -0
- data/Rakefile +201 -0
- data/lib/acdc.rb +35 -0
- data/lib/acdc/attribute.rb +20 -0
- data/lib/acdc/body.rb +190 -0
- data/lib/acdc/element.rb +82 -0
- metadata +90 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008-2009 Clint Hill - h3o(software)
|
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/README
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
= AC/DC - h3o(software)
|
2
|
+
|
3
|
+
== For Those About To Rock
|
4
|
+
|
5
|
+
This is a little XML-to-object-to-XML library that gets Dirty Deeds Done Dirt Cheap.
|
6
|
+
|
7
|
+
== Features
|
8
|
+
|
9
|
+
* Take XML string objects and convert them to real Ruby objects from your library
|
10
|
+
* Take real Ruby objects and convert them to XML strings
|
11
|
+
* Declare XML elements/attributes easily and with type enforcement
|
12
|
+
* Coerce objects to XML strings automatically (see JAIL_BREAK)
|
13
|
+
|
14
|
+
== Usage
|
15
|
+
|
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
|
+
=== It's A Long Way To The Top, If You Want To Rock n Roll
|
29
|
+
|
30
|
+
AcDc::Body assists you with declaring XML objects with ease. And #acdc makes
|
31
|
+
marshaling those objects from XML a breeze.
|
32
|
+
|
33
|
+
require 'acdc'
|
34
|
+
class TheJack < AcDc::Body
|
35
|
+
attribute :shes_got, "the jack"
|
36
|
+
element :big_balls
|
37
|
+
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
|
+
|
57
|
+
require 'acdc'
|
58
|
+
XML_element = Element("TNT")
|
59
|
+
puts XML_element
|
60
|
+
=> #<AcDc::Element:>
|
61
|
+
puts XML_element.acdc
|
62
|
+
=> "<Element>TNT</Element>"
|
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>"
|
71
|
+
|
72
|
+
== Contact
|
73
|
+
|
74
|
+
- Author:: Clint Hill clint.hill@h3osoftware.com
|
75
|
+
- Home Page:: http://h3osoftware.com/acdc
|
76
|
+
- GitHub:: git://github.com/clinth3o/acdc.git
|
data/Rakefile
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'spec/rake/spectask'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'yard'
|
7
|
+
include FileUtils
|
8
|
+
require File.join(File.dirname(__FILE__),"lib","acdc")
|
9
|
+
include AcDc
|
10
|
+
|
11
|
+
spec = Gem::Specification.new do |s|
|
12
|
+
s.name = "acdc"
|
13
|
+
s.version = AcDc::VERSION.join(".")
|
14
|
+
s.platform = Gem::Platform::RUBY
|
15
|
+
s.author = "Clint Hill"
|
16
|
+
s.email = "clint.hill@h3osoftware.com"
|
17
|
+
s.homepage = "http://h3osoftware.com/acdc"
|
18
|
+
s.summary = "AC/DC by h3o(software)"
|
19
|
+
s.description = <<-EOF
|
20
|
+
This is a little xml-to-object-to-xml library that gets Dirty Deeds Done Dirt Cheap.
|
21
|
+
EOF
|
22
|
+
s.rubyforge_project = "acdc"
|
23
|
+
s.require_path = "lib"
|
24
|
+
s.files = [
|
25
|
+
"LICENSE",
|
26
|
+
"README",
|
27
|
+
"Rakefile",
|
28
|
+
"lib/acdc.rb",
|
29
|
+
"lib/acdc/attribute.rb",
|
30
|
+
"lib/acdc/body.rb",
|
31
|
+
"lib/acdc/element.rb"
|
32
|
+
]
|
33
|
+
if s.respond_to? :specification_version then
|
34
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
35
|
+
s.specification_version = 3
|
36
|
+
|
37
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
38
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 2.3.2"])
|
39
|
+
s.add_runtime_dependency(%q<builder>, [">= 2.1.2"])
|
40
|
+
s.add_runtime_dependency(%q<hpricot>, [">= 0.8"])
|
41
|
+
else
|
42
|
+
s.add_dependency(%q<activesupport>, [">= 2.3.2"])
|
43
|
+
s.add_dependency(%q<builder>, [">= 2.1.2"])
|
44
|
+
s.add_dependency(%q<hpricot>, [">= 0.8"])
|
45
|
+
end
|
46
|
+
else
|
47
|
+
s.add_dependency(%q<activesupport>, [">= 2.3.2"])
|
48
|
+
s.add_dependency(%q<builder>, [">= 2.1.2"])
|
49
|
+
s.add_dependency(%q<hpricot>, [">= 0.8"])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Rake::GemPackageTask.new(spec) do |package|
|
54
|
+
package.gem_spec = spec
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
##############################################################################
|
60
|
+
# rSpec
|
61
|
+
##############################################################################
|
62
|
+
desc 'Run all specs and rcov'
|
63
|
+
task :spec => ["spec:default"]
|
64
|
+
namespace :spec do
|
65
|
+
Spec::Rake::SpecTask.new('default') do |t|
|
66
|
+
t.spec_opts = ["--format", "specdoc", "--colour"]
|
67
|
+
t.spec_files = Dir['spec/**/*_spec.rb'].sort
|
68
|
+
t.libs = ['lib','lib/acdc']
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
##############################################################################
|
73
|
+
# Documentation
|
74
|
+
##############################################################################
|
75
|
+
task :doc => ["doc:yardoc"]
|
76
|
+
namespace :doc do
|
77
|
+
YARD::Rake::YardocTask.new do |t|
|
78
|
+
t.options = ['-odoc/yardoc', '-rREADME', '-mtextile'] # optional
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
#############################################################################
|
83
|
+
# Stats
|
84
|
+
#############################################################################
|
85
|
+
STATS_DIRECTORIES = [
|
86
|
+
%w(AcDc lib/acdc),
|
87
|
+
%w(Specs spec)
|
88
|
+
].collect { |name, dir| [ name, "#{Dir.pwd}/#{dir}" ] }.select { |name, dir| File.directory?(dir) }
|
89
|
+
|
90
|
+
desc "Report code statistics (KLOCs, etc) from the application"
|
91
|
+
task :stats do
|
92
|
+
CodeStatistics.new(*STATS_DIRECTORIES).to_s
|
93
|
+
end
|
94
|
+
|
95
|
+
class CodeStatistics #:nodoc:
|
96
|
+
|
97
|
+
TEST_TYPES = %w(Specs)
|
98
|
+
|
99
|
+
def initialize(*pairs)
|
100
|
+
@pairs = pairs
|
101
|
+
@statistics = calculate_statistics
|
102
|
+
@total = calculate_total if pairs.length > 1
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_s
|
106
|
+
print_header
|
107
|
+
@pairs.each { |pair| print_line(pair.first, @statistics[pair.first]) }
|
108
|
+
print_splitter
|
109
|
+
|
110
|
+
if @total
|
111
|
+
print_line("Total", @total)
|
112
|
+
print_splitter
|
113
|
+
end
|
114
|
+
|
115
|
+
print_code_test_stats
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
def calculate_statistics
|
120
|
+
@pairs.inject({}) { |stats, pair| stats[pair.first] = calculate_directory_statistics(pair.last); stats }
|
121
|
+
end
|
122
|
+
|
123
|
+
def calculate_directory_statistics(directory, pattern = /.*\.rb$/)
|
124
|
+
stats = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
|
125
|
+
|
126
|
+
Dir.foreach(directory) do |file_name|
|
127
|
+
if File.stat(directory + "/" + file_name).directory? and (/^\./ !~ file_name)
|
128
|
+
newstats = calculate_directory_statistics(directory + "/" + file_name, pattern)
|
129
|
+
stats.each { |k, v| stats[k] += newstats[k] }
|
130
|
+
end
|
131
|
+
|
132
|
+
next unless file_name =~ pattern
|
133
|
+
|
134
|
+
f = File.open(directory + "/" + file_name)
|
135
|
+
|
136
|
+
while line = f.gets
|
137
|
+
stats["lines"] += 1
|
138
|
+
stats["classes"] += 1 if line =~ /class [A-Z]/
|
139
|
+
stats["methods"] += 1 if line =~ /def [a-z]/
|
140
|
+
stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
stats
|
145
|
+
end
|
146
|
+
|
147
|
+
def calculate_total
|
148
|
+
total = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
|
149
|
+
@statistics.each_value { |pair| pair.each { |k, v| total[k] += v } }
|
150
|
+
total
|
151
|
+
end
|
152
|
+
|
153
|
+
def calculate_code
|
154
|
+
code_loc = 0
|
155
|
+
@statistics.each { |k, v| code_loc += v['codelines'] unless TEST_TYPES.include? k }
|
156
|
+
code_loc
|
157
|
+
end
|
158
|
+
|
159
|
+
def calculate_tests
|
160
|
+
test_loc = 0
|
161
|
+
@statistics.each { |k, v| test_loc += v['codelines'] if TEST_TYPES.include? k }
|
162
|
+
test_loc
|
163
|
+
end
|
164
|
+
|
165
|
+
def print_header
|
166
|
+
print_splitter
|
167
|
+
puts "| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |"
|
168
|
+
print_splitter
|
169
|
+
end
|
170
|
+
|
171
|
+
def print_splitter
|
172
|
+
puts "+----------------------+-------+-------+---------+---------+-----+-------+"
|
173
|
+
end
|
174
|
+
|
175
|
+
def print_line(name, statistics)
|
176
|
+
m_over_c = (statistics["methods"] / statistics["classes"]) rescue m_over_c = 0
|
177
|
+
loc_over_m = (statistics["codelines"] / statistics["methods"]) - 2 rescue loc_over_m = 0
|
178
|
+
|
179
|
+
start = if TEST_TYPES.include? name
|
180
|
+
"| #{name.ljust(20)} "
|
181
|
+
else
|
182
|
+
"| #{name.ljust(20)} "
|
183
|
+
end
|
184
|
+
|
185
|
+
puts start +
|
186
|
+
"| #{statistics["lines"].to_s.rjust(5)} " +
|
187
|
+
"| #{statistics["codelines"].to_s.rjust(5)} " +
|
188
|
+
"| #{statistics["classes"].to_s.rjust(7)} " +
|
189
|
+
"| #{statistics["methods"].to_s.rjust(7)} " +
|
190
|
+
"| #{m_over_c.to_s.rjust(3)} " +
|
191
|
+
"| #{loc_over_m.to_s.rjust(5)} |"
|
192
|
+
end
|
193
|
+
|
194
|
+
def print_code_test_stats
|
195
|
+
code = calculate_code
|
196
|
+
tests = calculate_tests
|
197
|
+
|
198
|
+
puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f/code)}"
|
199
|
+
puts ""
|
200
|
+
end
|
201
|
+
end
|
data/lib/acdc.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'builder'
|
3
|
+
require 'activesupport'
|
4
|
+
require 'hpricot'
|
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")
|
9
|
+
|
10
|
+
module AcDc
|
11
|
+
|
12
|
+
VERSION = [0,2,2] unless defined?(AcDc::VERSION)
|
13
|
+
|
14
|
+
if defined?(JAIL_BREAK)
|
15
|
+
Element.class_eval{ alias :to_s :acdc }
|
16
|
+
Body.class_eval{ alias :to_s :acdc }
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
# Will construct a AcDc::Element classs
|
22
|
+
def Element(value, options = {})
|
23
|
+
AcDc::Element.new(value,options)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Will construct a AcDc::Attribute class
|
27
|
+
def Attribute(name,value)
|
28
|
+
AcDc::Attribute.new(name,value)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Will convert the XML to a class found in the library
|
32
|
+
def acdc(xml)
|
33
|
+
AcDc::Body.acdc(xml)
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,20 @@
|
|
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
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/acdc/body.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
module AcDc
|
2
|
+
class Body
|
3
|
+
|
4
|
+
attr_accessor :attributes, :elements, :sequence
|
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
|
+
if type
|
37
|
+
if val.respond_to?(:each)
|
38
|
+
val.each {|v| raise ArgumentError.new("Type is invalid") unless v.is_a?(type)}
|
39
|
+
else
|
40
|
+
raise ArgumentError.new("Type is invalid") unless val.is_a?(type)
|
41
|
+
end
|
42
|
+
if type.ancestors.include?(Body)
|
43
|
+
elements.update(key => type.new(val.to_hash.merge(:sequence => options_for(key)[:sequence])))
|
44
|
+
else
|
45
|
+
elements.update(key => type.new(val, options_for(key)))
|
46
|
+
end
|
47
|
+
else
|
48
|
+
elements.update(key => Element(val, options_for(key)))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Converts object to XML
|
55
|
+
def acdc
|
56
|
+
xml = Builder::XmlMarkup.new
|
57
|
+
attrs = attributes.inject({}){|acc,attr| acc.update(attr[1].to_hash)}
|
58
|
+
xml.tag!(tag_name,attrs){ |body|
|
59
|
+
elements.sort{|a,b| a[1].sequence <=> b[1].sequence}.each do |key, elem|
|
60
|
+
body << elem.acdc
|
61
|
+
end
|
62
|
+
}
|
63
|
+
xml.target!
|
64
|
+
end
|
65
|
+
|
66
|
+
# Calls #acdc then matches
|
67
|
+
def match(pattern)
|
68
|
+
acdc.match(pattern)
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_hash
|
72
|
+
elements
|
73
|
+
end
|
74
|
+
|
75
|
+
# The name to use for the tag
|
76
|
+
def tag_name
|
77
|
+
self.class.to_s.split("::").last
|
78
|
+
end
|
79
|
+
|
80
|
+
def method_missing(method_id, *args, &block)
|
81
|
+
key = method_id.to_s.gsub(/\=/,"").to_sym
|
82
|
+
if elements.has_key?(key) or attributes.has_key?(key)
|
83
|
+
(method_id.to_s.match(/\=$/)) ? write(method_id, *args, &block) : read(method_id)
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class << self
|
90
|
+
def inherited(child)
|
91
|
+
child.instance_variable_set('@declared_elements', @declared_elements)
|
92
|
+
child.instance_variable_set('@declared_attributes', @declared_attributes)
|
93
|
+
child.instance_variable_set('@element_sequence', @element_sequence)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Declare an Element for this Body
|
97
|
+
# Sequence of elements (XML Schema sequence) is taken care of by the order
|
98
|
+
# the elements are declared in the class definition.
|
99
|
+
#@param [Symbol] name A name to assign the Element (tag name)
|
100
|
+
#@param [Class] type A type to use for the element (enforcement)
|
101
|
+
#@option options [Boolean] :single False if object is a collection
|
102
|
+
#@option options [String] :tag String determining the name to use in the XML tag
|
103
|
+
def element(*options)
|
104
|
+
name = options.first
|
105
|
+
type = options.second || nil unless options.second.is_a?(Hash)
|
106
|
+
opts = options.extract_options!
|
107
|
+
opts.merge!(:tag => name) if opts[:tag].nil?
|
108
|
+
declared_elements.update(name => opts.merge(:type => type, :sequence => next_sequence))
|
109
|
+
end
|
110
|
+
|
111
|
+
# Declare an attribute for this Body
|
112
|
+
def attribute(name, value = nil)
|
113
|
+
declared_attributes.update(name => value)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns the Hash list of Elements declared
|
117
|
+
def declared_elements
|
118
|
+
@elements ||= {}
|
119
|
+
@declared_elements ||= @elements[to_s] ||= {}
|
120
|
+
end
|
121
|
+
|
122
|
+
# Returns a Hash list of Attributes declared
|
123
|
+
def declared_attributes
|
124
|
+
@attributes ||= {}
|
125
|
+
@declared_attributes ||= @attributes[to_s] ||= {}
|
126
|
+
end
|
127
|
+
|
128
|
+
# Converts the XML to a Class object found in the library
|
129
|
+
def acdc(xml)
|
130
|
+
doc = Hpricot.XML(xml)
|
131
|
+
klass = doc.root.name.constantize
|
132
|
+
attributes = doc.root.attributes.inject({}){|acc,attr| acc.update(attr[0].to_sym => attr[1])}
|
133
|
+
values = doc.root.children.inject({}) do |acc, node|
|
134
|
+
name = node.name.underscore.to_sym
|
135
|
+
value = value_from_node(node)
|
136
|
+
attrs = node.attributes
|
137
|
+
acc.merge!({name => value, :attributes => attrs})
|
138
|
+
end
|
139
|
+
klass.new(values.merge(:attributes => attributes))
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
def value_from_node(node)
|
144
|
+
if node.respond_to?(:children) and node.children
|
145
|
+
values = node.children.collect do |child|
|
146
|
+
return child.inner_text if child.text?
|
147
|
+
instantiate(child)
|
148
|
+
end
|
149
|
+
(values.size == 1) ? values.first : values
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def instantiate(node)
|
154
|
+
name = node.name
|
155
|
+
attrs = node.attributes
|
156
|
+
klass = name.constantize
|
157
|
+
klass.new(value_from_node(node), :attributes => attrs)
|
158
|
+
end
|
159
|
+
|
160
|
+
def next_sequence
|
161
|
+
@element_sequence ||= 0
|
162
|
+
@element_sequence = @element_sequence +=1
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def options_for(key)
|
169
|
+
self.class.declared_elements[key]
|
170
|
+
end
|
171
|
+
|
172
|
+
def read(method_id)
|
173
|
+
if elements.has_key?(method_id)
|
174
|
+
elements[method_id].value
|
175
|
+
else
|
176
|
+
attributes[method_id].value
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def write(method_id, *args, &block)
|
181
|
+
key = method_id.to_s.gsub(/\=$/,"").to_sym
|
182
|
+
if elements.has_key?(key)
|
183
|
+
elements.update(key => Element(args.first, options_for(key)))
|
184
|
+
else
|
185
|
+
attributes.update(key => Attribute(key,args.first))
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
data/lib/acdc/element.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module AcDc
|
2
|
+
|
3
|
+
# Basic XML Element
|
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
|
81
|
+
end
|
82
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: acdc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Clint Hill
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-02 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.3.2
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: builder
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.1.2
|
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
|
+
description: " This is a little xml-to-object-to-xml library that gets Dirty Deeds Done Dirt Cheap. \n"
|
46
|
+
email: clint.hill@h3osoftware.com
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files: []
|
52
|
+
|
53
|
+
files:
|
54
|
+
- LICENSE
|
55
|
+
- README
|
56
|
+
- Rakefile
|
57
|
+
- lib/acdc.rb
|
58
|
+
- lib/acdc/attribute.rb
|
59
|
+
- lib/acdc/body.rb
|
60
|
+
- lib/acdc/element.rb
|
61
|
+
has_rdoc: true
|
62
|
+
homepage: http://h3osoftware.com/acdc
|
63
|
+
licenses: []
|
64
|
+
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: "0"
|
75
|
+
version:
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: "0"
|
81
|
+
version:
|
82
|
+
requirements: []
|
83
|
+
|
84
|
+
rubyforge_project: acdc
|
85
|
+
rubygems_version: 1.3.5
|
86
|
+
signing_key:
|
87
|
+
specification_version: 3
|
88
|
+
summary: AC/DC by h3o(software)
|
89
|
+
test_files: []
|
90
|
+
|