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/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: "1.0"
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-06-21 00:00:00 +03:00
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: thoughtbot-shoulda
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.0.6
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/nuts.rb
50
+ - lib/peanuts/mappable.rb
41
51
  - lib/peanuts/mappings.rb
42
52
  - lib/peanuts/converters.rb
43
- - lib/peanuts/backend.rb
44
- - lib/peanuts/rexml.rb
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
- - test/parsing_test.rb
87
+ - spec/cat_spec.rb
@@ -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