ardm-serializer 1.2.2
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 +35 -0
- data/.travis.yml +11 -0
- data/Gemfile +81 -0
- data/LICENSE +20 -0
- data/README.rdoc +64 -0
- data/Rakefile +4 -0
- data/ardm-serializer.gemspec +28 -0
- data/benchmarks/to_json.rb +137 -0
- data/benchmarks/to_xml.rb +89 -0
- data/lib/ardm-serializer.rb +1 -0
- data/lib/dm-serializer.rb +14 -0
- data/lib/dm-serializer/common.rb +28 -0
- data/lib/dm-serializer/to_csv.rb +71 -0
- data/lib/dm-serializer/to_json.rb +103 -0
- data/lib/dm-serializer/to_xml.rb +126 -0
- data/lib/dm-serializer/to_yaml.rb +160 -0
- data/lib/dm-serializer/version.rb +5 -0
- data/lib/dm-serializer/xml.rb +56 -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/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 +290 -0
- data/spec/public/serializer_spec.rb +7 -0
- data/spec/public/to_csv_spec.rb +72 -0
- data/spec/public/to_json_spec.rb +75 -0
- data/spec/public/to_xml_spec.rb +110 -0
- data/spec/public/to_yaml_spec.rb +59 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +26 -0
- data/tasks/spec.rake +38 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +185 -0
@@ -0,0 +1 @@
|
|
1
|
+
require 'dm-serializer'
|
@@ -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,28 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Serializer
|
5
|
+
|
6
|
+
# Returns propreties to serialize based on :only or :exclude arrays,
|
7
|
+
# if provided :only takes precendence over :exclude
|
8
|
+
#
|
9
|
+
# @return [Array]
|
10
|
+
# Properties that need to be serialized.
|
11
|
+
def properties_to_serialize(options)
|
12
|
+
only_properties = Array(options[:only])
|
13
|
+
excluded_properties = Array(options[:exclude])
|
14
|
+
|
15
|
+
model.properties(repository.name).reject do |p|
|
16
|
+
if only_properties.include? p.name
|
17
|
+
false
|
18
|
+
else
|
19
|
+
excluded_properties.include?(p.name) ||
|
20
|
+
!(only_properties.empty? ||
|
21
|
+
only_properties.include?(p.name))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Model.append_inclusions(Serializer)
|
28
|
+
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.has_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.has_key? :writer
|
38
|
+
|
39
|
+
CSV.generate(options[:writer]) do |csv|
|
40
|
+
errors.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,103 @@
|
|
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.kind_of?(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
|
+
result[method] = __send__(method)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Note: if you want to include a whole other model via relation, use
|
35
|
+
# :methods:
|
36
|
+
#
|
37
|
+
# comments.to_json(:relationships=>{:user=>{:include=>[:first_name],:methods=>[:age]}})
|
38
|
+
#
|
39
|
+
# TODO: This needs tests and also needs to be ported to #to_xml and
|
40
|
+
# #to_yaml
|
41
|
+
if options[:relationships]
|
42
|
+
options[:relationships].each do |relationship_name, opts|
|
43
|
+
if respond_to?(relationship_name)
|
44
|
+
result[relationship_name] = __send__(relationship_name).to_json(opts.merge(:to_json => false))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
result
|
50
|
+
end
|
51
|
+
|
52
|
+
# Serialize a Resource to JavaScript Object Notation (JSON; RFC 4627)
|
53
|
+
#
|
54
|
+
# @return <String> a JSON representation of the Resource
|
55
|
+
def to_json(*args)
|
56
|
+
options = args.first
|
57
|
+
options = {} unless options.kind_of?(Hash)
|
58
|
+
|
59
|
+
result = as_json(options)
|
60
|
+
|
61
|
+
# default to making JSON
|
62
|
+
if options.fetch(:to_json, true)
|
63
|
+
MultiJson.encode(result)
|
64
|
+
else
|
65
|
+
result
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module ValidationErrors
|
70
|
+
module ToJson
|
71
|
+
def to_json(*args)
|
72
|
+
MultiJson.encode(Hash[ errors ])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
class Collection
|
80
|
+
def to_json(*args)
|
81
|
+
options = args.first
|
82
|
+
options = {} unless options.kind_of?(Hash)
|
83
|
+
|
84
|
+
resource_options = options.merge(:to_json => false)
|
85
|
+
collection = map { |resource| resource.to_json(resource_options) }
|
86
|
+
|
87
|
+
# default to making JSON
|
88
|
+
if options.fetch(:to_json, true)
|
89
|
+
MultiJson.encode(collection)
|
90
|
+
else
|
91
|
+
collection
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
if const_defined?(:Validations)
|
97
|
+
module Validations
|
98
|
+
class ValidationErrors
|
99
|
+
include DataMapper::Serializer::ValidationErrors::ToJson
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,126 @@
|
|
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
|
+
unless property.primitive == String
|
41
|
+
attrs['type'] = property.primitive.to_s.downcase
|
42
|
+
end
|
43
|
+
|
44
|
+
xml.add_node(root, property.name.to_s, value, attrs)
|
45
|
+
end
|
46
|
+
|
47
|
+
Array(opts[:methods]).each do |meth|
|
48
|
+
if self.respond_to?(meth)
|
49
|
+
xml_name = meth.to_s.gsub(/[^a-z0-9_]/, '')
|
50
|
+
value = __send__(meth)
|
51
|
+
|
52
|
+
unless value.nil?
|
53
|
+
if value.respond_to?(:to_xml_document)
|
54
|
+
xml.add_xml(root, value.to_xml_document)
|
55
|
+
else
|
56
|
+
xml.add_node(root, xml_name, value.to_s)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
doc
|
63
|
+
end
|
64
|
+
|
65
|
+
module ValidationErrors
|
66
|
+
module ToXml
|
67
|
+
def to_xml(opts = {})
|
68
|
+
to_xml_document(opts).to_s
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_xml_document(opts = {})
|
72
|
+
xml = DataMapper::Serializer::XML.serializer
|
73
|
+
doc = xml.new_document
|
74
|
+
root = xml.root_node(doc, "errors", {'type' => 'hash'})
|
75
|
+
|
76
|
+
errors.each do |key, value|
|
77
|
+
property = xml.add_node(root, key.to_s, nil, {'type' => 'array'})
|
78
|
+
property.attributes["type"] = 'array'
|
79
|
+
|
80
|
+
value.each do |error|
|
81
|
+
xml.add_node(property, "error", error)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
doc
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
class Collection
|
93
|
+
def to_xml(opts = {})
|
94
|
+
to_xml_document(opts).to_s
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_xml_document(opts = {})
|
98
|
+
xml = DataMapper::Serializer::XML.serializer
|
99
|
+
doc = xml.new_document
|
100
|
+
|
101
|
+
default_collection_element_name = lambda {
|
102
|
+
DataMapper::Inflector.pluralize(DataMapper::Inflector.underscore(self.model.to_s)).tr("/", "-")
|
103
|
+
}
|
104
|
+
|
105
|
+
root = xml.root_node(
|
106
|
+
doc,
|
107
|
+
opts[:collection_element_name] || default_collection_element_name[],
|
108
|
+
{'type' => 'array'}
|
109
|
+
)
|
110
|
+
|
111
|
+
self.each do |item|
|
112
|
+
item.to_xml_document(opts, doc)
|
113
|
+
end
|
114
|
+
|
115
|
+
doc
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
if const_defined?(:Validations)
|
120
|
+
module Validations
|
121
|
+
class ValidationErrors
|
122
|
+
include DataMapper::Serializer::ValidationErrors::ToXml
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,160 @@
|
|
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
|
+
def to_yaml(options = {})
|
31
|
+
YAML.quick_emit(object_id, options) do |out|
|
32
|
+
out.map(to_yaml_type, to_yaml_style) do |map|
|
33
|
+
encode_with(map, options.kind_of?(Hash) ? options : {})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end unless YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
|
37
|
+
|
38
|
+
# A callback to encode the resource in the YAML stream
|
39
|
+
#
|
40
|
+
# @param [#add] coder
|
41
|
+
# handles adding the values to the output
|
42
|
+
#
|
43
|
+
# @param [Hash] options
|
44
|
+
# optional Hash configuring the output
|
45
|
+
#
|
46
|
+
# @return [undefined]
|
47
|
+
#
|
48
|
+
# @api public
|
49
|
+
def encode_with(coder, options = {})
|
50
|
+
coder.tag = to_yaml_type if coder.respond_to?(:tag=)
|
51
|
+
coder.style = to_yaml_style if coder.respond_to?(:style=)
|
52
|
+
|
53
|
+
methods = []
|
54
|
+
|
55
|
+
methods.concat properties_to_serialize(options).map { |property| property.name }
|
56
|
+
methods.concat Array(options[:methods])
|
57
|
+
|
58
|
+
methods.each do |method|
|
59
|
+
coder.add(method.to_s, __send__(method))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# Return the YAML type to use for the output
|
66
|
+
#
|
67
|
+
# @return [String]
|
68
|
+
#
|
69
|
+
# @api private
|
70
|
+
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
|
+
def to_yaml_style
|
80
|
+
Psych::Nodes::Mapping::ANY
|
81
|
+
end if YAML.const_defined?(:ENGINE) && YAML::ENGINE.yamler == 'psych'
|
82
|
+
|
83
|
+
module ValidationErrors
|
84
|
+
module ToYaml
|
85
|
+
|
86
|
+
# Serialize the errors to YAML
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# yaml = errors.to_yaml # => a valid YAML string
|
90
|
+
#
|
91
|
+
# @param [Hash] options
|
92
|
+
#
|
93
|
+
# @return [String]
|
94
|
+
#
|
95
|
+
# @api public
|
96
|
+
def to_yaml(*args)
|
97
|
+
Hash[errors].to_yaml(*args)
|
98
|
+
end
|
99
|
+
|
100
|
+
# A callback to encode the errors in the YAML stream
|
101
|
+
#
|
102
|
+
# @param [#add] coder
|
103
|
+
# handles adding the values to the output
|
104
|
+
#
|
105
|
+
# @return [undefined]
|
106
|
+
#
|
107
|
+
# @api public
|
108
|
+
def encode_with(coder)
|
109
|
+
coder.map = Hash[errors]
|
110
|
+
end
|
111
|
+
|
112
|
+
end # module ToYaml
|
113
|
+
end # module ValidationErrors
|
114
|
+
|
115
|
+
module Collection
|
116
|
+
module ToYaml
|
117
|
+
|
118
|
+
# Serialize the collection to YAML
|
119
|
+
#
|
120
|
+
# @example
|
121
|
+
# yaml = collection.to_yaml # => a valid YAML string
|
122
|
+
#
|
123
|
+
# @param [Hash] options
|
124
|
+
#
|
125
|
+
# @return [String]
|
126
|
+
#
|
127
|
+
# @api public
|
128
|
+
def to_yaml(*args)
|
129
|
+
to_a.to_yaml(*args)
|
130
|
+
end
|
131
|
+
|
132
|
+
# A callback to encode the collection in the YAML stream
|
133
|
+
#
|
134
|
+
# @param [#add] coder
|
135
|
+
# handles adding the values to the output
|
136
|
+
#
|
137
|
+
# @return [undefined]
|
138
|
+
#
|
139
|
+
# @api public
|
140
|
+
def encode_with(coder)
|
141
|
+
coder.seq = to_a
|
142
|
+
end
|
143
|
+
|
144
|
+
end # module ToYaml
|
145
|
+
end # module Collection
|
146
|
+
end # module Serializer
|
147
|
+
|
148
|
+
class Collection
|
149
|
+
include Serializer::Collection::ToYaml
|
150
|
+
end # class Collection
|
151
|
+
|
152
|
+
if const_defined?(:Validations)
|
153
|
+
module Validations
|
154
|
+
class ValidationErrors
|
155
|
+
include DataMapper::Serializer::ValidationErrors::ToYaml
|
156
|
+
end # class ValidationErrors
|
157
|
+
end # module Validations
|
158
|
+
end
|
159
|
+
|
160
|
+
end # module DataMapper
|