dm-serializer 0.9.11 → 0.10.0
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/{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
|