csverizer 0.0.6 → 0.0.7
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 +4 -4
- data/lib/active_model/csv_array_serializer.rb +10 -16
- data/lib/active_model/csverizer.rb +298 -35
- data/lib/active_model/csverizer/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55eee804461744dce24ad41fccb06203f0eb9788849cedfd22ddbf3188398394
|
4
|
+
data.tar.gz: 2468a5c68cec4beca7fbe0d8c71f52dc81e2b129fb4c59b54653f37816fca595
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59abeb2c9a6a7eeb91d1d15bfddeb69914fc67c2eed7d6647ed4c76f4186b39f3d1834e60bdef3d21e626cdbb3b658ce1985a02afd0d3db4b76c847a1a71d094
|
7
|
+
data.tar.gz: d4e4531e84adc53d16fda163fc83743ad97d7f5de0f9f820862233b9f326671591832d2c32d84779bbc852e00868acbbadee873ad3a3544e654771a29754114a
|
@@ -9,25 +9,19 @@ module ActiveModel
|
|
9
9
|
@options = options
|
10
10
|
end
|
11
11
|
|
12
|
-
def to_a
|
13
|
-
return ActiveModel::Csverizer.new(nil).to_a if @objects.nil?
|
14
|
-
@objects.collect do |object|
|
15
|
-
serializer = @each_serializer || ActiveModel::CsverizerFactory
|
16
|
-
serializer.new(object, @options).to_a
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
12
|
def to_csv
|
13
|
+
serializer = @each_serializer || ActiveModel::CsverizerFactory
|
14
|
+
serializer = serializer.new(@objects.first, @options)
|
15
|
+
options_hash = @options.slice(:serializer)
|
16
|
+
|
21
17
|
CSV.generate do |csv|
|
22
|
-
csv << attribute_names
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
18
|
+
csv << serializer.attribute_names
|
19
|
+
serializer = @each_serializer || ActiveModel::CsverizerFactory
|
26
20
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
21
|
+
@objects.each do |record|
|
22
|
+
serializer.new(record, options_hash).to_a.each { |record| csv << record }
|
23
|
+
end
|
24
|
+
end
|
31
25
|
end
|
32
26
|
end
|
33
27
|
end
|
@@ -2,44 +2,316 @@ require 'csv'
|
|
2
2
|
|
3
3
|
module ActiveModel
|
4
4
|
class Csverizer
|
5
|
-
@
|
6
|
-
@associations = []
|
7
|
-
@root = true
|
5
|
+
@mutex = Mutex.new
|
8
6
|
|
9
7
|
class << self
|
10
|
-
|
8
|
+
def inherited(base)
|
9
|
+
base._root = _root
|
10
|
+
base._attributes = (_attributes || []).dup
|
11
|
+
base._associations = (_associations || {}).dup
|
12
|
+
end
|
13
|
+
|
14
|
+
def setup
|
15
|
+
@mutex.synchronize do
|
16
|
+
yield CONFIG
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
EMBED_IN_ROOT_OPTIONS = [
|
21
|
+
:include,
|
22
|
+
:embed_in_root,
|
23
|
+
:embed_in_root_key,
|
24
|
+
:embed_namespace
|
25
|
+
].freeze
|
26
|
+
|
27
|
+
def embed(type, options={})
|
28
|
+
CONFIG.embed = type
|
29
|
+
if EMBED_IN_ROOT_OPTIONS.any? { |opt| options[opt].present? }
|
30
|
+
CONFIG.embed_in_root = true
|
31
|
+
end
|
32
|
+
if options[:embed_in_root_key].present?
|
33
|
+
CONFIG.embed_in_root_key = options[:embed_in_root_key]
|
34
|
+
end
|
35
|
+
ActiveSupport::Deprecation.warn <<-WARN
|
36
|
+
** Notice: embed is deprecated. **
|
37
|
+
The use of .embed method on a Serializer will be soon removed, as this should have a global scope and not a class scope.
|
38
|
+
Please use the global .setup method instead:
|
39
|
+
ActiveModel::Serializer.setup do |config|
|
40
|
+
config.embed = :#{type}
|
41
|
+
config.embed_in_root = #{CONFIG.embed_in_root || false}
|
42
|
+
end
|
43
|
+
WARN
|
44
|
+
end
|
45
|
+
|
46
|
+
def format_keys(format)
|
47
|
+
@key_format = format
|
48
|
+
end
|
49
|
+
attr_reader :key_format
|
50
|
+
|
51
|
+
def serializer_for(resource, options = {})
|
52
|
+
if resource.respond_to?(:serializer_class)
|
53
|
+
resource.serializer_class
|
54
|
+
elsif resource.respond_to?(:to_ary)
|
55
|
+
if Object.constants.include?(:ArraySerializer)
|
56
|
+
::ArraySerializer
|
57
|
+
else
|
58
|
+
ArraySerializer
|
59
|
+
end
|
60
|
+
else
|
61
|
+
klass_name = build_serializer_class(resource, options)
|
62
|
+
Serializer.serializers_cache.fetch_or_store(klass_name) do
|
63
|
+
_const_get(klass_name)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
attr_accessor :_root, :_attributes, :_associations
|
69
|
+
alias root _root=
|
70
|
+
alias root= _root=
|
71
|
+
|
72
|
+
def root_name
|
73
|
+
if name
|
74
|
+
root_name = name.demodulize.underscore.sub(/_serializer$/, '')
|
75
|
+
CONFIG.plural_default_root ? root_name.pluralize : root_name
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def attributes(*attrs)
|
80
|
+
attrs.each do |attr|
|
81
|
+
striped_attr = strip_attribute attr
|
82
|
+
|
83
|
+
@_attributes << striped_attr
|
84
|
+
|
85
|
+
define_method striped_attr do
|
86
|
+
object.read_attribute_for_serialization attr
|
87
|
+
end unless method_defined?(attr)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def has_one(*attrs)
|
92
|
+
associate(Association::HasOne, *attrs)
|
93
|
+
end
|
94
|
+
|
95
|
+
def has_many(*attrs)
|
96
|
+
associate(Association::HasMany, *attrs)
|
97
|
+
end
|
98
|
+
|
99
|
+
def serializers_cache
|
100
|
+
@serializers_cache ||= Concurrent::Map.new
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def strip_attribute(attr)
|
106
|
+
symbolized = attr.is_a?(Symbol)
|
107
|
+
|
108
|
+
attr = attr.to_s.gsub(/\?\Z/, '')
|
109
|
+
attr = attr.to_sym if symbolized
|
110
|
+
attr
|
111
|
+
end
|
112
|
+
|
113
|
+
def build_serializer_class(resource, options)
|
114
|
+
"".tap do |klass_name|
|
115
|
+
klass_name << "#{options[:namespace]}::" if options[:namespace]
|
116
|
+
klass_name << options[:prefix].to_s.classify if options[:prefix]
|
117
|
+
klass_name << "#{resource.class.name}Serializer"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def associate(klass, *attrs)
|
122
|
+
options = attrs.extract_options!
|
123
|
+
|
124
|
+
attrs.each do |attr|
|
125
|
+
define_method attr do
|
126
|
+
object.send attr
|
127
|
+
end unless method_defined?(attr)
|
128
|
+
|
129
|
+
@_associations[attr] = klass.new(attr, options)
|
130
|
+
end
|
131
|
+
end
|
11
132
|
end
|
12
133
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
|
134
|
+
def initialize(object, options={})
|
135
|
+
@object = object
|
136
|
+
@scope = options[:scope]
|
137
|
+
@root = options.fetch(:root, self.class._root)
|
138
|
+
@polymorphic = options.fetch(:polymorphic, false)
|
139
|
+
@meta_key = options[:meta_key] || :meta
|
140
|
+
@meta = options[@meta_key]
|
141
|
+
@wrap_in_array = options[:_wrap_in_array]
|
142
|
+
@only = options[:only] ? Array(options[:only]) : nil
|
143
|
+
@except = options[:except] ? Array(options[:except]) : nil
|
144
|
+
@key_format = options[:key_format]
|
145
|
+
@context = options[:context]
|
146
|
+
@namespace = options[:namespace]
|
147
|
+
@prefix = options.fetch(:prefix, '')
|
148
|
+
end
|
149
|
+
attr_accessor :object, :scope, :root, :meta_key, :meta, :key_format, :context, :polymorphic
|
150
|
+
|
151
|
+
def json_key
|
152
|
+
key = if root == true || root.nil?
|
153
|
+
self.class.root_name
|
154
|
+
else
|
155
|
+
root
|
156
|
+
end
|
157
|
+
|
158
|
+
key_format == :lower_camel && key.present? ? key.camelize(:lower) : key
|
17
159
|
end
|
18
160
|
|
19
|
-
def
|
20
|
-
|
161
|
+
def attributes
|
162
|
+
filter(self.class._attributes.dup).each_with_object({}) do |name, hash|
|
163
|
+
hash[name] = send(name)
|
164
|
+
end
|
21
165
|
end
|
22
166
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
167
|
+
def associations(options={})
|
168
|
+
associations = self.class._associations
|
169
|
+
included_associations = filter(associations.keys)
|
170
|
+
associations.each_with_object({}) do |(name, association), hash|
|
171
|
+
if included_associations.include? name
|
172
|
+
if association.embed_ids?
|
173
|
+
ids = serialize_ids association
|
174
|
+
if association.embed_namespace?
|
175
|
+
hash = hash[association.embed_namespace] ||= {}
|
176
|
+
hash[association.key] = ids
|
177
|
+
else
|
178
|
+
hash[association.key] = ids
|
179
|
+
end
|
180
|
+
elsif association.embed_objects?
|
181
|
+
if association.embed_namespace?
|
182
|
+
hash = hash[association.embed_namespace] ||= {}
|
183
|
+
end
|
184
|
+
hash[association.embedded_key] = serialize association, options
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
28
188
|
end
|
29
189
|
|
30
|
-
def
|
31
|
-
@
|
32
|
-
|
33
|
-
|
34
|
-
|
190
|
+
def filter(keys)
|
191
|
+
if @only
|
192
|
+
keys & @only
|
193
|
+
elsif @except
|
194
|
+
keys - @except
|
195
|
+
else
|
196
|
+
keys
|
197
|
+
end
|
35
198
|
end
|
36
199
|
|
37
|
-
|
200
|
+
def embedded_in_root_associations
|
201
|
+
associations = self.class._associations
|
202
|
+
included_associations = filter(associations.keys)
|
203
|
+
associations.each_with_object({}) do |(name, association), hash|
|
204
|
+
if included_associations.include? name
|
205
|
+
association_serializer = build_serializer(association)
|
206
|
+
# we must do this always because even if the current association is not
|
207
|
+
# embedded in root, it might have its own associations that are embedded in root
|
208
|
+
hash.merge!(association_serializer.embedded_in_root_associations) do |key, oldval, newval|
|
209
|
+
if oldval.respond_to?(:to_ary)
|
210
|
+
[oldval, newval].flatten.uniq
|
211
|
+
else
|
212
|
+
oldval.merge(newval) { |_, oldval, newval| [oldval, newval].flatten.uniq }
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
if association.embed_in_root?
|
217
|
+
if association.embed_in_root_key?
|
218
|
+
hash = hash[association.embed_in_root_key] ||= {}
|
219
|
+
end
|
38
220
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
221
|
+
serialized_data = association_serializer.serializable_object
|
222
|
+
key = association.root_key
|
223
|
+
if hash.has_key?(key)
|
224
|
+
hash[key].concat(serialized_data).uniq!
|
225
|
+
else
|
226
|
+
hash[key] = serialized_data
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def build_serializer(association)
|
234
|
+
object = send(association.name)
|
235
|
+
association.build_serializer(object, association_options_for_serializer(association))
|
236
|
+
end
|
237
|
+
|
238
|
+
def association_options_for_serializer(association)
|
239
|
+
prefix = association.options[:prefix]
|
240
|
+
namespace = association.options[:namespace] || @namespace || self.namespace
|
241
|
+
|
242
|
+
{ scope: scope }.tap do |opts|
|
243
|
+
opts[:namespace] = namespace if namespace
|
244
|
+
opts[:prefix] = prefix if prefix
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def serialize(association,options={})
|
249
|
+
build_serializer(association).serializable_object(options)
|
250
|
+
end
|
251
|
+
|
252
|
+
def serialize_ids(association)
|
253
|
+
associated_data = send(association.name)
|
254
|
+
if associated_data.respond_to?(:to_ary)
|
255
|
+
associated_data.map { |elem| serialize_id(elem, association) }
|
256
|
+
else
|
257
|
+
serialize_id(associated_data, association) if associated_data
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def key_format
|
262
|
+
@key_format || self.class.key_format || CONFIG.key_format
|
263
|
+
end
|
264
|
+
|
265
|
+
def format_key(key)
|
266
|
+
if key_format == :lower_camel
|
267
|
+
key.to_s.camelize(:lower)
|
268
|
+
else
|
269
|
+
key
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def convert_keys(hash)
|
274
|
+
Hash[hash.map do |k,v|
|
275
|
+
key = if k.is_a?(Symbol)
|
276
|
+
format_key(k).to_sym
|
277
|
+
else
|
278
|
+
format_key(k)
|
279
|
+
end
|
280
|
+
|
281
|
+
[key ,v]
|
282
|
+
end]
|
283
|
+
end
|
284
|
+
|
285
|
+
attr_writer :serialization_options
|
286
|
+
def serialization_options
|
287
|
+
@serialization_options || {}
|
288
|
+
end
|
289
|
+
|
290
|
+
def serializable_object(options={})
|
291
|
+
self.serialization_options = options
|
292
|
+
return @wrap_in_array ? [] : nil if @object.nil?
|
293
|
+
hash = attributes
|
294
|
+
hash.merge! associations(options)
|
295
|
+
hash = convert_keys(hash) if key_format.present?
|
296
|
+
hash = { :type => type_name(@object), type_name(@object) => hash } if @polymorphic
|
297
|
+
@wrap_in_array ? [hash] : hash
|
298
|
+
end
|
299
|
+
alias_method :serializable_hash, :serializable_object
|
300
|
+
|
301
|
+
def serialize_id(elem, association)
|
302
|
+
id = elem.read_attribute_for_serialization(association.embed_key)
|
303
|
+
association.polymorphic? ? { id: id, type: type_name(elem) } : id
|
304
|
+
end
|
305
|
+
|
306
|
+
def type_name(elem)
|
307
|
+
elem.class.to_s.demodulize.underscore.to_sym
|
308
|
+
end
|
309
|
+
|
310
|
+
def to_csv
|
311
|
+
CSV.generate do |csv|
|
312
|
+
csv << attribute_names
|
313
|
+
to_a.each { |record| csv << record }
|
314
|
+
end
|
43
315
|
end
|
44
316
|
|
45
317
|
def to_a
|
@@ -55,13 +327,6 @@ module ActiveModel
|
|
55
327
|
values
|
56
328
|
end
|
57
329
|
|
58
|
-
def to_csv
|
59
|
-
CSV.generate do |csv|
|
60
|
-
csv << attribute_names if @root
|
61
|
-
to_a.each { |record| csv << record }
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
330
|
def attribute_names
|
66
331
|
names = self.class._attributes.collect do |attribute|
|
67
332
|
@prefix + attribute.to_s
|
@@ -71,8 +336,6 @@ module ActiveModel
|
|
71
336
|
end
|
72
337
|
end
|
73
338
|
|
74
|
-
private
|
75
|
-
|
76
339
|
def read_attribute(name)
|
77
340
|
return send(name) if respond_to?(name)
|
78
341
|
object.read_attribute_for_serialization(name)
|
@@ -83,7 +346,7 @@ module ActiveModel
|
|
83
346
|
end
|
84
347
|
|
85
348
|
def associated_serializers
|
86
|
-
@associated_serializers ||= self.class.
|
349
|
+
@associated_serializers ||= self.class._associations.collect do |hash|
|
87
350
|
object = read_attribute(hash[:associated])
|
88
351
|
hash[:serializer].new(object, prefix: hash[:associated].to_s + '_')
|
89
352
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csverizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Cunningham
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-05-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|