delineate 0.6.1 → 0.6.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 +4 -4
- data/VERSION +1 -1
- data/delineate.gemspec +4 -3
- data/lib/delineate/attribute_map.rb +40 -98
- data/lib/delineate/map_attributes.rb +3 -1
- data/lib/delineate/resolve.rb +97 -0
- data/lib/delineate/serializers/csv_serializer.rb +7 -7
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6242128797a0959401231046cd088cf6c4d3cd5
|
4
|
+
data.tar.gz: 3c04565b00c65ee61c96c1f87b9154722060ef9f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5412696a28e4d9c40b97496ab6d5182943adbfb3b3b01e59bd4203d4ee47b4feef056f3348300cba91ba3990424ec83e932742e24b81b7635c2a848b21e07b5
|
7
|
+
data.tar.gz: 87587a174725ecd3d79a68abd1a38163ae1d3fc69a9b6e11d2dfa17e348340a5cbf9a713f0dc8000bddfd65f43a3f6e62cecc0584cd2adc359fdd7457836cc69
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.6.
|
1
|
+
0.6.2
|
data/delineate.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: delineate 0.6.
|
5
|
+
# stub: delineate 0.6.2 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "delineate"
|
9
|
-
s.version = "0.6.
|
9
|
+
s.version = "0.6.2"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Tom Smith"]
|
14
|
-
s.date = "2014-02-
|
14
|
+
s.date = "2014-02-28"
|
15
15
|
s.description = "ActiveRecord serializer DSL for mapping model attributes and associations. Similar to ActiveModel Serializers with many enhancements including bi-directional support, i.e. deserialization."
|
16
16
|
s.email = "tsmith@landfall.com"
|
17
17
|
s.extra_rdoc_files = [
|
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
|
|
34
34
|
"lib/delineate/attribute_map.rb",
|
35
35
|
"lib/delineate/map_attributes.rb",
|
36
36
|
"lib/delineate/map_serializer.rb",
|
37
|
+
"lib/delineate/resolve.rb",
|
37
38
|
"lib/delineate/schema.rb",
|
38
39
|
"lib/delineate/serialization.rb",
|
39
40
|
"lib/delineate/serializers/csv_serializer.rb",
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/hash/deep_dup.rb'
|
2
2
|
|
3
|
+
require 'delineate/resolve'
|
3
4
|
require 'delineate/serialization'
|
4
5
|
require 'delineate/schema'
|
5
6
|
|
@@ -222,12 +223,10 @@ module Delineate
|
|
222
223
|
@attributes[name] = options
|
223
224
|
|
224
225
|
model_attr = (options[:model_attr] || name).to_sym
|
225
|
-
model_attr = define_attr_methods(name, model_attr, options)
|
226
|
+
model_attr = define_attr_methods(name, model_attr, options)
|
226
227
|
|
227
228
|
if options[:access] != :ro
|
228
|
-
|
229
|
-
raise "Expected 'attr_accessible :#{model_attr}' in #{@klass_name}"
|
230
|
-
end
|
229
|
+
validate_attr_writable(model_attr)
|
231
230
|
@write_attributes[name] = model_attr
|
232
231
|
end
|
233
232
|
end
|
@@ -246,12 +245,7 @@ module Delineate
|
|
246
245
|
|
247
246
|
attr_map.instance_eval(&blk) if block_given?
|
248
247
|
|
249
|
-
|
250
|
-
raise ArgumentError, "Map association '#{name}' in class #{@klass_name} specifies :replace but has empty block"
|
251
|
-
end
|
252
|
-
if options[:access] != :ro and !klass.accessible_attributes.include?(model_attr.to_s+'_attributes')
|
253
|
-
raise "Expected attr_accessible and/or accepts_nested_attributes_for :#{model_attr} in #{@klass_name} model"
|
254
|
-
end
|
248
|
+
validate_assoc_map(name, model_attr, attr_map, options)
|
255
249
|
|
256
250
|
@associations[name] = {:klass_name => reflection.class_name, :options => options,
|
257
251
|
:attr_map => attr_map.empty? ? nil : attr_map,
|
@@ -263,7 +257,7 @@ module Delineate
|
|
263
257
|
return if other_attr_map.nil?
|
264
258
|
|
265
259
|
@attributes = @attributes.deep_merge(other_attr_map.attributes)
|
266
|
-
@associations.deep_merge
|
260
|
+
@associations = @associations.deep_merge(other_attr_map.associations)
|
267
261
|
|
268
262
|
@write_attributes = {:_destroy => :_destroy}
|
269
263
|
@attributes.each {|k, v| @write_attributes[k] = (v[:model_attr] || k) unless v[:access] == :ro}
|
@@ -297,31 +291,6 @@ module Delineate
|
|
297
291
|
self
|
298
292
|
end
|
299
293
|
|
300
|
-
def resolved?
|
301
|
-
@resolved
|
302
|
-
end
|
303
|
-
|
304
|
-
# Will raise an exception of the map cannot be fully resolved
|
305
|
-
def resolve!
|
306
|
-
resolve(:must_resolve)
|
307
|
-
self
|
308
|
-
end
|
309
|
-
|
310
|
-
# Attempts to resolve the map and the maps it depends on. If must_resolve is truthy, will
|
311
|
-
# raise an exception if map cannot be resolved.
|
312
|
-
def resolve(must_resolve = false, resolving = [])
|
313
|
-
return true if @resolved
|
314
|
-
return true if resolving.include?(@klass_name) # prevent infinite recursion
|
315
|
-
|
316
|
-
resolving.push(@klass_name)
|
317
|
-
|
318
|
-
result = resolve_associations(must_resolve, resolving)
|
319
|
-
result = false unless resolve_sti_baseclass(must_resolve, resolving)
|
320
|
-
|
321
|
-
resolving.pop
|
322
|
-
@resolved = result
|
323
|
-
end
|
324
|
-
|
325
294
|
|
326
295
|
protected
|
327
296
|
|
@@ -354,8 +323,10 @@ module Delineate
|
|
354
323
|
raise ArgumentError, "Association '#{association}' in model #{@klass_name} is not defined" if reflection.nil?
|
355
324
|
begin
|
356
325
|
reflection.klass
|
357
|
-
rescue
|
358
|
-
|
326
|
+
rescue => e
|
327
|
+
msg = "Cannot resolve association class '#{reflection.class_name}' from model '#{@klass_name}'"
|
328
|
+
msg += "\n#{e.message}"
|
329
|
+
raise NameError, msg
|
359
330
|
end
|
360
331
|
end
|
361
332
|
end
|
@@ -384,7 +355,7 @@ module Delineate
|
|
384
355
|
validate_access_option(options[:access])
|
385
356
|
options[:model_attr] = options.delete(:using) if options.key?(:using)
|
386
357
|
|
387
|
-
raise ArgumentError, 'Cannot specify :override or provide block with :polymorphic' if options[:polymorphic]
|
358
|
+
raise ArgumentError, 'Cannot specify :override or provide block with :polymorphic' if options[:polymorphic] && (blk or options[:override])
|
388
359
|
raise ArgumentError, 'Option :override must = :replace or :merge' unless !options.key?(:override) || [:merge, :replace].include?(options[:override])
|
389
360
|
end
|
390
361
|
|
@@ -411,70 +382,37 @@ module Delineate
|
|
411
382
|
raise ArgumentError, 'Invalid value for :access option' if opt and !VALID_ACCESS_OPTIONS.include?(opt)
|
412
383
|
end
|
413
384
|
|
414
|
-
def
|
415
|
-
|
416
|
-
|
417
|
-
map
|
418
|
-
end
|
419
|
-
|
420
|
-
def resolve_associations(must_resolve, resolving)
|
421
|
-
result = true
|
422
|
-
|
423
|
-
@associations.each do |assoc_name, assoc|
|
424
|
-
if detect_circular_merge(assoc)
|
425
|
-
raise "Detected attribute map circular merge references: class=#{@klass_name}, association=#{assoc_name}"
|
426
|
-
end
|
427
|
-
|
428
|
-
assoc_map = assoc[:attr_map] || assoc[:klass_name].constantize.attribute_maps.try(:fetch, @name, nil)
|
429
|
-
if assoc_map && !assoc_map.resolved?
|
430
|
-
if assoc_map.resolve(must_resolve, resolving) && merge_option?(assoc[:options]) && assoc[:attr_map]
|
431
|
-
merge_map = assoc[:klass_name].constantize.attribute_maps[@name]
|
432
|
-
assoc_map = merge_map.dup.merge!(assoc_map, :with_options => true, :with_state => true)
|
433
|
-
end
|
434
|
-
end
|
435
|
-
assoc[:attr_map] = assoc_map
|
436
|
-
|
437
|
-
if assoc_map.nil? or !assoc_map.resolve(false, resolving)
|
438
|
-
result = false
|
439
|
-
raise "Cannot resolve map for association :#{assoc_name} in #{@klass_name}:#{@name} map" if must_resolve
|
440
|
-
end
|
385
|
+
def validate_attr_writable(attr_name)
|
386
|
+
if attr_name.to_s != klass.primary_key && !klass.accessible_attributes.detect { |a| a == attr_name.to_s }
|
387
|
+
raise "Expected 'attr_accessible :#{attr_name}' in #{@klass_name}"
|
441
388
|
end
|
442
|
-
|
443
|
-
result
|
444
389
|
end
|
445
390
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
if
|
451
|
-
|
452
|
-
@resolved = @sti_baseclass_merged = true
|
453
|
-
self.copy(klass.superclass.attribute_maps[@name].dup.merge!(self))
|
454
|
-
else
|
455
|
-
result = false
|
456
|
-
raise "Can't resolve base class map for #{@klass_name}:#{@name} map" if must_resolve
|
457
|
-
end
|
391
|
+
def validate_assoc_map(name, model_attr, attr_map, options)
|
392
|
+
if !merge_option?(options) && attr_map.empty?
|
393
|
+
raise ArgumentError, "Map association '#{name}' in class #{@klass_name} specifies :replace but has empty block"
|
394
|
+
end
|
395
|
+
if options[:access] != :ro and !klass.accessible_attributes.include?(model_attr.to_s+'_attributes')
|
396
|
+
raise "Expected attr_accessible and/or accepts_nested_attributes_for :#{model_attr} in #{@klass_name} model"
|
458
397
|
end
|
459
|
-
|
460
|
-
result
|
461
398
|
end
|
462
399
|
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
map.associations.each_value do |a|
|
470
|
-
return true if a[:klass_name] == @klass_name && merge_option?(a[:options]) && a[:attr_map]
|
471
|
-
end
|
400
|
+
def validate_attr_accessor(read_or_write, options)
|
401
|
+
return unless (accessor = options[read_or_write])
|
402
|
+
raise ArgumentError, "Invalid parameter for #{read_or_write}" unless (accessor.is_a?(Symbol) || accessor.is_a?(Proc))
|
403
|
+
accessor
|
404
|
+
end
|
472
405
|
|
473
|
-
|
406
|
+
def validate(map, class_name)
|
407
|
+
raise(NameError, "Expected attribute map :#{@name} to be defined for class '#{class_name}'") if map.nil?
|
408
|
+
map.resolve! unless map.resolved?
|
409
|
+
map
|
474
410
|
end
|
475
411
|
|
476
412
|
# Defines custom read/write attribute methods
|
477
413
|
def define_attr_methods(name, model_attr, options)
|
414
|
+
return model_attr if is_model_attr?(model_attr)
|
415
|
+
|
478
416
|
read_model_attr = define_attr_reader_method(name, model_attr, options)
|
479
417
|
write_model_attr = define_attr_writer_method(name, model_attr, options)
|
480
418
|
|
@@ -486,10 +424,9 @@ module Delineate
|
|
486
424
|
end
|
487
425
|
|
488
426
|
def define_attr_reader_method(name, model_attr, options)
|
489
|
-
return unless (reader =
|
490
|
-
raise ArgumentError, 'Invalid parameter for :read' unless (reader.is_a?(Symbol) || reader.is_a?(Proc))
|
427
|
+
return unless (reader = validate_attr_accessor(:read, options))
|
491
428
|
|
492
|
-
returning(
|
429
|
+
returning accessor_method_name(name, model_attr) do |method_name|
|
493
430
|
if reader.is_a?(Symbol)
|
494
431
|
klass.class_eval %(
|
495
432
|
def #{method_name}
|
@@ -511,10 +448,9 @@ module Delineate
|
|
511
448
|
end
|
512
449
|
|
513
450
|
def define_attr_writer_method(name, model_attr, options)
|
514
|
-
return unless (writer =
|
515
|
-
raise ArgumentError, 'Invalid parameter for :write' unless (writer.is_a?(Symbol) || writer.is_a?(Proc))
|
451
|
+
return unless (writer = validate_attr_accessor(:write, options))
|
516
452
|
|
517
|
-
returning(
|
453
|
+
returning accessor_method_name(name, model_attr) do |method_name|
|
518
454
|
if writer.is_a?(Symbol)
|
519
455
|
klass.class_eval %(
|
520
456
|
def #{method_name}=(value)
|
@@ -537,6 +473,12 @@ module Delineate
|
|
537
473
|
end
|
538
474
|
end
|
539
475
|
|
476
|
+
def accessor_method_name(name, model_attr)
|
477
|
+
model_attr == name ? "#{name}_#{@name}" : model_attr
|
478
|
+
end
|
479
|
+
|
480
|
+
|
481
|
+
include Resolve
|
540
482
|
include Serialization
|
541
483
|
include Schema
|
542
484
|
|
@@ -8,6 +8,7 @@ module ActiveRecord
|
|
8
8
|
|
9
9
|
# Collection of declared attribute maps for the model class
|
10
10
|
class_inheritable_accessor :attribute_maps
|
11
|
+
#class_attribute :attribute_maps
|
11
12
|
self.attribute_maps = {}
|
12
13
|
|
13
14
|
# The map_attributes method lets an ActiveRecord model class define a set
|
@@ -112,7 +113,7 @@ module ActiveRecord
|
|
112
113
|
end
|
113
114
|
|
114
115
|
def attribute_map(map_name)
|
115
|
-
self.class.
|
116
|
+
self.class.attribute_map(map_name)
|
116
117
|
end
|
117
118
|
|
118
119
|
# Returns the attributes as specified in the attribut map. The +format+ paramater
|
@@ -179,6 +180,7 @@ module ActiveRecord
|
|
179
180
|
raise "Base class for CTI subclass #{self.name} must specify attribute map #{map.name}" unless base_class_map
|
180
181
|
|
181
182
|
map.copy(base_class_map)
|
183
|
+
map.associations.delete_if {|k, a| a[:klass_name] == self.name}
|
182
184
|
map.instance_variable_set(:@resolved, false)
|
183
185
|
end
|
184
186
|
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Delineate
|
2
|
+
module Resolve
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
# Returns true if this map is fully resolved
|
6
|
+
def resolved?
|
7
|
+
@resolved
|
8
|
+
end
|
9
|
+
|
10
|
+
# Attempts to resolve this map and the maps it depends on, including declared associations.
|
11
|
+
# Will raise an exception if the map cannot be fully resolved.
|
12
|
+
def resolve!
|
13
|
+
resolve(:must_resolve)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
# Attempts to resolve this map and the maps it depends on, including declared associations,
|
18
|
+
# and returns success status as a boolean. If the +must_resolve+ parameter is truthy, raises
|
19
|
+
# raise an exception if the map cannot be fully resolved.
|
20
|
+
def resolve(must_resolve = false, resolving = [])
|
21
|
+
return true if @resolved
|
22
|
+
return true if resolving.include?(@klass_name) # prevent infinite recursion
|
23
|
+
|
24
|
+
resolving.push(@klass_name)
|
25
|
+
|
26
|
+
result = resolve_associations(must_resolve, resolving)
|
27
|
+
result = false unless resolve_sti_baseclass(must_resolve, resolving)
|
28
|
+
|
29
|
+
resolving.pop
|
30
|
+
@resolved = result
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Resolves association maps, and handles map merges as necessary
|
36
|
+
def resolve_associations(must_resolve, resolving)
|
37
|
+
result = true
|
38
|
+
|
39
|
+
@associations.each do |assoc_name, assoc|
|
40
|
+
detect_circular_merge!(assoc_name, assoc)
|
41
|
+
|
42
|
+
assoc_map = assoc[:attr_map] || assoc[:klass_name].constantize.attribute_maps.try(:fetch, @name, nil)
|
43
|
+
if assoc_map && assoc_map.resolve(must_resolve, resolving)
|
44
|
+
assoc_map = merge_assoc_map(assoc, assoc_map) if merge_option?(assoc[:options])
|
45
|
+
end
|
46
|
+
|
47
|
+
assoc[:attr_map] = assoc_map
|
48
|
+
|
49
|
+
if assoc_map.nil? or !assoc_map.resolve(false, resolving)
|
50
|
+
result = false
|
51
|
+
raise "Cannot resolve map for association :#{assoc_name} in #{@klass_name}:#{@name} map" if must_resolve
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
# If this is the map of an STI subclass, inherit/merge the map from the base class
|
59
|
+
def resolve_sti_baseclass(must_resolve, resolving)
|
60
|
+
result = true
|
61
|
+
|
62
|
+
if merge_option?(@options) && klass_sti_subclass? && !@sti_baseclass_merged
|
63
|
+
if klass.superclass.attribute_maps.try(:fetch, @name, nil).try(:resolve, must_resolve, resolving)
|
64
|
+
@resolved = @sti_baseclass_merged = true
|
65
|
+
self.copy(klass.superclass.attribute_maps[@name].dup.merge!(self))
|
66
|
+
else
|
67
|
+
result = false
|
68
|
+
raise "Can't resolve base class map for #{@klass_name}:#{@name} map" if must_resolve
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
result
|
73
|
+
end
|
74
|
+
|
75
|
+
# Raises exception if an association specifies a merge, and the association class's
|
76
|
+
# attribute map attempts to merge the association parent attribute map.
|
77
|
+
def detect_circular_merge!(assoc_name, assoc)
|
78
|
+
return if assoc.nil? || assoc[:attr_map].nil? || !merge_option?(assoc[:options])
|
79
|
+
return unless (map = assoc[:klass_name].constantize.attribute_maps.try(:fetch, @name, nil))
|
80
|
+
|
81
|
+
map.associations.each_value do |a|
|
82
|
+
if a[:klass_name] == @klass_name && merge_option?(a[:options]) && a[:attr_map]
|
83
|
+
raise "Detected attribute map circular merge references: class=#{@klass_name}, association=#{assoc_name}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def merge_assoc_map(assoc, assoc_map)
|
89
|
+
if merge_option?(assoc[:options]) && assoc[:attr_map]
|
90
|
+
merge_map = assoc[:klass_name].constantize.attribute_maps[@name]
|
91
|
+
assoc_map = merge_map.dup.merge!(assoc_map, :with_options => true, :with_state => true)
|
92
|
+
end
|
93
|
+
assoc_map
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
@@ -14,8 +14,8 @@ module Delineate
|
|
14
14
|
# of the attributes.
|
15
15
|
def serialize(options = {})
|
16
16
|
opts = options[:include_header] ?
|
17
|
-
{:write_headers => true, :headers => serializable_header, :encoding =>
|
18
|
-
{:encoding =>
|
17
|
+
{:write_headers => true, :headers => serializable_header, :encoding => 'UTF-8'} :
|
18
|
+
{:encoding => 'UTF-8'}
|
19
19
|
|
20
20
|
opts = remove_serializer_class_options(options).merge(opts)
|
21
21
|
opts.delete(:include_header)
|
@@ -27,18 +27,18 @@ module Delineate
|
|
27
27
|
|
28
28
|
# Returns the header row as a CSV string.
|
29
29
|
def serialize_header(options = {})
|
30
|
-
opts = {:encoding =>
|
30
|
+
opts = {:encoding => 'UTF-8'}.merge(remove_serializer_class_options(options))
|
31
31
|
CSV.generate_line(serializable_header, opts)
|
32
32
|
end
|
33
33
|
|
34
34
|
# Not implemented yet.
|
35
35
|
def serialize_in(csv_string, options = {})
|
36
|
-
raise
|
36
|
+
raise 'Serializing from CSV is not supported. You can inherit a class from CsvSerializer to write a custom importer.'
|
37
37
|
end
|
38
38
|
|
39
39
|
# Returns the record's mapped attributes in the serializer's "internal"
|
40
40
|
# format. For this class the representation is an array of one or more
|
41
|
-
# rows, one row for each item in
|
41
|
+
# rows, one row for each item in the record's has_many collections. Each
|
42
42
|
# row is an array of values ordered as follows:
|
43
43
|
#
|
44
44
|
# 1. All the record's mapped attributes in map order.
|
@@ -70,7 +70,7 @@ module Delineate
|
|
70
70
|
end
|
71
71
|
|
72
72
|
# Returns the header row as an array of strings, one for each
|
73
|
-
# mapped attribute, including nested
|
73
|
+
# mapped attribute, including nested associations. The items
|
74
74
|
# appear in the array in the same order as their corresponding
|
75
75
|
# attribute values.
|
76
76
|
def serializable_header(prefix = '')
|
@@ -93,7 +93,7 @@ module Delineate
|
|
93
93
|
|
94
94
|
private
|
95
95
|
|
96
|
-
# The diff here is that if the
|
96
|
+
# The diff here is that if the association record(s) is empty, we have to generate
|
97
97
|
# a new empty record: @record.class.new.build_xxx or @record.class.new.xxx.build
|
98
98
|
def add_includes(assoc_type)
|
99
99
|
includes = @options.delete(:include)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delineate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -147,6 +147,7 @@ files:
|
|
147
147
|
- lib/delineate/attribute_map.rb
|
148
148
|
- lib/delineate/map_attributes.rb
|
149
149
|
- lib/delineate/map_serializer.rb
|
150
|
+
- lib/delineate/resolve.rb
|
150
151
|
- lib/delineate/schema.rb
|
151
152
|
- lib/delineate/serialization.rb
|
152
153
|
- lib/delineate/serializers/csv_serializer.rb
|