sbf-dm-serializer 1.3.0.beta
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.
- 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,157 @@
|
|
1
|
+
require 'dm-serializer/common'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Serializer
|
5
|
+
TAG_NAME = "ruby/DataMapper,#{DataMapper::VERSION}".freeze
|
6
|
+
|
7
|
+
# Include a callback to register the YAML output
|
8
|
+
#
|
9
|
+
# @param [DataMapper::Model] descendant
|
10
|
+
#
|
11
|
+
# @return [undefined]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
def self.included(descendant)
|
15
|
+
YAML.add_domain_type(TAG_NAME, descendant.name) do |_tag, values|
|
16
|
+
values
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Serialize a Resource to YAML
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# yaml = resource.to_yaml # => a valid YAML string
|
24
|
+
#
|
25
|
+
# @param [Hash] options
|
26
|
+
#
|
27
|
+
# @return [String]
|
28
|
+
#
|
29
|
+
# @api public
|
30
|
+
unless YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
|
31
|
+
def to_yaml(options = {})
|
32
|
+
YAML.quick_emit(object_id, options) do |out|
|
33
|
+
out.map(to_yaml_type, to_yaml_style) do |map|
|
34
|
+
encode_with(map, options.is_a?(Hash) ? options : {})
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# A callback to encode the resource in the YAML stream
|
41
|
+
#
|
42
|
+
# @param [#add] coder
|
43
|
+
# handles adding the values to the output
|
44
|
+
#
|
45
|
+
# @param [Hash] options
|
46
|
+
# optional Hash configuring the output
|
47
|
+
#
|
48
|
+
# @return [undefined]
|
49
|
+
#
|
50
|
+
# @api public
|
51
|
+
def encode_with(coder, options = {})
|
52
|
+
coder.tag = to_yaml_type if coder.respond_to?(:tag=)
|
53
|
+
coder.style = to_yaml_style if coder.respond_to?(:style=)
|
54
|
+
|
55
|
+
methods = []
|
56
|
+
|
57
|
+
methods.concat(properties_to_serialize(options).map(&:name))
|
58
|
+
methods.concat Array(options[:methods])
|
59
|
+
|
60
|
+
methods.each do |method|
|
61
|
+
coder.add(method.to_s, __send__(method))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Return the YAML type to use for the output
|
66
|
+
#
|
67
|
+
# @return [String]
|
68
|
+
#
|
69
|
+
# @api private
|
70
|
+
private def to_yaml_type
|
71
|
+
"!#{TAG_NAME}:#{model.name}"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Return the YAML style to use for the output
|
75
|
+
#
|
76
|
+
# @return [Integer]
|
77
|
+
#
|
78
|
+
# @api private
|
79
|
+
if YAML.const_defined?(:ENGINE) && YAML::ENGINE.yamler == 'psych'
|
80
|
+
def to_yaml_style
|
81
|
+
Psych::Nodes::Mapping::ANY
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
module ValidationErrors
|
86
|
+
module ToYaml
|
87
|
+
# Serialize the errors to YAML
|
88
|
+
#
|
89
|
+
# @example
|
90
|
+
# yaml = errors.to_yaml # => a valid YAML string
|
91
|
+
#
|
92
|
+
# @param [Hash] args
|
93
|
+
#
|
94
|
+
# @return [String]
|
95
|
+
#
|
96
|
+
# @api public
|
97
|
+
def to_yaml(*args)
|
98
|
+
violations.to_h.to_yaml(*args)
|
99
|
+
end
|
100
|
+
|
101
|
+
# A callback to encode the errors in the YAML stream
|
102
|
+
#
|
103
|
+
# @param [#add] coder
|
104
|
+
# handles adding the values to the output
|
105
|
+
#
|
106
|
+
# @return [undefined]
|
107
|
+
#
|
108
|
+
# @api public
|
109
|
+
def encode_with(coder)
|
110
|
+
coder.map = errors.to_h
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
module Collection
|
116
|
+
module ToYaml
|
117
|
+
# Serialize the collection to YAML
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
# yaml = collection.to_yaml # => a valid YAML string
|
121
|
+
#
|
122
|
+
# @param [Hash] args
|
123
|
+
#
|
124
|
+
# @return [String]
|
125
|
+
#
|
126
|
+
# @api public
|
127
|
+
def to_yaml(*args)
|
128
|
+
to_a.to_yaml(*args)
|
129
|
+
end
|
130
|
+
|
131
|
+
# A callback to encode the collection in the YAML stream
|
132
|
+
#
|
133
|
+
# @param [#add] coder
|
134
|
+
# handles adding the values to the output
|
135
|
+
#
|
136
|
+
# @return [undefined]
|
137
|
+
#
|
138
|
+
# @api public
|
139
|
+
def encode_with(coder)
|
140
|
+
coder.seq = to_a
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class Collection
|
147
|
+
include Serializer::Collection::ToYaml
|
148
|
+
end
|
149
|
+
|
150
|
+
if const_defined?(:Validations)
|
151
|
+
module Validations
|
152
|
+
class ValidationErrors
|
153
|
+
include DataMapper::Serializer::ValidationErrors::ToYaml
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'libxml'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Serializer
|
5
|
+
module XML
|
6
|
+
module LibXML
|
7
|
+
def self.new_document
|
8
|
+
::LibXML::XML::Document.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.root_node(doc, name, attrs = {})
|
12
|
+
root = ::LibXML::XML::Node.new(name)
|
13
|
+
|
14
|
+
attrs.each do |attr_name, attr_val|
|
15
|
+
root[attr_name] = attr_val
|
16
|
+
end
|
17
|
+
|
18
|
+
doc.root.nil? ? doc.root = root : doc.root << root
|
19
|
+
root
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.add_node(parent, name, value, attrs = {})
|
23
|
+
value_str = value.to_s unless value.nil?
|
24
|
+
node = ::LibXML::XML::Node.new(name, value_str)
|
25
|
+
|
26
|
+
attrs.each do |attr_name, attr_val|
|
27
|
+
node[attr_name] = attr_val
|
28
|
+
end
|
29
|
+
|
30
|
+
parent << node
|
31
|
+
node
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.add_xml(parent, xml)
|
35
|
+
parent << xml.root.copy(true)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.output(doc)
|
39
|
+
doc.root.to_s
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Serializer
|
5
|
+
module XML
|
6
|
+
module Nokogiri
|
7
|
+
def self.new_document
|
8
|
+
::Nokogiri::XML::Document.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.root_node(doc, name, attrs = {})
|
12
|
+
root = ::Nokogiri::XML::Node.new(name, doc)
|
13
|
+
|
14
|
+
attrs.each do |attr_name, attr_val|
|
15
|
+
root[attr_name] = attr_val
|
16
|
+
end
|
17
|
+
|
18
|
+
doc.root.nil? ? doc.root = root : doc.root << root
|
19
|
+
root
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.add_node(parent, name, value, attrs = {})
|
23
|
+
node = ::Nokogiri::XML::Node.new(name, parent.document)
|
24
|
+
node << ::Nokogiri::XML::Text.new(value.to_s, parent.document) unless value.nil?
|
25
|
+
|
26
|
+
attrs.each do |attr_name, attr_val|
|
27
|
+
node[attr_name] = attr_val
|
28
|
+
end
|
29
|
+
|
30
|
+
parent << node
|
31
|
+
node
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.add_xml(parent, xml)
|
35
|
+
parent << xml.root
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.output(doc)
|
39
|
+
doc.root.to_s
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Serializer
|
5
|
+
module XML
|
6
|
+
module REXML
|
7
|
+
def self.new_document
|
8
|
+
::REXML::Document.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.root_node(document, name, attrs = {})
|
12
|
+
add_node(document.root || document, name, nil, attrs)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.add_node(parent, name, value, attrs = {})
|
16
|
+
node = parent.add_element(name)
|
17
|
+
|
18
|
+
attrs.each do |attr_name, attr_val|
|
19
|
+
node.attributes[attr_name] = attr_val
|
20
|
+
end
|
21
|
+
|
22
|
+
node << ::REXML::Text.new(value.to_s) unless value.nil?
|
23
|
+
node
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.add_xml(parent, xml)
|
27
|
+
parent.add(xml)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.output(doc)
|
31
|
+
doc.to_s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Serializer
|
3
|
+
module XML
|
4
|
+
# The supported XML Serializers
|
5
|
+
SERIALIZERS = {
|
6
|
+
libxml: 'LibXML',
|
7
|
+
nokogiri: 'Nokogiri',
|
8
|
+
rexml: 'REXML'
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
#
|
12
|
+
# The current XML Serializer.
|
13
|
+
#
|
14
|
+
# @return [Module]
|
15
|
+
# The module within {DataMapper::Serialize::XML}.
|
16
|
+
#
|
17
|
+
# @since 1.1.0
|
18
|
+
#
|
19
|
+
def self.serializer
|
20
|
+
@serializer
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Sets the XML Serializer to use.
|
25
|
+
#
|
26
|
+
# @param [Symbol] name
|
27
|
+
# The name of the serializer to use. Must be either `:libxml`,
|
28
|
+
# `:nokogiri` or `:rexml`.
|
29
|
+
#
|
30
|
+
# @return [Module]
|
31
|
+
# The module within {DataMapper::Serialize::XML}.
|
32
|
+
#
|
33
|
+
# @since 1.1.0
|
34
|
+
#
|
35
|
+
def self.serializer=(name)
|
36
|
+
serializer_const = SERIALIZERS[name]
|
37
|
+
|
38
|
+
unless serializer_const
|
39
|
+
raise(ArgumentError,"unsupported XML Serializer #{name}")
|
40
|
+
end
|
41
|
+
|
42
|
+
require "dm-serializer/xml/#{name}"
|
43
|
+
@serializer = const_get(serializer_const)
|
44
|
+
end
|
45
|
+
|
46
|
+
%i(nokogiri libxml rexml).each do |name|
|
47
|
+
# attempt to load the first available XML Serializer
|
48
|
+
begin
|
49
|
+
self.serializer = name
|
50
|
+
break
|
51
|
+
rescue LoadError
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'dm-serializer/to_json'
|
2
|
+
require 'dm-serializer/to_xml'
|
3
|
+
require 'dm-serializer/to_yaml'
|
4
|
+
require 'dm-serializer/to_csv'
|
5
|
+
|
6
|
+
module DataMapper
|
7
|
+
# Define the `Serialize` constant for backwards compatibility.
|
8
|
+
#
|
9
|
+
# @note
|
10
|
+
# The `Serialize` constant will be removed soon, please use
|
11
|
+
# {Serializer} instead.
|
12
|
+
#
|
13
|
+
Serialize = Serializer
|
14
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Cow
|
2
|
+
include DataMapper::Resource
|
3
|
+
|
4
|
+
property :id, Integer, key: true
|
5
|
+
property :composite, Integer, key: true
|
6
|
+
property :name, String
|
7
|
+
property :breed, String
|
8
|
+
|
9
|
+
belongs_to :mother_cow, model: self, required: false
|
10
|
+
has n, :baby_cows, model: self, child_key: %i(mother_cow_id mother_cow_composite)
|
11
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Planet
|
2
|
+
include DataMapper::Resource
|
3
|
+
|
4
|
+
property :name, String, key: true
|
5
|
+
property :aphelion, Float
|
6
|
+
|
7
|
+
validates_length_of :name, min: 2
|
8
|
+
|
9
|
+
# Sorry these associations don't make any sense
|
10
|
+
# I just needed a many-to-many association to test against
|
11
|
+
has n, :friended_planets
|
12
|
+
has n, :friend_planets, through: :friended_planets, model: 'Planet'
|
13
|
+
|
14
|
+
belongs_to :solar_system
|
15
|
+
|
16
|
+
def category
|
17
|
+
case self.name.downcase
|
18
|
+
when 'mercury', 'venus', 'earth', 'mars' then 'terrestrial'
|
19
|
+
when 'jupiter', 'saturn', 'uranus', 'neptune' then 'gas giants'
|
20
|
+
when 'pluto' then 'dwarf planets'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_known_form_of_life?
|
25
|
+
self.name.downcase == 'earth'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class FriendedPlanet
|
30
|
+
include DataMapper::Resource
|
31
|
+
|
32
|
+
property :planet_name, String, key: true
|
33
|
+
property :friend_planet_name, String, key: true
|
34
|
+
|
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
|
+
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Yes, this crazy capitalization is intentional,
|
2
|
+
# to test xml root element name generation
|
3
|
+
module QuanTum
|
4
|
+
class Cat
|
5
|
+
include DataMapper::Resource
|
6
|
+
|
7
|
+
property :id, Serial
|
8
|
+
property :name, String
|
9
|
+
property :location, String
|
10
|
+
|
11
|
+
repository(:alternate) do
|
12
|
+
property :is_dead, Boolean
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|