peanuts 1.0 → 2.0.7
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/MIT-LICENSE +1 -1
- data/README.rdoc +56 -25
- data/Rakefile +7 -4
- data/lib/peanuts/converters.rb +20 -13
- data/lib/peanuts/mappable.rb +253 -0
- data/lib/peanuts/mapper.rb +95 -0
- data/lib/peanuts/mappings.rb +129 -74
- data/lib/peanuts/xml/libxml.rb +231 -0
- data/lib/peanuts/xml.rb +60 -0
- data/lib/peanuts.rb +7 -1
- data/spec/cat_spec.rb +151 -0
- metadata +19 -8
- data/lib/peanuts/backend.rb +0 -38
- data/lib/peanuts/nuts.rb +0 -219
- data/lib/peanuts/rexml.rb +0 -98
- data/test/parsing_test.rb +0 -115
data/spec/cat_spec.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
|
3
|
+
require 'bigdecimal'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'rubygems'
|
6
|
+
require 'shoulda'
|
7
|
+
require 'peanuts'
|
8
|
+
|
9
|
+
|
10
|
+
class Cheezburger
|
11
|
+
include Peanuts
|
12
|
+
|
13
|
+
attribute :weight, :float
|
14
|
+
attribute :price, :decimal
|
15
|
+
|
16
|
+
def initialize(weight = nil, price = nil)
|
17
|
+
@weight, @price = weight, price
|
18
|
+
end
|
19
|
+
|
20
|
+
def eql?(other)
|
21
|
+
other && weight == other.weight && price == other.price
|
22
|
+
end
|
23
|
+
|
24
|
+
alias == eql?
|
25
|
+
end
|
26
|
+
|
27
|
+
class Paws
|
28
|
+
include Peanuts
|
29
|
+
|
30
|
+
elements :paws, :name => :paw, :ns => 'urn:x-lol'
|
31
|
+
end
|
32
|
+
|
33
|
+
class Cat
|
34
|
+
include Peanuts
|
35
|
+
|
36
|
+
namespaces :lol => 'urn:x-lol', :kthnx => 'urn:x-lol:kthnx'
|
37
|
+
|
38
|
+
root 'kitteh', :ns => 'urn:x-lol'
|
39
|
+
|
40
|
+
attribute :has_tail?, :boolean, :name => 'has-tail', :ns => :kthnx
|
41
|
+
attribute :ears, :integer
|
42
|
+
|
43
|
+
element :ration, [:string], :name => :eats, :ns => :kthnx
|
44
|
+
element :name, :ns => 'urn:x-lol:kthnx'
|
45
|
+
|
46
|
+
shallow :paws, Paws
|
47
|
+
|
48
|
+
shallow :pals, :ns => :kthnx do
|
49
|
+
elements :friends, :name => :pal
|
50
|
+
end
|
51
|
+
|
52
|
+
element :cheezburger, Cheezburger
|
53
|
+
element :moar_cheezburgers do
|
54
|
+
elements :cheezburger, Cheezburger
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
shared_examples_for 'my cat' do
|
59
|
+
it 'should be named Silly Tom' do
|
60
|
+
@cat.name.should == 'Silly Tom'
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should eat tigers and lions' do
|
64
|
+
@cat.ration.should == %w(tigers lions)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should be a friend of Chrissy, Missy & Sissy' do
|
68
|
+
@cat.friends.should == ['Chrissy', 'Missy', 'Sissy']
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should have 2 ears' do
|
72
|
+
@cat.ears.should == 2
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should have a tail' do
|
76
|
+
@cat.should have_tail
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should have four paws' do
|
80
|
+
@cat.paws.should == %w(one two three four)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should has cheezburger' do
|
84
|
+
@cat.cheezburger.should be_kind_of Cheezburger
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should has 2 moar good cheezburgerz' do
|
88
|
+
@cat.moar_cheezburgers.cheezburger.should == [
|
89
|
+
Cheezburger.new(685.940, BigDecimal('19')),
|
90
|
+
Cheezburger.new(9356.7, BigDecimal('7.40'))]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
shared_examples_for 'my cheezburger' do
|
95
|
+
it 'should weigh 14.5547 pounds' do
|
96
|
+
@cheezburger.weight.should == 14.5547
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should cost $2.05' do
|
100
|
+
@cheezburger.price.should == BigDecimal('2.05')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
shared_examples_for 'sample kitteh' do
|
105
|
+
before :all do
|
106
|
+
@xml_fragment = <<-EOS
|
107
|
+
<kitteh xmlns='urn:x-lol' xmlns:kthnx='urn:x-lol:kthnx' ears=' 2 ' kthnx:has-tail=' yes '>
|
108
|
+
<name xmlns='urn:x-lol:kthnx'>
|
109
|
+
Silly
|
110
|
+
Tom
|
111
|
+
</name>
|
112
|
+
<kthnx:eats>
|
113
|
+
tigers
|
114
|
+
lions
|
115
|
+
</kthnx:eats>
|
116
|
+
<kthnx:pals>
|
117
|
+
<pal>Chrissy</pal>
|
118
|
+
<pal>Missy</pal>
|
119
|
+
<pal>Sissy</pal>
|
120
|
+
</kthnx:pals>
|
121
|
+
<paws>
|
122
|
+
<paw> one</paw>
|
123
|
+
<paw> two </paw>
|
124
|
+
<paw>three</paw>
|
125
|
+
<paw>four</paw>
|
126
|
+
</paws>
|
127
|
+
<cheezburger price='2.05' weight='14.5547' />
|
128
|
+
<moar_cheezburgers>
|
129
|
+
<cheezburger price='19' weight='685.940' />
|
130
|
+
<cheezburger price='7.40' weight='9356.7' />
|
131
|
+
</moar_cheezburgers>
|
132
|
+
</kitteh>
|
133
|
+
EOS
|
134
|
+
@cat = Cat.from_xml(@xml_fragment)
|
135
|
+
@cheezburger = @cat.cheezburger
|
136
|
+
end
|
137
|
+
|
138
|
+
it_should_behave_like 'my cat', 'my cheezburger'
|
139
|
+
end
|
140
|
+
|
141
|
+
describe 'My cat' do
|
142
|
+
it_should_behave_like 'sample kitteh'
|
143
|
+
|
144
|
+
context 'saved and restored' do
|
145
|
+
it_should_behave_like 'sample kitteh'
|
146
|
+
|
147
|
+
before :all do
|
148
|
+
@cat = Cat.from_xml(@cat.to_xml)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: peanuts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Igor Gunko
|
@@ -9,18 +9,28 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-09-30 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
16
|
+
name: libxml-ruby
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.1.3
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
17
27
|
type: :development
|
18
28
|
version_requirement:
|
19
29
|
version_requirements: !ruby/object:Gem::Requirement
|
20
30
|
requirements:
|
21
31
|
- - ">="
|
22
32
|
- !ruby/object:Gem::Version
|
23
|
-
version: 2.
|
33
|
+
version: 1.2.8
|
24
34
|
version:
|
25
35
|
description: " Peanuts is an XML to Ruby and back again mapping library.\n"
|
26
36
|
email: tekmon@gmail.com
|
@@ -37,11 +47,12 @@ files:
|
|
37
47
|
- Rakefile
|
38
48
|
- lib/peanuts.rb
|
39
49
|
- lib/omg-peanuts.rb
|
40
|
-
- lib/peanuts/
|
50
|
+
- lib/peanuts/mappable.rb
|
41
51
|
- lib/peanuts/mappings.rb
|
42
52
|
- lib/peanuts/converters.rb
|
43
|
-
- lib/peanuts/
|
44
|
-
- lib/peanuts/
|
53
|
+
- lib/peanuts/mapper.rb
|
54
|
+
- lib/peanuts/xml.rb
|
55
|
+
- lib/peanuts/xml/libxml.rb
|
45
56
|
has_rdoc: true
|
46
57
|
homepage: http://github.com/omg/peanuts
|
47
58
|
licenses: []
|
@@ -73,4 +84,4 @@ signing_key:
|
|
73
84
|
specification_version: 2
|
74
85
|
summary: Making XML <-> Ruby binding easy
|
75
86
|
test_files:
|
76
|
-
-
|
87
|
+
- spec/cat_spec.rb
|
data/lib/peanuts/backend.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'monitor'
|
2
|
-
|
3
|
-
module Peanuts
|
4
|
-
module XmlBackend
|
5
|
-
extend MonitorMixin
|
6
|
-
|
7
|
-
autoload :REXMLBackend, 'peanuts/rexml'
|
8
|
-
|
9
|
-
def self.default
|
10
|
-
synchronize do
|
11
|
-
unless defined? @@default
|
12
|
-
@@default = REXMLBackend.new
|
13
|
-
def self.default #:nodoc:
|
14
|
-
@@default
|
15
|
-
end
|
16
|
-
@@default
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.default=(backend)
|
22
|
-
@@default = backend
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.current
|
26
|
-
Thread.current[XmlBackend.name] || default
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.current=(backend)
|
30
|
-
Thread.current[XmlBackend.name] = backend
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
def backend #:doc:
|
35
|
-
XmlBackend.current
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
data/lib/peanuts/nuts.rb
DELETED
@@ -1,219 +0,0 @@
|
|
1
|
-
require 'peanuts/mappings'
|
2
|
-
|
3
|
-
module Peanuts #:nodoc:
|
4
|
-
# See also +ClassMethods+
|
5
|
-
def self.included(other) #:nodoc:
|
6
|
-
other.extend(ClassMethods)
|
7
|
-
end
|
8
|
-
|
9
|
-
# See also +PeaNuts+.
|
10
|
-
module ClassMethods
|
11
|
-
include XmlBackend
|
12
|
-
include Mappings
|
13
|
-
|
14
|
-
# namespaces(hash) -> Hash
|
15
|
-
# namespaces -> Hash
|
16
|
-
#
|
17
|
-
# Updates and returns class-level prefix mappings.
|
18
|
-
# When given a hash of mappings merges it over current.
|
19
|
-
# When called withot arguments simply returns current mappings.
|
20
|
-
#
|
21
|
-
# === Example:
|
22
|
-
# class Cat
|
23
|
-
# include PeaNuts
|
24
|
-
# namespaces :lol => 'urn:lol', ...
|
25
|
-
# ...
|
26
|
-
# end
|
27
|
-
def namespaces(mappings = nil)
|
28
|
-
@namespaces ||= {}
|
29
|
-
mappings ? @namespaces.update(mappings) : @namespaces
|
30
|
-
end
|
31
|
-
|
32
|
-
# root(xmlname[, :xmlns => ...]) -> Mappings::Root
|
33
|
-
# root -> Mappings::Root
|
34
|
-
#
|
35
|
-
# Defines element name.
|
36
|
-
# TODO: moar details
|
37
|
-
#
|
38
|
-
# === Arguments
|
39
|
-
# [+xmlname+] Element name
|
40
|
-
# [+options+] <tt>:xmlns => <tt> Element namespace
|
41
|
-
#
|
42
|
-
# === Example:
|
43
|
-
# class Cat
|
44
|
-
# include Peanuts
|
45
|
-
# ...
|
46
|
-
# root :kitteh, :xmlns => 'urn:lol'
|
47
|
-
# ...
|
48
|
-
# end
|
49
|
-
def root(xmlname = nil, options = {})
|
50
|
-
@root = Root.new(xmlname, prepare_options(options)) if xmlname
|
51
|
-
@root ||= Root.new('root')
|
52
|
-
end
|
53
|
-
|
54
|
-
# element(name, [type[, options]]) -> Mappings::Element or Mappings::ElementValue
|
55
|
-
# element(name[, options]) { block } -> Mappings::Element
|
56
|
-
#
|
57
|
-
# Defines single-element mapping.
|
58
|
-
#
|
59
|
-
# === Arguments
|
60
|
-
# [+name+] Accessor name
|
61
|
-
# [+type+] Element type. <tt>:string</tt> assumed if omitted (see +Converter+).
|
62
|
-
# [+options+] <tt>:xmlname</tt>, <tt>:xmlns</tt>, converter options (see +Converter+).
|
63
|
-
# [+block+] An anonymous class definition.
|
64
|
-
#
|
65
|
-
# === Example:
|
66
|
-
# class Cat
|
67
|
-
# include Peanuts
|
68
|
-
# ...
|
69
|
-
# element :name, :string, :whitespace => :collapse
|
70
|
-
# element :cheeseburger, Cheeseburger, :xmlname => :cheezburger
|
71
|
-
# ...
|
72
|
-
# end
|
73
|
-
def element(name, type = :string, options = {}, &block)
|
74
|
-
type, options = prepare_args(type, options, &block)
|
75
|
-
define_accessor name
|
76
|
-
(mappings << (type.is_a?(Class) ? Element : ElementValue).new(name, type, prepare_options(options))).last
|
77
|
-
end
|
78
|
-
|
79
|
-
# elements(name, [type[, options]]) -> Mappings::Element or Mappings::ElementValue
|
80
|
-
# elements(name[, options]) { block } -> Mappings::Element
|
81
|
-
#
|
82
|
-
# Defines multiple elements mapping.
|
83
|
-
#
|
84
|
-
# === Arguments
|
85
|
-
# [+name+] Accessor name
|
86
|
-
# [+type+] Element type. <tt>:string</tt> assumed if omitted (see +Converter+).
|
87
|
-
# [+options+] <tt>:xmlname</tt>, <tt>:xmlns</tt>, converter options (see +Converter+).
|
88
|
-
# [+block+] An anonymous class definition.
|
89
|
-
#
|
90
|
-
# === Example:
|
91
|
-
# class RichCat
|
92
|
-
# include Peanuts
|
93
|
-
# ...
|
94
|
-
# elements :ration, :string, :whitespace => :collapse
|
95
|
-
# elements :cheeseburgers, Cheeseburger, :xmlname => :cheezburger
|
96
|
-
# ...
|
97
|
-
# end
|
98
|
-
def elements(name, type = :string, options = {}, &block)
|
99
|
-
type, options = prepare_args(type, options, &block)
|
100
|
-
define_accessor name
|
101
|
-
(mappings << (type.is_a?(Class) ? Elements : ElementValues).new(name, type, prepare_options(options))).last
|
102
|
-
end
|
103
|
-
|
104
|
-
# attribute(name, [type[, options]]) -> Mappings::Attribute or Mappings::AttributeValue
|
105
|
-
#
|
106
|
-
# Defines attribute mapping.
|
107
|
-
#
|
108
|
-
# === Arguments
|
109
|
-
# [+name+] Accessor name
|
110
|
-
# [+type+] Element type. <tt>:string</tt> assumed if omitted (see +Converter+).
|
111
|
-
# [+options+] <tt>:xmlname</tt>, <tt>:xmlns</tt>, converter options (see +Converter+).
|
112
|
-
#
|
113
|
-
# === Example:
|
114
|
-
# class Cat
|
115
|
-
# include Peanuts
|
116
|
-
# ...
|
117
|
-
# element :name, :string, :whitespace => :collapse
|
118
|
-
# element :cheeseburger, Cheeseburger, :xmlname => :cheezburger
|
119
|
-
# ...
|
120
|
-
# end
|
121
|
-
def attribute(name, type = :string, options = {})
|
122
|
-
define_accessor name
|
123
|
-
mappings << Attribute.new(name, type, prepare_options(options))
|
124
|
-
end
|
125
|
-
|
126
|
-
# mappings -> Array
|
127
|
-
#
|
128
|
-
# Returns all mappings defined on a class.
|
129
|
-
def mappings
|
130
|
-
@mappings ||= []
|
131
|
-
end
|
132
|
-
|
133
|
-
def parse(source, options = {})
|
134
|
-
backend.parse(source, options) {|node| parse_node(new, node) }
|
135
|
-
end
|
136
|
-
|
137
|
-
def build(nut, result = :string, options = {})
|
138
|
-
options, result = result, :string if result.is_a?(Hash)
|
139
|
-
options[:xmlname] ||= root.xmlname
|
140
|
-
options[:xmlns_prefix] = namespaces.invert[options[:xmlns] ||= root.xmlns]
|
141
|
-
backend.build(result, options) {|node| build_node(nut, node) }
|
142
|
-
end
|
143
|
-
|
144
|
-
def build_node(nut, node) #:nodoc:
|
145
|
-
backend.add_namespaces(node, namespaces)
|
146
|
-
callem(:to_xml, nut, node)
|
147
|
-
node
|
148
|
-
end
|
149
|
-
|
150
|
-
def parse_node(nut, node) #:nodoc:
|
151
|
-
callem(:from_xml, nut, node)
|
152
|
-
nut
|
153
|
-
end
|
154
|
-
|
155
|
-
private
|
156
|
-
def prepare_args(type, options, &block)
|
157
|
-
if block_given?
|
158
|
-
options = type if type.is_a?(Hash)
|
159
|
-
type = Class.new
|
160
|
-
type.class_eval do
|
161
|
-
include Peanuts
|
162
|
-
class_eval(&block)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
return type, prepare_options(options)
|
166
|
-
end
|
167
|
-
|
168
|
-
def prepare_options(options)
|
169
|
-
ns = options[:xmlns]
|
170
|
-
if ns.is_a?(Symbol)
|
171
|
-
raise ArgumentError, "undefined prefix: #{ns}" unless options[:xmlns] = namespaces[ns]
|
172
|
-
end
|
173
|
-
options
|
174
|
-
end
|
175
|
-
|
176
|
-
def define_accessor(name)
|
177
|
-
if method_defined?(name) || method_defined?("#{name}=")
|
178
|
-
raise ArgumentError, "#{name}: name already defined or reserved"
|
179
|
-
end
|
180
|
-
attr_accessor name
|
181
|
-
end
|
182
|
-
|
183
|
-
def callem(method, *args)
|
184
|
-
mappings.each {|m| m.send(method, *args) }
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
def parse(source, options = {})
|
189
|
-
backend.parse(source, options) {|node| parse_node(node) }
|
190
|
-
end
|
191
|
-
|
192
|
-
# build([options]) -> root element or string
|
193
|
-
# build([options]) -> root element or string
|
194
|
-
# build(destination[, options]) -> destination
|
195
|
-
#
|
196
|
-
# Defines attribute mapping.
|
197
|
-
#
|
198
|
-
# === Arguments
|
199
|
-
# [+destination+]
|
200
|
-
# Can be given a symbol a backend-specific object, an instance of String or IO classes.
|
201
|
-
# [<tt>:string</tt>] will return an XML string.
|
202
|
-
# [<tt>:document</tt>] will return a backend specific document object.
|
203
|
-
# [<tt>:object</tt>] will return a backend specific object. New document will be created.
|
204
|
-
# [an instance of +String+] the contents of the string will be replaced with the generated XML.
|
205
|
-
# [an instance of +IO+] the IO will be written to.
|
206
|
-
# [+options+] Backend-specific options
|
207
|
-
#
|
208
|
-
# === Example:
|
209
|
-
# cat = Cat.new
|
210
|
-
# cat.name = 'Pussy'
|
211
|
-
# puts cat.build
|
212
|
-
# ...
|
213
|
-
# doc = REXML::Document.new
|
214
|
-
# cat.build(doc)
|
215
|
-
# puts doc.to_s
|
216
|
-
def build(result = :string, options = {})
|
217
|
-
self.class.build(self, result, options)
|
218
|
-
end
|
219
|
-
end
|
data/lib/peanuts/rexml.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
require 'rexml/document'
|
2
|
-
require 'peanuts/backend'
|
3
|
-
|
4
|
-
class Peanuts::XmlBackend::REXMLBackend #:nodoc:
|
5
|
-
def parse(source, options)
|
6
|
-
case source
|
7
|
-
when nil
|
8
|
-
return nil
|
9
|
-
when REXML::Document
|
10
|
-
node = source.root
|
11
|
-
when REXML::Node
|
12
|
-
node = source
|
13
|
-
when String, IO
|
14
|
-
node = REXML::Document.new(source).root
|
15
|
-
else
|
16
|
-
raise ArgumentError, 'invalid source'
|
17
|
-
end
|
18
|
-
node && yield(node)
|
19
|
-
end
|
20
|
-
|
21
|
-
def build(result, options)
|
22
|
-
case result
|
23
|
-
when :string, :document, :object, String, IO
|
24
|
-
doc = REXML::Document.new
|
25
|
-
when REXML::Document
|
26
|
-
doc = result
|
27
|
-
when REXML::Node
|
28
|
-
node, doc = result, result.document
|
29
|
-
else
|
30
|
-
raise ArgumentError, 'invalid destination'
|
31
|
-
end
|
32
|
-
node ||= doc.root
|
33
|
-
unless node
|
34
|
-
name, ns, prefix = options[:xmlname], options[:xmlns], options[:xmlns_prefix]
|
35
|
-
name, ns = "#{prefix}:#{name}", nil if prefix
|
36
|
-
node = add_element(doc, name, ns, nil)
|
37
|
-
end
|
38
|
-
|
39
|
-
yield node
|
40
|
-
|
41
|
-
case result
|
42
|
-
when :string
|
43
|
-
doc.to_s
|
44
|
-
when String
|
45
|
-
result.replace(doc.to_s)
|
46
|
-
when IO
|
47
|
-
doc.write(result)
|
48
|
-
result
|
49
|
-
when REXML::Document, :document
|
50
|
-
doc
|
51
|
-
when REXML::Node, :object
|
52
|
-
node
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def add_namespaces(context, namespaces)
|
57
|
-
namespaces.each {|prefix, uri| context.add_namespace(prefix.to_s, uri) }
|
58
|
-
end
|
59
|
-
|
60
|
-
def each_element(context, name, ns, &block)
|
61
|
-
ns = context.namespace unless ns
|
62
|
-
REXML::XPath.each(context, "ns:#{name}", 'ns' => ns, &block)
|
63
|
-
end
|
64
|
-
|
65
|
-
def value(node)
|
66
|
-
node.text
|
67
|
-
end
|
68
|
-
|
69
|
-
def attribute(context, name, ns)
|
70
|
-
name, ns = to_prefixed_name(context, name, ns, true)
|
71
|
-
context.attributes[name]
|
72
|
-
end
|
73
|
-
|
74
|
-
def set_attribute(context, name, ns, text)
|
75
|
-
name, ns = to_prefixed_name(context, name, ns, true)
|
76
|
-
context.add_attribute(name, text)
|
77
|
-
end
|
78
|
-
|
79
|
-
def add_element(context, name, ns, text)
|
80
|
-
name, ns = to_prefixed_name(context, name, ns, false)
|
81
|
-
elem = context.add_element(name)
|
82
|
-
elem.add_namespace(ns) if ns
|
83
|
-
elem.text = text if text
|
84
|
-
elem
|
85
|
-
end
|
86
|
-
|
87
|
-
private
|
88
|
-
def to_prefixed_name(context, name, ns, prefix_required)
|
89
|
-
if ns
|
90
|
-
if prefix = context.namespaces.invert[ns]
|
91
|
-
name, ns = "#{prefix}:#{name}", nil
|
92
|
-
else
|
93
|
-
raise ArgumentError, "no prefix defined for #{ns}" if prefix_required
|
94
|
-
end
|
95
|
-
end
|
96
|
-
return name, ns
|
97
|
-
end
|
98
|
-
end
|
data/test/parsing_test.rb
DELETED
@@ -1,115 +0,0 @@
|
|
1
|
-
#$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
2
|
-
|
3
|
-
require 'bigdecimal'
|
4
|
-
require 'test/unit'
|
5
|
-
require 'rubygems'
|
6
|
-
require 'shoulda'
|
7
|
-
require 'lib/peanuts'
|
8
|
-
|
9
|
-
|
10
|
-
class Cheezburger
|
11
|
-
include Peanuts
|
12
|
-
|
13
|
-
attribute :weight, :float
|
14
|
-
attribute :price, :decimal
|
15
|
-
end
|
16
|
-
|
17
|
-
class Cat
|
18
|
-
include Peanuts
|
19
|
-
|
20
|
-
namespaces :lol => 'urn:x-lol', :kthnx => 'urn:x-lol:kthnx'
|
21
|
-
|
22
|
-
root 'kitteh', :xmlns => :lol
|
23
|
-
|
24
|
-
attribute :has_tail, :boolean, :xmlname => 'has-tail', :xmlns => 'urn:x-lol:kthnx'
|
25
|
-
attribute :ears, :integer
|
26
|
-
|
27
|
-
element :ration, [:string], :xmlname => :eats, :xmlns => :kthnx
|
28
|
-
element :name, :string, :xmlns => 'urn:x-lol:kthnx'
|
29
|
-
elements :paws, :string, :xmlname => :paw
|
30
|
-
|
31
|
-
element :friends, :xmlname => :pals do
|
32
|
-
elements :names, :string, :xmlname => :pal
|
33
|
-
end
|
34
|
-
|
35
|
-
element :cheezburger, Cheezburger
|
36
|
-
element :moar_cheezburgers do
|
37
|
-
elements :cheezburger, Cheezburger
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class ParsingTest < Test::Unit::TestCase
|
42
|
-
def setup
|
43
|
-
@xml_fragment = <<-EOS
|
44
|
-
<kitteh xmlns='urn:x-lol' xmlns:kthnx='urn:x-lol:kthnx' ears=' 2 ' kthnx:has-tail=' yes '>
|
45
|
-
<name xmlns='urn:x-lol:kthnx'>
|
46
|
-
Silly
|
47
|
-
Tom
|
48
|
-
</name>
|
49
|
-
<kthnx:eats>
|
50
|
-
tigers
|
51
|
-
lions
|
52
|
-
</kthnx:eats>
|
53
|
-
<pals>
|
54
|
-
<pal>Chrissy</pal>
|
55
|
-
<pal>Missy</pal>
|
56
|
-
<pal>Sissy</pal>
|
57
|
-
</pals>
|
58
|
-
<paw> one</paw>
|
59
|
-
<paw> two </paw>
|
60
|
-
<paw>three</paw>
|
61
|
-
<paw>four</paw>
|
62
|
-
<cheezburger price='2.05' weight='14.5547' />
|
63
|
-
<moar_cheezburgers>
|
64
|
-
<cheezburger price='19' weight='685.940' />
|
65
|
-
<cheezburger price='7.40' weight='9356.7' />
|
66
|
-
</moar_cheezburgers>
|
67
|
-
</kitteh>
|
68
|
-
EOS
|
69
|
-
@cat = Cat.parse(@xml_fragment)
|
70
|
-
end
|
71
|
-
|
72
|
-
context "A cat" do
|
73
|
-
should 'be named Silly Tom' do
|
74
|
-
assert_equal 'Silly Tom', @cat.name
|
75
|
-
end
|
76
|
-
|
77
|
-
should 'eat tigers and lions' do
|
78
|
-
assert_equal %w(tigers lions), @cat.ration
|
79
|
-
end
|
80
|
-
|
81
|
-
should 'be a friend of Chrissy, Missy & Sissy' do
|
82
|
-
assert_equal ['Chrissy', 'Missy', 'Sissy'], @cat.friends.names
|
83
|
-
end
|
84
|
-
|
85
|
-
should 'have 2 ears' do
|
86
|
-
assert_equal 2, @cat.ears
|
87
|
-
end
|
88
|
-
|
89
|
-
should 'have a tail' do
|
90
|
-
assert @cat.has_tail
|
91
|
-
end
|
92
|
-
|
93
|
-
should 'have four paws' do
|
94
|
-
assert_equal %w(one two three four), @cat.paws
|
95
|
-
end
|
96
|
-
|
97
|
-
should 'has cheezburger' do
|
98
|
-
assert_kind_of Cheezburger, @cat.cheezburger
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
context 'A cheezburger' do
|
103
|
-
setup do
|
104
|
-
@burger = @cat.cheezburger
|
105
|
-
end
|
106
|
-
|
107
|
-
should 'weigh 14.5547 pounds' do
|
108
|
-
assert_equal 14.5547, @burger.weight
|
109
|
-
end
|
110
|
-
|
111
|
-
should 'cost $2.05' do
|
112
|
-
assert_equal BigDecimal('2.05'), @burger.price
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|