peanuts 1.0 → 2.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|