dm-serializer 0.9.11 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{History.txt → History.rdoc} +8 -1
- data/Manifest.txt +3 -2
- data/README.rdoc +64 -0
- data/Rakefile +2 -3
- data/benchmarks/to_json.rb +137 -0
- data/benchmarks/to_xml.rb +3 -3
- data/lib/dm-serializer/common.rb +8 -4
- data/lib/dm-serializer/to_csv.rb +27 -6
- data/lib/dm-serializer/to_json.rb +36 -17
- data/lib/dm-serializer/to_xml.rb +41 -4
- data/lib/dm-serializer/to_yaml.rb +15 -4
- data/lib/dm-serializer/version.rb +1 -1
- data/lib/dm-serializer/xml_serializers/libxml.rb +5 -0
- data/lib/dm-serializer/xml_serializers/nokogiri.rb +4 -0
- data/lib/dm-serializer/xml_serializers/rexml.rb +4 -0
- data/spec/fixtures/cow.rb +2 -2
- data/spec/fixtures/planet.rb +17 -4
- data/spec/fixtures/quan_tum_cat.rb +2 -2
- data/spec/lib/serialization_method_shared_spec.rb +53 -24
- data/spec/public/serializer_spec.rb +1 -2
- data/spec/public/to_csv_spec.rb +49 -35
- data/spec/public/to_json_spec.rb +9 -6
- data/spec/public/to_xml_spec.rb +31 -23
- data/spec/public/to_yaml_spec.rb +27 -9
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +13 -6
- data/tasks/install.rb +1 -1
- data/tasks/spec.rb +4 -4
- metadata +15 -21
- data/README.textile +0 -61
data/lib/dm-serializer/to_xml.rb
CHANGED
@@ -8,7 +8,8 @@ module DataMapper
|
|
8
8
|
#
|
9
9
|
# @return <REXML::Document> an XML representation of this Resource
|
10
10
|
def to_xml(opts = {})
|
11
|
-
|
11
|
+
xml = XMLSerializers::SERIALIZER
|
12
|
+
xml.output(to_xml_document(opts)).to_s
|
12
13
|
end
|
13
14
|
|
14
15
|
protected
|
@@ -21,7 +22,7 @@ module DataMapper
|
|
21
22
|
def to_xml_document(opts={}, doc = nil)
|
22
23
|
xml = XMLSerializers::SERIALIZER
|
23
24
|
doc ||= xml.new_document
|
24
|
-
default_xml_element_name = lambda { Extlib::Inflection.underscore(
|
25
|
+
default_xml_element_name = lambda { Extlib::Inflection.underscore(model.name).tr("/", "-") }
|
25
26
|
root = xml.root_node(doc, opts[:element_name] || default_xml_element_name[])
|
26
27
|
properties_to_serialize(opts).each do |property|
|
27
28
|
value = send(property.name)
|
@@ -33,10 +34,16 @@ module DataMapper
|
|
33
34
|
if self.respond_to?(meth)
|
34
35
|
xml_name = meth.to_s.gsub(/[^a-z0-9_]/, '')
|
35
36
|
value = send(meth)
|
36
|
-
|
37
|
+
unless value.nil?
|
38
|
+
if value.respond_to?(:to_xml_document)
|
39
|
+
xml.add_xml(root, value.send(:to_xml_document))
|
40
|
+
else
|
41
|
+
xml.add_node(root, xml_name, value.to_s)
|
42
|
+
end
|
43
|
+
end
|
37
44
|
end
|
38
45
|
end
|
39
|
-
|
46
|
+
doc
|
40
47
|
end
|
41
48
|
end
|
42
49
|
|
@@ -58,4 +65,34 @@ module DataMapper
|
|
58
65
|
doc
|
59
66
|
end
|
60
67
|
end
|
68
|
+
|
69
|
+
if Serialize::Support.dm_validations_loaded?
|
70
|
+
|
71
|
+
module Validate
|
72
|
+
class ValidationErrors
|
73
|
+
def to_xml(opts = {})
|
74
|
+
to_xml_document(opts).to_s
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
def to_xml_document(opts = {})
|
80
|
+
xml = DataMapper::Serialize::XMLSerializers::SERIALIZER
|
81
|
+
doc = xml.new_document
|
82
|
+
root = xml.root_node(doc, "errors", {'type' => 'hash'})
|
83
|
+
|
84
|
+
errors.each do |key, value|
|
85
|
+
property = xml.add_node(root, key.to_s, nil, {'type' => 'array'})
|
86
|
+
property.attributes["type"] = 'array'
|
87
|
+
value.each do |error|
|
88
|
+
xml.add_node(property, "error", error)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
doc
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
61
98
|
end
|
@@ -6,7 +6,7 @@ module DataMapper
|
|
6
6
|
#
|
7
7
|
# @return <YAML> a YAML representation of this Resource
|
8
8
|
def to_yaml(opts_or_emitter = {})
|
9
|
-
if opts_or_emitter.is_a?(
|
9
|
+
if !opts_or_emitter.is_a?(Hash)
|
10
10
|
emitter = opts_or_emitter
|
11
11
|
opts = {}
|
12
12
|
else
|
@@ -16,8 +16,7 @@ module DataMapper
|
|
16
16
|
|
17
17
|
YAML::quick_emit(object_id,emitter) do |out|
|
18
18
|
out.map(nil,to_yaml_style) do |map|
|
19
|
-
|
20
|
-
propset.each do |property|
|
19
|
+
properties_to_serialize(opts).each do |property|
|
21
20
|
value = send(property.name.to_sym)
|
22
21
|
map.add(property.name, value.is_a?(Class) ? value.to_s : value)
|
23
22
|
end
|
@@ -37,7 +36,7 @@ module DataMapper
|
|
37
36
|
|
38
37
|
class Collection
|
39
38
|
def to_yaml(opts_or_emitter = {})
|
40
|
-
if opts_or_emitter.is_a?(
|
39
|
+
if !opts_or_emitter.is_a?(Hash)
|
41
40
|
to_a.to_yaml(opts_or_emitter)
|
42
41
|
else
|
43
42
|
# FIXME: Don't double handle the YAML (remove the YAML.load)
|
@@ -45,4 +44,16 @@ module DataMapper
|
|
45
44
|
end
|
46
45
|
end
|
47
46
|
end
|
47
|
+
|
48
|
+
if Serialize::Support.dm_validations_loaded?
|
49
|
+
|
50
|
+
module Validate
|
51
|
+
class ValidationErrors
|
52
|
+
def to_yaml(*args)
|
53
|
+
errors.to_hash.to_yaml(*args)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
48
59
|
end
|
data/spec/fixtures/cow.rb
CHANGED
@@ -6,6 +6,6 @@ class Cow
|
|
6
6
|
property :name, String
|
7
7
|
property :breed, String
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
belongs_to :mother_cow, :model => self, :nullable => true
|
10
|
+
has n, :baby_cows, :model => self, :child_key => [ :mother_cow_id, :mother_cow_composite ]
|
11
11
|
end
|
data/spec/fixtures/planet.rb
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
class Planet
|
2
2
|
include DataMapper::Resource
|
3
3
|
|
4
|
-
property :name,
|
4
|
+
property :name, String, :key => true
|
5
5
|
property :aphelion, Float
|
6
6
|
|
7
|
+
validates_length :name, :min => 2
|
8
|
+
|
7
9
|
# Sorry these associations don't make any sense
|
8
10
|
# I just needed a many-to-many association to test against
|
9
11
|
has n, :friended_planets
|
10
|
-
has n, :friend_planets, :through => :friended_planets, :
|
12
|
+
has n, :friend_planets, :through => :friended_planets, :model => 'Planet'
|
13
|
+
|
14
|
+
belongs_to :solar_system
|
11
15
|
|
12
16
|
def category
|
13
17
|
case self.name.downcase
|
@@ -28,6 +32,15 @@ class FriendedPlanet
|
|
28
32
|
property :planet_name, String, :key => true
|
29
33
|
property :friend_planet_name, String, :key => true
|
30
34
|
|
31
|
-
belongs_to :planet, :child_key => [:planet_name]
|
32
|
-
belongs_to :friend_planet, :
|
35
|
+
belongs_to :planet, :child_key => [ :planet_name ]
|
36
|
+
belongs_to :friend_planet, :model => 'Planet', :child_key => [ :friend_planet_name ]
|
37
|
+
end
|
38
|
+
|
39
|
+
class SolarSystem
|
40
|
+
include DataMapper::Resource
|
41
|
+
|
42
|
+
property :id, Serial
|
43
|
+
|
44
|
+
property :name, String
|
45
|
+
|
33
46
|
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
|
1
|
+
require 'spec_helper'
|
3
2
|
|
4
3
|
share_examples_for 'A serialization method that also serializes core classes' do
|
5
4
|
# This spec ensures that we don't break any serialization methods attached
|
@@ -32,13 +31,19 @@ share_examples_for 'A serialization method that also serializes core classes' do
|
|
32
31
|
|
33
32
|
it 'serializes an array of collections' do
|
34
33
|
query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
|
35
|
+
keys = %w[ id composite name breed ]
|
36
|
+
|
37
|
+
resources = [
|
38
|
+
keys.zip([ 1, 2, 'Betsy', 'Jersey' ]).to_hash,
|
39
|
+
keys.zip([ 89, 34, 'Berta', 'Guernsey' ]).to_hash,
|
40
|
+
]
|
41
|
+
|
42
|
+
collection = DataMapper::Collection.new(query, query.model.load(resources, query))
|
43
|
+
|
44
|
+
result = @harness.test(collection)
|
45
|
+
result[0].values_at(*keys).should == resources[0].values_at(*keys)
|
46
|
+
result[1].values_at(*keys).should == resources[1].values_at(*keys)
|
42
47
|
end
|
43
48
|
end
|
44
49
|
|
@@ -144,6 +149,14 @@ share_examples_for 'A serialization method' do
|
|
144
149
|
result = @harness.test(planet, :only => [:name], :exclude => [:name])
|
145
150
|
result.values_at("name", "aphelion").should == ["Mars", nil]
|
146
151
|
end
|
152
|
+
|
153
|
+
it 'should support child associations included via the :methods parameter' do
|
154
|
+
solar_system = SolarSystem.create(:name => "one")
|
155
|
+
planet = Planet.new(:name => "earth")
|
156
|
+
planet.solar_system = solar_system
|
157
|
+
result = @harness.test(planet, :methods => [:solar_system])
|
158
|
+
result['solar_system'].values_at('name', 'id').should == ['one', 1]
|
159
|
+
end
|
147
160
|
end
|
148
161
|
|
149
162
|
describe "(collections and proxies)" do
|
@@ -162,19 +175,24 @@ share_examples_for 'A serialization method' do
|
|
162
175
|
|
163
176
|
it 'should serialize a collection' do
|
164
177
|
query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
178
|
+
|
179
|
+
keys = %w[ id composite name breed ]
|
180
|
+
|
181
|
+
resources = [
|
182
|
+
keys.zip([ 1, 2, 'Betsy', 'Jersey' ]).to_hash,
|
183
|
+
keys.zip([ 10, 20, 'Berta', 'Guernsey' ]).to_hash,
|
184
|
+
]
|
185
|
+
|
186
|
+
collection = DataMapper::Collection.new(query, query.model.load(resources, query))
|
169
187
|
|
170
188
|
result = @harness.test(collection)
|
171
|
-
result[0].values_at(
|
172
|
-
result[1].values_at(
|
189
|
+
result[0].values_at(*keys).should == resources[0].values_at(*keys)
|
190
|
+
result[1].values_at(*keys).should == resources[1].values_at(*keys)
|
173
191
|
end
|
174
192
|
|
175
193
|
it 'should serialize an empty collection' do
|
176
194
|
query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
|
177
|
-
collection = DataMapper::Collection.new(query)
|
195
|
+
collection = DataMapper::Collection.new(query)
|
178
196
|
|
179
197
|
result = @harness.test(collection)
|
180
198
|
result.should be_empty
|
@@ -206,29 +224,40 @@ share_examples_for 'A serialization method' do
|
|
206
224
|
end
|
207
225
|
|
208
226
|
it "serializes a many to many relationship" do
|
209
|
-
|
210
|
-
|
227
|
+
pending 'TODO: fix many to many in dm-core' do
|
228
|
+
p1 = Planet.create(:name => 'earth')
|
229
|
+
p2 = Planet.create(:name => 'mars')
|
211
230
|
|
212
|
-
|
231
|
+
FriendedPlanet.create(:planet => p1, :friend_planet => p2)
|
213
232
|
|
214
|
-
|
215
|
-
|
233
|
+
result = @harness.test(p1.reload.friend_planets)
|
234
|
+
result.should be_kind_of(Array)
|
216
235
|
|
217
|
-
|
236
|
+
result[0]["name"].should == "mars"
|
237
|
+
end
|
218
238
|
end
|
219
239
|
end
|
220
240
|
|
221
241
|
describe "(multiple repositories)" do
|
222
242
|
before(:all) do
|
223
243
|
QuanTum::Cat.auto_migrate!
|
224
|
-
repository(:alternate){QuanTum::Cat.auto_migrate!}
|
244
|
+
DataMapper.repository(:alternate) { QuanTum::Cat.auto_migrate! }
|
225
245
|
end
|
226
246
|
|
227
247
|
it "should use the repsoitory for the model" do
|
228
248
|
gerry = QuanTum::Cat.create(:name => "gerry")
|
229
|
-
george = repository(:alternate){QuanTum::Cat.create(:name => "george", :is_dead => false)}
|
249
|
+
george = DataMapper.repository(:alternate){ QuanTum::Cat.create(:name => "george", :is_dead => false) }
|
230
250
|
@harness.test(gerry )['is_dead'].should be(nil)
|
231
251
|
@harness.test(george)['is_dead'].should be(false)
|
232
252
|
end
|
233
253
|
end
|
254
|
+
|
255
|
+
it 'should integrate with dm-validations' do
|
256
|
+
planet = Planet.create(:name => 'a')
|
257
|
+
results = @harness.test(planet.errors)
|
258
|
+
results.should == {
|
259
|
+
"name" => planet.errors[:name],
|
260
|
+
"solar_system_id" => planet.errors[:solar_system_id]
|
261
|
+
}
|
262
|
+
end
|
234
263
|
end
|
data/spec/public/to_csv_spec.rb
CHANGED
@@ -1,48 +1,62 @@
|
|
1
|
-
require '
|
2
|
-
require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
|
1
|
+
require 'spec_helper'
|
3
2
|
|
4
|
-
|
5
|
-
#
|
6
|
-
|
7
|
-
|
3
|
+
if defined?(::CSV)
|
4
|
+
describe DataMapper::Serialize, '#to_csv' do
|
5
|
+
#
|
6
|
+
# ==== blah, it's CSV
|
7
|
+
#
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
before(:all) do
|
10
|
+
query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
|
11
|
+
|
12
|
+
resources = [
|
13
|
+
{:id => 1, :composite => 2, :name => 'Betsy', :breed => 'Jersey'},
|
14
|
+
{:id => 10, :composite => 20, :name => 'Berta', :breed => 'Guernsey'}
|
15
|
+
]
|
16
|
+
|
17
|
+
@collection = DataMapper::Collection.new(query, resources)
|
11
18
|
|
12
|
-
|
13
|
-
c.load([1, 2, 'Betsy', 'Jersey'])
|
14
|
-
c.load([10, 20, 'Berta', 'Guernsey'])
|
19
|
+
@empty_collection = DataMapper::Collection.new(query)
|
15
20
|
end
|
16
21
|
|
17
|
-
|
18
|
-
|
22
|
+
it "should serialize a resource to CSV" do
|
23
|
+
peter = Cow.new
|
24
|
+
peter.id = 44
|
25
|
+
peter.composite = 344
|
26
|
+
peter.name = 'Peter'
|
27
|
+
peter.breed = 'Long Horn'
|
19
28
|
|
20
|
-
|
21
|
-
|
22
|
-
peter.id = 44
|
23
|
-
peter.composite = 344
|
24
|
-
peter.name = 'Peter'
|
25
|
-
peter.breed = 'Long Horn'
|
26
|
-
peter.to_csv.chomp.split(',')[0..3].should == ['44','344','Peter','Long Horn']
|
27
|
-
end
|
29
|
+
peter.to_csv.chomp.split(',')[0..3].should == ['44','344','Peter','Long Horn']
|
30
|
+
end
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
it "should serialize a collection to CSV" do
|
33
|
+
result = @collection.to_csv.gsub(/[[:space:]]+\n/, "\n")
|
34
|
+
result.split("\n")[0].split(',')[0..3].should == ['1','2','Betsy','Jersey']
|
35
|
+
result.split("\n")[1].split(',')[0..3].should == ['10','20','Berta','Guernsey']
|
36
|
+
end
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
38
|
+
it 'should integration with dm-validations by providing one line per error' do
|
39
|
+
planet = Planet.create(:name => 'a')
|
40
|
+
result = planet.errors.to_csv.gsub(/[[:space:]]+\n/, "\n").split("\n")
|
41
|
+
result.should include("name,#{planet.errors[:name][0]}")
|
42
|
+
result.should include("solar_system_id,#{planet.errors[:solar_system_id][0]}")
|
43
|
+
result.length.should == 2
|
39
44
|
end
|
40
45
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
+
describe "multiple repositories" do
|
47
|
+
before(:all) do
|
48
|
+
QuanTum::Cat.auto_migrate!
|
49
|
+
DataMapper.repository(:alternate){ QuanTum::Cat.auto_migrate! }
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should use the repsoitory for the model" do
|
53
|
+
gerry = QuanTum::Cat.create(:name => "gerry")
|
54
|
+
george = DataMapper.repository(:alternate){ QuanTum::Cat.create(:name => "george", :is_dead => false) }
|
55
|
+
gerry.to_csv.should_not match(/false/)
|
56
|
+
george.to_csv.should match(/false/)
|
57
|
+
end
|
46
58
|
end
|
47
59
|
end
|
60
|
+
else
|
61
|
+
warn "[WARNING] Cannot require 'faster_csv' or 'csv', not running #to_csv specs"
|
48
62
|
end
|