sbf-dm-serializer 1.3.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +38 -0
- data/.rspec +5 -0
- data/.rubocop.yml +468 -0
- data/Gemfile +80 -0
- data/LICENSE +20 -0
- data/README.rdoc +64 -0
- data/Rakefile +4 -0
- data/benchmarks/to_json.rb +137 -0
- data/benchmarks/to_xml.rb +89 -0
- data/dm-serializer.gemspec +24 -0
- data/lib/dm-serializer/common.rb +27 -0
- data/lib/dm-serializer/to_csv.rb +71 -0
- data/lib/dm-serializer/to_json.rb +99 -0
- data/lib/dm-serializer/to_xml.rb +123 -0
- data/lib/dm-serializer/to_yaml.rb +157 -0
- data/lib/dm-serializer/version.rb +5 -0
- data/lib/dm-serializer/xml/libxml.rb +44 -0
- data/lib/dm-serializer/xml/nokogiri.rb +44 -0
- data/lib/dm-serializer/xml/rexml.rb +36 -0
- data/lib/dm-serializer/xml.rb +56 -0
- data/lib/dm-serializer.rb +14 -0
- data/spec/fixtures/cow.rb +11 -0
- data/spec/fixtures/planet.rb +46 -0
- data/spec/fixtures/quan_tum_cat.rb +15 -0
- data/spec/fixtures/vehicle.rb +14 -0
- data/spec/lib/serialization_method_shared_spec.rb +287 -0
- data/spec/public/serializer_spec.rb +7 -0
- data/spec/public/to_csv_spec.rb +71 -0
- data/spec/public/to_json_spec.rb +75 -0
- data/spec/public/to_xml_spec.rb +108 -0
- data/spec/public/to_yaml_spec.rb +59 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec_helper.rb +26 -0
- data/tasks/spec.rake +21 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +139 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require 'pathname'
|
3
|
+
require 'better-benchmark'
|
4
|
+
|
5
|
+
gem 'dm-core', '1.0.0'
|
6
|
+
require 'dm-core'
|
7
|
+
|
8
|
+
spec_dir_path = Pathname(__FILE__).dirname.expand_path
|
9
|
+
$LOAD_PATH.unshift(spec_dir_path.parent + 'lib/')
|
10
|
+
require 'dm-serializer'
|
11
|
+
|
12
|
+
def load_driver(name, default_uri)
|
13
|
+
begin
|
14
|
+
DataMapper.setup(name, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
|
15
|
+
DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[name]
|
16
|
+
DataMapper::Repository.adapters[:alternate] = DataMapper::Repository.adapters[name]
|
17
|
+
true
|
18
|
+
rescue LoadError => e
|
19
|
+
warn "Could not load do_#{name}: #{e}"
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
HAS_SQLITE3 = load_driver(:sqlite3, 'sqlite3::memory:')
|
25
|
+
|
26
|
+
module DataMapper
|
27
|
+
module Serialize
|
28
|
+
# Serialize a Resource to JavaScript Object Notation (JSON; RFC 4627)
|
29
|
+
#
|
30
|
+
# @return <String> a JSON representation of the Resource
|
31
|
+
def to_json_old(*args)
|
32
|
+
options = args.first || {}
|
33
|
+
result = '{ '
|
34
|
+
fields = []
|
35
|
+
|
36
|
+
propset = properties_to_serialize(options)
|
37
|
+
|
38
|
+
fields += propset.map do |property|
|
39
|
+
"#{property.name.to_json}: #{send(property.name).to_json}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# add methods
|
43
|
+
(options[:methods] || []).each do |meth|
|
44
|
+
if self.respond_to?(meth)
|
45
|
+
fields << "#{meth.to_json}: #{send(meth).to_json}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Note: if you want to include a whole other model via relation, use :methods
|
50
|
+
# comments.to_json(:relationships=>{:user=>{:include=>[:first_name],:methods=>[:age]}})
|
51
|
+
# add relationships
|
52
|
+
# TODO: This needs tests and also needs to be ported to #to_xml and #to_yaml
|
53
|
+
(options[:relationships] || {}).each do |rel,opts|
|
54
|
+
if self.respond_to?(rel)
|
55
|
+
fields << "#{rel.to_json}: #{send(rel).to_json(opts)}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
result << fields.join(', ')
|
60
|
+
result << ' }'
|
61
|
+
result
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Collection
|
66
|
+
def to_json_old(*args)
|
67
|
+
opts = args.first || {}
|
68
|
+
'[' << map { |e| e.to_json_old(opts) }.join(',') << ']'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
class Cow
|
77
|
+
include DataMapper::Resource
|
78
|
+
|
79
|
+
property :id, Integer, :key => true
|
80
|
+
property :composite, Integer, :key => true
|
81
|
+
property :name, String
|
82
|
+
property :breed, String
|
83
|
+
|
84
|
+
has n, :baby_cows, :model => 'Cow'
|
85
|
+
belongs_to :mother_cow, :model => 'Cow', :required => false
|
86
|
+
end
|
87
|
+
|
88
|
+
DataMapper.auto_migrate!
|
89
|
+
cow = Cow.create(
|
90
|
+
:id => 89,
|
91
|
+
:composite => 34,
|
92
|
+
:name => 'Berta',
|
93
|
+
:breed => 'Guernsey'
|
94
|
+
)
|
95
|
+
|
96
|
+
10.times do |n|
|
97
|
+
Cow.create(
|
98
|
+
:id => n*10,
|
99
|
+
:composite => n,
|
100
|
+
:name => "Bertha"*n,
|
101
|
+
:breed => "Mooing#{n}"
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
all_cows = Cow.all.reload
|
106
|
+
|
107
|
+
puts "Benchmarking single resource serialization."
|
108
|
+
puts "Set 1: old method"
|
109
|
+
puts "Set 2: new method"
|
110
|
+
result = Benchmark.compare_realtime(
|
111
|
+
:iterations => 10,
|
112
|
+
:inner_iterations => 20000,
|
113
|
+
:verbose => true
|
114
|
+
) { |iteration|
|
115
|
+
cow.to_json_old
|
116
|
+
}.with { |iteration|
|
117
|
+
cow.to_json
|
118
|
+
}
|
119
|
+
|
120
|
+
Benchmark.report_on result
|
121
|
+
|
122
|
+
puts
|
123
|
+
|
124
|
+
puts "Benchmarking collection serialization."
|
125
|
+
puts "Set 1: old method"
|
126
|
+
puts "Set 2: new method"
|
127
|
+
result = Benchmark.compare_realtime(
|
128
|
+
:iterations => 10,
|
129
|
+
:inner_iterations => 5000,
|
130
|
+
:verbose => true
|
131
|
+
) { |iteration|
|
132
|
+
all_cows.to_json_old
|
133
|
+
}.with { |iteration|
|
134
|
+
all_cows.to_json
|
135
|
+
}
|
136
|
+
|
137
|
+
Benchmark.report_on result
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
gem 'dm-core', '1.0.0'
|
5
|
+
require 'dm-core'
|
6
|
+
|
7
|
+
spec_dir_path = Pathname(__FILE__).dirname.expand_path
|
8
|
+
$LOAD_PATH.unshift(spec_dir_path.parent + 'lib/')
|
9
|
+
require 'dm-serializer'
|
10
|
+
|
11
|
+
def load_driver(name, default_uri)
|
12
|
+
begin
|
13
|
+
DataMapper.setup(name, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
|
14
|
+
DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[name]
|
15
|
+
DataMapper::Repository.adapters[:alternate] = DataMapper::Repository.adapters[name]
|
16
|
+
true
|
17
|
+
rescue LoadError => e
|
18
|
+
warn "Could not load do_#{name}: #{e}"
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
HAS_SQLITE3 = load_driver(:sqlite3, 'sqlite3::memory:')
|
24
|
+
|
25
|
+
class Cow
|
26
|
+
include DataMapper::Resource
|
27
|
+
|
28
|
+
property :id, Integer, :key => true
|
29
|
+
property :composite, Integer, :key => true
|
30
|
+
property :name, String
|
31
|
+
property :breed, String
|
32
|
+
|
33
|
+
has n, :baby_cows, :model => 'Cow'
|
34
|
+
belongs_to :mother_cow, :model => 'Cow'
|
35
|
+
end
|
36
|
+
|
37
|
+
require "benchwarmer"
|
38
|
+
|
39
|
+
TIMES = 2000
|
40
|
+
DataMapper.auto_migrate!
|
41
|
+
cow = Cow.create(
|
42
|
+
:id => 89,
|
43
|
+
:composite => 34,
|
44
|
+
:name => 'Berta',
|
45
|
+
:breed => 'Guernsey'
|
46
|
+
)
|
47
|
+
all_cows = Cow.all
|
48
|
+
|
49
|
+
puts "REXML"
|
50
|
+
Benchmark.warmer(TIMES) do
|
51
|
+
group("Serialization:") do
|
52
|
+
report "Single Resource" do
|
53
|
+
cow.to_xml
|
54
|
+
end
|
55
|
+
report "Collection" do
|
56
|
+
all_cows.to_xml
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
require 'nokogiri'
|
62
|
+
load 'dm-serializer/xml_serializers.rb'
|
63
|
+
|
64
|
+
puts "Nokogiri"
|
65
|
+
Benchmark.warmer(TIMES) do
|
66
|
+
group("Serialization:") do
|
67
|
+
report "Single Resource" do
|
68
|
+
cow.to_xml
|
69
|
+
end
|
70
|
+
report "Collection" do
|
71
|
+
all_cows.to_xml
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
require 'libxml'
|
77
|
+
load 'dm-serializer/xml_serializers.rb'
|
78
|
+
|
79
|
+
puts "LibXML"
|
80
|
+
Benchmark.warmer(TIMES) do
|
81
|
+
group("Serialization:") do
|
82
|
+
report "Single Resource" do
|
83
|
+
cow.to_xml
|
84
|
+
end
|
85
|
+
report "Collection" do
|
86
|
+
all_cows.to_xml
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.expand_path('../lib/dm-serializer/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.authors = ['Guy van den Berg', 'Dan Kubb']
|
5
|
+
gem.email = ['dan.kubb@gmail.com']
|
6
|
+
gem.summary = 'DataMapper plugin for serializing Resources and Collections'
|
7
|
+
gem.description = 'dm-serializer allows DataMapper models and collections to be serialized to a variety of formats ' \
|
8
|
+
'(currently JSON, XML, YAML and CSV)'
|
9
|
+
gem.license = 'Nonstandard'
|
10
|
+
gem.homepage = 'https://datamapper.org'
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.extra_rdoc_files = %w(LICENSE README.rdoc)
|
14
|
+
|
15
|
+
gem.name = 'sbf-dm-serializer'
|
16
|
+
gem.require_paths = ['lib']
|
17
|
+
gem.version = DataMapper::Serializer::VERSION
|
18
|
+
gem.required_ruby_version = '>= 2.7'
|
19
|
+
|
20
|
+
gem.add_runtime_dependency('sbf-dm-core', '~> 1.3.0.beta')
|
21
|
+
gem.add_runtime_dependency('fastercsv', '~> 1.5.4')
|
22
|
+
gem.add_runtime_dependency('multi_json', '~> 1.3.2')
|
23
|
+
gem.add_runtime_dependency('rexml', '~> 3.2')
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Serializer
|
5
|
+
# Returns properties to serialize based on :only or :exclude arrays,
|
6
|
+
# if provided :only takes precedence over :exclude
|
7
|
+
#
|
8
|
+
# @return [Array]
|
9
|
+
# Properties that need to be serialized.
|
10
|
+
def properties_to_serialize(options)
|
11
|
+
only_properties = Array(options[:only])
|
12
|
+
excluded_properties = Array(options[:exclude])
|
13
|
+
|
14
|
+
model.properties(repository.name).reject do |p|
|
15
|
+
if only_properties.include? p.name
|
16
|
+
false
|
17
|
+
else
|
18
|
+
excluded_properties.include?(p.name) ||
|
19
|
+
!(only_properties.empty? ||
|
20
|
+
only_properties.include?(p.name))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Model.append_inclusions(Serializer)
|
27
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'dm-serializer/common'
|
2
|
+
|
3
|
+
if RUBY_VERSION >= '1.9.0'
|
4
|
+
require 'csv'
|
5
|
+
else
|
6
|
+
begin
|
7
|
+
require 'fastercsv'
|
8
|
+
CSV = FasterCSV
|
9
|
+
rescue LoadError
|
10
|
+
# do nothing
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module DataMapper
|
15
|
+
module Serializer
|
16
|
+
# Serialize a Resource to comma-separated values (CSV).
|
17
|
+
#
|
18
|
+
# @return <String> a CSV representation of the Resource
|
19
|
+
def to_csv(*args)
|
20
|
+
options = args.first || {}
|
21
|
+
options = options.to_h if options.respond_to?(:to_h)
|
22
|
+
options[:writer] = '' unless options.key? :writer
|
23
|
+
|
24
|
+
CSV.generate(options[:writer]) do |csv|
|
25
|
+
row = properties_to_serialize(options).map do |property|
|
26
|
+
__send__(property.name).to_s
|
27
|
+
end
|
28
|
+
csv << row
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module ValidationErrors
|
33
|
+
module ToCsv
|
34
|
+
def to_csv(*args)
|
35
|
+
options = args.first || {}
|
36
|
+
options = options.to_h if options.respond_to?(:to_h)
|
37
|
+
options[:writer] = '' unless options.key? :writer
|
38
|
+
|
39
|
+
CSV.generate(options[:writer]) do |csv|
|
40
|
+
violations.each do |key, value|
|
41
|
+
value.each do |error|
|
42
|
+
row = []
|
43
|
+
row << key.to_s
|
44
|
+
row << error.to_s
|
45
|
+
csv << row
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Collection
|
55
|
+
def to_csv(*args)
|
56
|
+
result = ''
|
57
|
+
each do |item|
|
58
|
+
result << ("#{item.to_csv(args.first)}\n")
|
59
|
+
end
|
60
|
+
result
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
if const_defined?(:Validations)
|
65
|
+
module Validations
|
66
|
+
class ValidationErrors
|
67
|
+
include DataMapper::Serializer::ValidationErrors::ToCsv
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'dm-serializer/common'
|
2
|
+
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
module DataMapper
|
6
|
+
module Serializer
|
7
|
+
#
|
8
|
+
# Converts the resource into a hash of properties.
|
9
|
+
#
|
10
|
+
# @param [Hash] options
|
11
|
+
# Additional options.
|
12
|
+
#
|
13
|
+
# @return [Hash{String => String}]
|
14
|
+
# The hash of resources properties.
|
15
|
+
#
|
16
|
+
# @since 1.0.1
|
17
|
+
#
|
18
|
+
def as_json(options = {})
|
19
|
+
options = {} if options.nil?
|
20
|
+
result = {}
|
21
|
+
|
22
|
+
properties_to_serialize(options).each do |property|
|
23
|
+
property_name = property.name
|
24
|
+
value = __send__(property_name)
|
25
|
+
result[property_name] = value.is_a?(DataMapper::Model) ? value.name : value
|
26
|
+
end
|
27
|
+
|
28
|
+
# add methods
|
29
|
+
Array(options[:methods]).each do |method|
|
30
|
+
next unless respond_to?(method)
|
31
|
+
|
32
|
+
result[method] = __send__(method)
|
33
|
+
end
|
34
|
+
|
35
|
+
# NOTE: if you want to include a whole other model via relation, use
|
36
|
+
# :methods:
|
37
|
+
#
|
38
|
+
# comments.to_json(:relationships=>{:user=>{:include=>[:first_name],:methods=>[:age]}})
|
39
|
+
#
|
40
|
+
# TODO: This needs tests and also needs to be ported to #to_xml and
|
41
|
+
# #to_yaml
|
42
|
+
options[:relationships]&.each do |relationship_name, opts|
|
43
|
+
result[relationship_name] = __send__(relationship_name).to_json(opts.merge(to_json: false)) if respond_to?(relationship_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
result
|
47
|
+
end
|
48
|
+
|
49
|
+
# Serialize a Resource to JavaScript Object Notation (JSON; RFC 4627)
|
50
|
+
#
|
51
|
+
# @return <String> a JSON representation of the Resource
|
52
|
+
def to_json(*args)
|
53
|
+
options = args.first
|
54
|
+
options = {} unless options.is_a?(Hash)
|
55
|
+
|
56
|
+
result = as_json(options)
|
57
|
+
|
58
|
+
# default to making JSON
|
59
|
+
if options.fetch(:to_json, true)
|
60
|
+
MultiJson.dump(result)
|
61
|
+
else
|
62
|
+
result
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module ValidationErrors
|
67
|
+
module ToJson
|
68
|
+
def to_json(*_args)
|
69
|
+
MultiJson.dump(violations.to_h)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class Collection
|
76
|
+
def to_json(*args)
|
77
|
+
options = args.first
|
78
|
+
options = {} unless options.is_a?(Hash)
|
79
|
+
|
80
|
+
resource_options = options.merge(to_json: false)
|
81
|
+
collection = map { |resource| resource.to_json(resource_options) }
|
82
|
+
|
83
|
+
# default to making JSON
|
84
|
+
if options.fetch(:to_json, true)
|
85
|
+
MultiJson.dump(collection)
|
86
|
+
else
|
87
|
+
collection
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
if const_defined?(:Validations)
|
93
|
+
module Validations
|
94
|
+
class ValidationErrors
|
95
|
+
include DataMapper::Serializer::ValidationErrors::ToJson
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'dm-serializer/common'
|
2
|
+
require 'dm-serializer/xml'
|
3
|
+
|
4
|
+
module DataMapper
|
5
|
+
module Serializer
|
6
|
+
# Serialize a Resource to XML.
|
7
|
+
#
|
8
|
+
# @return [LibXML::Document, Nokogiri::Document, REXML::Document]
|
9
|
+
# An XML representation of this Resource.
|
10
|
+
#
|
11
|
+
def to_xml(opts = {})
|
12
|
+
xml = XML.serializer
|
13
|
+
xml.output(to_xml_document(opts)).to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
# This method requires certain methods to be implemented in the
|
17
|
+
# individual serializer library subclasses:
|
18
|
+
#
|
19
|
+
# * new_document
|
20
|
+
# * root_node
|
21
|
+
# * add_property_node
|
22
|
+
# * add_node
|
23
|
+
def to_xml_document(opts = {}, doc = nil)
|
24
|
+
xml = XML.serializer
|
25
|
+
doc ||= xml.new_document
|
26
|
+
|
27
|
+
default_xml_element_name = lambda {
|
28
|
+
DataMapper::Inflector.underscore(model.name).tr('/', '-')
|
29
|
+
}
|
30
|
+
|
31
|
+
root = xml.root_node(
|
32
|
+
doc,
|
33
|
+
(opts[:element_name] || default_xml_element_name[])
|
34
|
+
)
|
35
|
+
|
36
|
+
properties_to_serialize(opts).each do |property|
|
37
|
+
value = __send__(property.name)
|
38
|
+
attrs = {}
|
39
|
+
|
40
|
+
dump_class = property.dump_class
|
41
|
+
attrs['type'] = dump_class.to_s.downcase unless dump_class == ::String
|
42
|
+
xml.add_node(root, property.name.to_s, value, attrs)
|
43
|
+
end
|
44
|
+
|
45
|
+
Array(opts[:methods]).each do |meth|
|
46
|
+
next unless respond_to?(meth)
|
47
|
+
|
48
|
+
xml_name = meth.to_s.gsub(/[^a-z0-9_]/, '')
|
49
|
+
value = __send__(meth)
|
50
|
+
|
51
|
+
unless value.nil?
|
52
|
+
if value.respond_to?(:to_xml_document)
|
53
|
+
xml.add_xml(root, value.to_xml_document)
|
54
|
+
else
|
55
|
+
xml.add_node(root, xml_name, value.to_s)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
doc
|
61
|
+
end
|
62
|
+
|
63
|
+
module ValidationErrors
|
64
|
+
module ToXml
|
65
|
+
def to_xml(opts = {})
|
66
|
+
to_xml_document(opts).to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_xml_document(_opts = {})
|
70
|
+
xml = DataMapper::Serializer::XML.serializer
|
71
|
+
doc = xml.new_document
|
72
|
+
root = xml.root_node(doc, 'errors', {'type' => 'hash'})
|
73
|
+
|
74
|
+
violations.each do |key, value|
|
75
|
+
property = xml.add_node(root, key.to_s, nil, {'type' => 'array'})
|
76
|
+
property.attributes['type'] = 'array'
|
77
|
+
|
78
|
+
value.each do |error|
|
79
|
+
xml.add_node(property, 'error', error)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
doc
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class Collection
|
90
|
+
def to_xml(opts = {})
|
91
|
+
to_xml_document(opts).to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_xml_document(opts = {})
|
95
|
+
xml = DataMapper::Serializer::XML.serializer
|
96
|
+
doc = xml.new_document
|
97
|
+
|
98
|
+
default_collection_element_name = lambda {
|
99
|
+
DataMapper::Inflector.pluralize(DataMapper::Inflector.underscore(model.to_s)).tr('/', '-')
|
100
|
+
}
|
101
|
+
|
102
|
+
xml.root_node(
|
103
|
+
doc,
|
104
|
+
opts[:collection_element_name] || default_collection_element_name[],
|
105
|
+
{'type' => 'array'}
|
106
|
+
)
|
107
|
+
|
108
|
+
each do |item|
|
109
|
+
item.to_xml_document(opts, doc)
|
110
|
+
end
|
111
|
+
|
112
|
+
doc
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
if const_defined?(:Validations)
|
117
|
+
module Validations
|
118
|
+
class ValidationErrors
|
119
|
+
include DataMapper::Serializer::ValidationErrors::ToXml
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|