blueprinter 0.26.0 → 0.30.0
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/CHANGELOG.md +55 -50
- data/README.md +17 -50
- data/Rakefile +13 -1
- data/lib/blueprinter/base.rb +10 -15
- data/lib/blueprinter/blueprinter_error.rb +2 -0
- data/lib/blueprinter/configuration.rb +14 -2
- data/lib/blueprinter/deprecation.rb +5 -3
- data/lib/blueprinter/empty_types.rb +7 -9
- data/lib/blueprinter/extractor.rb +6 -4
- data/lib/blueprinter/extractors/association_extractor.rb +8 -3
- data/lib/blueprinter/extractors/auto_extractor.rb +2 -0
- data/lib/blueprinter/extractors/block_extractor.rb +3 -1
- data/lib/blueprinter/extractors/hash_extractor.rb +2 -0
- data/lib/blueprinter/extractors/public_send_extractor.rb +3 -1
- data/lib/blueprinter/field.rb +44 -47
- data/lib/blueprinter/formatters/date_time_formatter.rb +3 -1
- data/lib/blueprinter/helpers/base_helpers.rb +17 -13
- data/lib/blueprinter/helpers/type_helpers.rb +5 -5
- data/lib/blueprinter/transformer.rb +4 -2
- data/lib/blueprinter/version.rb +3 -1
- data/lib/blueprinter/view.rb +8 -6
- data/lib/blueprinter/view_collection.rb +17 -12
- data/lib/blueprinter.rb +2 -0
- data/lib/generators/blueprinter/blueprint_generator.rb +37 -48
- data/lib/generators/blueprinter/templates/blueprint.rb +2 -0
- metadata +5 -173
- data/lib/tasks/blueprinter_tasks.rake +0 -4
data/lib/blueprinter/base.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'blueprinter_error'
|
2
4
|
require_relative 'configuration'
|
3
5
|
require_relative 'deprecation'
|
@@ -58,7 +60,7 @@ module Blueprinter
|
|
58
60
|
name,
|
59
61
|
extractor,
|
60
62
|
self,
|
61
|
-
block: block
|
63
|
+
block: block
|
62
64
|
)
|
63
65
|
end
|
64
66
|
|
@@ -123,7 +125,7 @@ module Blueprinter
|
|
123
125
|
options.fetch(:name) { method },
|
124
126
|
options.fetch(:extractor) { Blueprinter.configuration.extractor_default.new },
|
125
127
|
self,
|
126
|
-
options.merge(block: block)
|
128
|
+
options.merge(block: block)
|
127
129
|
)
|
128
130
|
end
|
129
131
|
|
@@ -163,7 +165,7 @@ module Blueprinter
|
|
163
165
|
method,
|
164
166
|
options.merge(
|
165
167
|
association: true,
|
166
|
-
extractor: options.fetch(:extractor) { AssociationExtractor.new }
|
168
|
+
extractor: options.fetch(:extractor) { AssociationExtractor.new }
|
167
169
|
),
|
168
170
|
&block
|
169
171
|
)
|
@@ -252,9 +254,7 @@ module Blueprinter
|
|
252
254
|
#
|
253
255
|
# @api private
|
254
256
|
def self.prepare(object, view_name:, local_options:, root: nil, meta: nil)
|
255
|
-
unless view_collection.
|
256
|
-
raise BlueprinterError, "View '#{view_name}' is not defined"
|
257
|
-
end
|
257
|
+
raise BlueprinterError, "View '#{view_name}' is not defined" unless view_collection.view? view_name
|
258
258
|
|
259
259
|
data = prepare_data(object, view_name, local_options)
|
260
260
|
prepend_root_and_meta(data, root, meta)
|
@@ -279,7 +279,6 @@ module Blueprinter
|
|
279
279
|
end
|
280
280
|
end
|
281
281
|
|
282
|
-
|
283
282
|
# Specify one transformer to be included for serialization.
|
284
283
|
# Takes a class which extends Blueprinter::Transformer
|
285
284
|
#
|
@@ -315,7 +314,6 @@ module Blueprinter
|
|
315
314
|
current_view.add_transformer(transformer)
|
316
315
|
end
|
317
316
|
|
318
|
-
|
319
317
|
# Specify another view that should be mixed into the current view.
|
320
318
|
#
|
321
319
|
# @param view_name [Symbol] the view to mix into the current view.
|
@@ -338,7 +336,6 @@ module Blueprinter
|
|
338
336
|
current_view.include_view(view_name)
|
339
337
|
end
|
340
338
|
|
341
|
-
|
342
339
|
# Specify additional views that should be mixed into the current view.
|
343
340
|
#
|
344
341
|
# @param view_name [Array<Symbol>] the views to mix into the current view.
|
@@ -361,12 +358,10 @@ module Blueprinter
|
|
361
358
|
#
|
362
359
|
# @return [Array<Symbol>] an array of view names.
|
363
360
|
|
364
|
-
|
365
361
|
def self.include_views(*view_names)
|
366
362
|
current_view.include_views(view_names)
|
367
363
|
end
|
368
364
|
|
369
|
-
|
370
365
|
# Exclude a field that was mixed into the current view.
|
371
366
|
#
|
372
367
|
# @param field_name [Symbol] the field to exclude from the current view.
|
@@ -444,13 +439,13 @@ module Blueprinter
|
|
444
439
|
# end
|
445
440
|
# end
|
446
441
|
#
|
447
|
-
# ExampleBlueprint.
|
448
|
-
# ExampleBlueprint.
|
442
|
+
# ExampleBlueprint.view?(:custom) => true
|
443
|
+
# ExampleBlueprint.view?(:doesnt_exist) => false
|
449
444
|
#
|
450
445
|
# @return [Boolean] a boolean value indicating if the view is
|
451
446
|
# supported by this Blueprint.
|
452
|
-
def self.
|
453
|
-
view_collection.
|
447
|
+
def self.view?(view_name)
|
448
|
+
view_collection.view? view_name
|
454
449
|
end
|
455
450
|
end
|
456
451
|
end
|
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blueprinter
|
2
4
|
class Configuration
|
3
|
-
attr_accessor :association_default, :datetime_format, :deprecations, :field_default, :generator, :if, :method,
|
5
|
+
attr_accessor :association_default, :datetime_format, :deprecations, :field_default, :generator, :if, :method,
|
6
|
+
:sort_fields_by, :unless, :extractor_default, :default_transformers, :custom_array_like_classes
|
4
7
|
|
5
|
-
VALID_CALLABLES = %i
|
8
|
+
VALID_CALLABLES = %i[if unless].freeze
|
6
9
|
|
7
10
|
def initialize
|
8
11
|
@deprecations = :stderror
|
@@ -16,6 +19,15 @@ module Blueprinter
|
|
16
19
|
@unless = nil
|
17
20
|
@extractor_default = AutoExtractor
|
18
21
|
@default_transformers = []
|
22
|
+
@custom_array_like_classes = []
|
23
|
+
end
|
24
|
+
|
25
|
+
def array_like_classes
|
26
|
+
@array_like_classes ||= [
|
27
|
+
Array,
|
28
|
+
defined?(ActiveRecord::Relation) && ActiveRecord::Relation,
|
29
|
+
*custom_array_like_classes
|
30
|
+
].compact
|
19
31
|
end
|
20
32
|
|
21
33
|
def jsonify(blob)
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# @api private
|
2
4
|
module Blueprinter
|
3
5
|
class Deprecation
|
4
6
|
class << self
|
5
|
-
VALID_BEHAVIORS = %i
|
6
|
-
MESSAGE_PREFIX =
|
7
|
+
VALID_BEHAVIORS = %i[silence stderror raise].freeze
|
8
|
+
MESSAGE_PREFIX = '[DEPRECATION::WARNING] Blueprinter:'
|
7
9
|
|
8
10
|
def report(message)
|
9
11
|
full_msg = qualified_message(message)
|
@@ -26,7 +28,7 @@ module Blueprinter
|
|
26
28
|
|
27
29
|
def behavior
|
28
30
|
configured = Blueprinter.configuration.deprecations
|
29
|
-
return configured
|
31
|
+
return configured if VALID_BEHAVIORS.include?(configured)
|
30
32
|
|
31
33
|
:stderror
|
32
34
|
end
|
@@ -1,12 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'helpers/type_helpers'
|
2
4
|
|
3
5
|
module Blueprinter
|
4
|
-
EMPTY_COLLECTION =
|
5
|
-
EMPTY_HASH =
|
6
|
-
EMPTY_STRING =
|
6
|
+
EMPTY_COLLECTION = 'empty_collection'
|
7
|
+
EMPTY_HASH = 'empty_hash'
|
8
|
+
EMPTY_STRING = 'empty_string'
|
7
9
|
|
8
10
|
module EmptyTypes
|
9
11
|
include TypeHelpers
|
12
|
+
|
10
13
|
private
|
11
14
|
|
12
15
|
def use_default_value?(value, empty_type)
|
@@ -18,12 +21,7 @@ module Blueprinter
|
|
18
21
|
when Blueprinter::EMPTY_HASH
|
19
22
|
value.is_a?(Hash) && value.empty?
|
20
23
|
when Blueprinter::EMPTY_STRING
|
21
|
-
value.to_s ==
|
22
|
-
else
|
23
|
-
Blueprinter::Deprecation.report(
|
24
|
-
"Invalid empty type '#{empty_type}' received. Blueprinter will raise an error in the next major version."\
|
25
|
-
"Must be one of [nil, Blueprinter::EMPTY_COLLECTION, Blueprinter::EMPTY_HASH, Blueprinter::EMPTY_STRING]"
|
26
|
-
)
|
24
|
+
value.to_s == ''
|
27
25
|
end
|
28
26
|
end
|
29
27
|
end
|
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blueprinter
|
2
4
|
class Extractor
|
3
|
-
def extract(_field_name, _object, _local_options, _options={})
|
4
|
-
|
5
|
+
def extract(_field_name, _object, _local_options, _options = {})
|
6
|
+
raise NotImplementedError, 'An Extractor must implement #extract'
|
5
7
|
end
|
6
8
|
|
7
|
-
def self.extract(field_name, object, local_options, options={})
|
8
|
-
|
9
|
+
def self.extract(field_name, object, local_options, options = {})
|
10
|
+
new.extract(field_name, object, local_options, options)
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blueprinter
|
2
4
|
# @api private
|
3
5
|
class AssociationExtractor < Extractor
|
@@ -7,12 +9,13 @@ module Blueprinter
|
|
7
9
|
@extractor = Blueprinter.configuration.extractor_default.new
|
8
10
|
end
|
9
11
|
|
10
|
-
def extract(association_name, object, local_options, options={})
|
11
|
-
options_without_default = options.reject { |k,_|
|
12
|
+
def extract(association_name, object, local_options, options = {})
|
13
|
+
options_without_default = options.reject { |k, _| %i[default default_if].include?(k) }
|
12
14
|
# Merge in assocation options hash
|
13
15
|
local_options = local_options.merge(options[:options]) if options[:options].is_a?(Hash)
|
14
16
|
value = @extractor.extract(association_name, object, local_options, options_without_default)
|
15
17
|
return default_value(options) if use_default_value?(value, options[:default_if])
|
18
|
+
|
16
19
|
view = options[:view] || :default
|
17
20
|
blueprint = association_blueprint(options[:blueprint], value)
|
18
21
|
blueprint.prepare(value, view_name: view, local_options: local_options)
|
@@ -21,7 +24,9 @@ module Blueprinter
|
|
21
24
|
private
|
22
25
|
|
23
26
|
def default_value(association_options)
|
24
|
-
association_options.
|
27
|
+
return association_options.fetch(:default) if association_options.key?(:default)
|
28
|
+
|
29
|
+
Blueprinter.configuration.association_default
|
25
30
|
end
|
26
31
|
|
27
32
|
def association_blueprint(blueprint, value)
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blueprinter
|
2
4
|
# @api private
|
3
5
|
class BlockExtractor < Extractor
|
4
|
-
def extract(
|
6
|
+
def extract(_field_name, object, local_options, options = {})
|
5
7
|
options[:block].call(object, local_options)
|
6
8
|
end
|
7
9
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blueprinter
|
2
4
|
# @api private
|
3
5
|
class PublicSendExtractor < Extractor
|
4
|
-
def extract(field_name, object,
|
6
|
+
def extract(field_name, object, _local_options, _options = {})
|
5
7
|
object.public_send(field_name)
|
6
8
|
end
|
7
9
|
end
|
data/lib/blueprinter/field.rb
CHANGED
@@ -1,63 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# @api private
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
module Blueprinter
|
5
|
+
class Field
|
6
|
+
attr_reader :method, :name, :extractor, :options, :blueprint
|
7
|
+
|
8
|
+
def initialize(method, name, extractor, blueprint, options = {})
|
9
|
+
@method = method
|
10
|
+
@name = name
|
11
|
+
@extractor = extractor
|
12
|
+
@blueprint = blueprint
|
13
|
+
@options = options
|
14
|
+
end
|
11
15
|
|
12
|
-
|
13
|
-
|
14
|
-
|
16
|
+
def extract(object, local_options)
|
17
|
+
extractor.extract(method, object, local_options, options)
|
18
|
+
end
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
unless_callable && unless_callable.call(field_name, object, local_options)
|
19
|
-
end
|
20
|
+
def skip?(field_name, object, local_options)
|
21
|
+
return true if if_callable && !if_callable.call(field_name, object, local_options)
|
20
22
|
|
21
|
-
|
23
|
+
unless_callable && unless_callable.call(field_name, object, local_options)
|
24
|
+
end
|
22
25
|
|
23
|
-
|
24
|
-
return @if_callable if defined?(@if_callable)
|
25
|
-
@if_callable = callable_from(:if)
|
26
|
-
end
|
26
|
+
private
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
@unless_callable = callable_from(:unless)
|
31
|
-
end
|
28
|
+
def if_callable
|
29
|
+
return @if_callable if defined?(@if_callable)
|
32
30
|
|
33
|
-
|
34
|
-
|
31
|
+
@if_callable = callable_from(:if)
|
32
|
+
end
|
33
|
+
|
34
|
+
def unless_callable
|
35
|
+
return @unless_callable if defined?(@unless_callable)
|
35
36
|
|
36
|
-
|
37
|
-
Blueprinter::Deprecation.report("`:#{condition}` conditions now expects 3 arguments instead of 2.")
|
38
|
-
->(_field_name, obj, options) { callable.call(obj, options) }
|
39
|
-
else
|
40
|
-
callable
|
37
|
+
@unless_callable = callable_from(:unless)
|
41
38
|
end
|
42
|
-
end
|
43
39
|
|
44
|
-
|
45
|
-
|
40
|
+
def callable_from(condition)
|
41
|
+
config = Blueprinter.configuration
|
46
42
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
43
|
+
# Use field-level callable, or when not defined, try global callable
|
44
|
+
tmp = if options.key?(condition)
|
45
|
+
options.fetch(condition)
|
46
|
+
elsif config.valid_callable?(condition)
|
47
|
+
config.public_send(condition)
|
48
|
+
end
|
53
49
|
|
54
|
-
|
50
|
+
return false unless tmp
|
55
51
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
52
|
+
case tmp
|
53
|
+
when Proc then tmp
|
54
|
+
when Symbol then blueprint.method(tmp)
|
55
|
+
else
|
56
|
+
raise ArgumentError, "#{tmp.class} is passed to :#{condition}"
|
57
|
+
end
|
61
58
|
end
|
62
59
|
end
|
63
60
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blueprinter
|
2
4
|
class DateTimeFormatter
|
3
5
|
InvalidDateTimeFormatterError = Class.new(BlueprinterError)
|
@@ -24,7 +26,7 @@ module Blueprinter
|
|
24
26
|
when Proc then format.call(value)
|
25
27
|
when String then value.strftime(format)
|
26
28
|
else
|
27
|
-
raise InvalidDateTimeFormatterError,
|
29
|
+
raise InvalidDateTimeFormatterError, "Cannot format DateTime object with invalid formatter: #{format.class}"
|
28
30
|
end
|
29
31
|
end
|
30
32
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blueprinter
|
2
4
|
module BaseHelpers
|
3
5
|
def self.included(base)
|
@@ -33,7 +35,8 @@ module Blueprinter
|
|
33
35
|
|
34
36
|
def prepend_root_and_meta(data, root, meta)
|
35
37
|
return data unless root
|
36
|
-
|
38
|
+
|
39
|
+
ret = { root => data }
|
37
40
|
meta ? ret.merge!(meta: meta) : ret
|
38
41
|
end
|
39
42
|
|
@@ -44,6 +47,7 @@ module Blueprinter
|
|
44
47
|
def object_to_hash(object, view_name:, local_options:)
|
45
48
|
result_hash = view_collection.fields_for(view_name).each_with_object({}) do |field, hash|
|
46
49
|
next if field.skip?(field.name, object, local_options)
|
50
|
+
|
47
51
|
hash[field.name] = field.extract(object, local_options)
|
48
52
|
end
|
49
53
|
view_collection.transformers(view_name).each do |transformer|
|
@@ -57,9 +61,9 @@ module Blueprinter
|
|
57
61
|
when String, Symbol
|
58
62
|
# no-op
|
59
63
|
when NilClass
|
60
|
-
raise BlueprinterError,
|
64
|
+
raise BlueprinterError, 'meta requires a root to be passed' if meta
|
61
65
|
else
|
62
|
-
raise BlueprinterError,
|
66
|
+
raise BlueprinterError, 'root should be one of String, Symbol, NilClass'
|
63
67
|
end
|
64
68
|
end
|
65
69
|
|
@@ -69,10 +73,10 @@ module Blueprinter
|
|
69
73
|
|
70
74
|
def validate_blueprint!(blueprint, method)
|
71
75
|
validate_presence_of_blueprint!(blueprint)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
+
return if dynamic_blueprint?(blueprint)
|
77
|
+
|
78
|
+
validate_blueprint_has_ancestors!(blueprint, method)
|
79
|
+
validate_blueprint_has_blueprinter_base_ancestor!(blueprint, method)
|
76
80
|
end
|
77
81
|
|
78
82
|
def validate_presence_of_blueprint!(blueprint)
|
@@ -84,10 +88,10 @@ module Blueprinter
|
|
84
88
|
# it means it, at the very least, does not have Blueprinter::Base as
|
85
89
|
# one of its ancestor classes (e.g: Hash) and thus an error should
|
86
90
|
# be raised.
|
87
|
-
|
88
|
-
|
91
|
+
return if blueprint.respond_to?(:ancestors)
|
92
|
+
|
93
|
+
raise BlueprinterError, "Blueprint provided for #{association_name} " \
|
89
94
|
'association is not valid.'
|
90
|
-
end
|
91
95
|
end
|
92
96
|
|
93
97
|
def validate_blueprint_has_blueprinter_base_ancestor!(blueprint, association_name)
|
@@ -96,9 +100,9 @@ module Blueprinter
|
|
96
100
|
return if blueprint.ancestors.include? Blueprinter::Base
|
97
101
|
|
98
102
|
# Raise error describing what's wrong.
|
99
|
-
raise BlueprinterError, "Class #{blueprint.name} does not inherit from "\
|
100
|
-
|
101
|
-
|
103
|
+
raise BlueprinterError, "Class #{blueprint.name} does not inherit from " \
|
104
|
+
'Blueprinter::Base and is not a valid Blueprinter ' \
|
105
|
+
"for #{association_name} association."
|
102
106
|
end
|
103
107
|
|
104
108
|
def jsonify(blob)
|
@@ -1,13 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blueprinter
|
2
4
|
module TypeHelpers
|
3
5
|
private
|
4
|
-
def active_record_relation?(object)
|
5
|
-
!!(defined?(ActiveRecord::Relation) &&
|
6
|
-
object.is_a?(ActiveRecord::Relation))
|
7
|
-
end
|
8
6
|
|
9
7
|
def array_like?(object)
|
10
|
-
|
8
|
+
Blueprinter.configuration.array_like_classes.any? do |klass|
|
9
|
+
object.is_a?(klass)
|
10
|
+
end
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blueprinter
|
2
4
|
# @api private
|
3
5
|
class Transformer
|
4
6
|
def transform(_result_hash, _primary_obj, _options = {})
|
5
|
-
|
7
|
+
raise NotImplementedError, 'A Transformer must implement #transform'
|
6
8
|
end
|
7
9
|
|
8
10
|
def self.transform(result_hash, primary_obj, options = {})
|
9
|
-
|
11
|
+
new.transform(result_hash, primary_obj, options)
|
10
12
|
end
|
11
13
|
end
|
12
14
|
end
|
data/lib/blueprinter/version.rb
CHANGED
data/lib/blueprinter/view.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blueprinter
|
2
4
|
# @api private
|
3
5
|
DefinitionPlaceholder = Struct.new :name, :view?
|
@@ -18,14 +20,14 @@ module Blueprinter
|
|
18
20
|
view_transformers.empty? ? Blueprinter.configuration.default_transformers : view_transformers
|
19
21
|
end
|
20
22
|
|
21
|
-
def track_definition_order(method,
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
def track_definition_order(method, viewable: true)
|
24
|
+
return unless @sort_by_definition
|
25
|
+
|
26
|
+
@definition_order << DefinitionPlaceholder.new(method, viewable)
|
25
27
|
end
|
26
28
|
|
27
29
|
def inherit(view)
|
28
|
-
view.fields.
|
30
|
+
view.fields.each_value do |field|
|
29
31
|
self << field
|
30
32
|
end
|
31
33
|
|
@@ -69,7 +71,7 @@ module Blueprinter
|
|
69
71
|
end
|
70
72
|
|
71
73
|
def <<(field)
|
72
|
-
track_definition_order(field.name,false)
|
74
|
+
track_definition_order(field.name, viewable: false)
|
73
75
|
fields[field.name] = field
|
74
76
|
end
|
75
77
|
end
|
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blueprinter
|
2
4
|
# @api private
|
3
5
|
class ViewCollection
|
4
6
|
attr_reader :views, :sort_by_definition
|
7
|
+
|
5
8
|
def initialize
|
6
9
|
@views = {
|
7
10
|
identifier: View.new(:identifier),
|
@@ -16,8 +19,8 @@ module Blueprinter
|
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
19
|
-
def
|
20
|
-
views.
|
22
|
+
def view?(view_name)
|
23
|
+
views.key? view_name
|
21
24
|
end
|
22
25
|
|
23
26
|
def fields_for(view_name)
|
@@ -26,7 +29,9 @@ module Blueprinter
|
|
26
29
|
fields, excluded_fields = sortable_fields(view_name)
|
27
30
|
sorted_fields = sort_by_definition ? sort_by_def(view_name, fields) : fields.values.sort_by(&:name)
|
28
31
|
|
29
|
-
(identifier_fields + sorted_fields).
|
32
|
+
(identifier_fields + sorted_fields).tap do |fields_array|
|
33
|
+
fields_array.reject! { |field| excluded_fields.include?(field.name) }
|
34
|
+
end
|
30
35
|
end
|
31
36
|
|
32
37
|
def transformers(view_name)
|
@@ -47,15 +52,15 @@ module Blueprinter
|
|
47
52
|
# @return [Array<(Hash, Hash<String, NilClass>)>] fields, excluded_fields
|
48
53
|
def sortable_fields(view_name)
|
49
54
|
excluded_fields = {}
|
50
|
-
fields = views[:default].fields
|
55
|
+
fields = views[:default].fields.clone
|
51
56
|
views[view_name].included_view_names.each do |included_view_name|
|
52
57
|
next if view_name == included_view_name
|
53
58
|
|
54
59
|
view_fields, view_excluded_fields = sortable_fields(included_view_name)
|
55
|
-
fields
|
60
|
+
fields.merge!(view_fields)
|
56
61
|
excluded_fields.merge!(view_excluded_fields)
|
57
62
|
end
|
58
|
-
fields
|
63
|
+
fields.merge!(views[view_name].fields) unless view_name == :default
|
59
64
|
|
60
65
|
views[view_name].excluded_field_names.each { |name| excluded_fields[name] = nil }
|
61
66
|
|
@@ -65,7 +70,9 @@ module Blueprinter
|
|
65
70
|
# select and order members of fields according to traversal of the definition_orders
|
66
71
|
def sort_by_def(view_name, fields)
|
67
72
|
ordered_fields = {}
|
68
|
-
views[:default].definition_order.each
|
73
|
+
views[:default].definition_order.each do |definition|
|
74
|
+
add_to_ordered_fields(ordered_fields, definition, fields, view_name)
|
75
|
+
end
|
69
76
|
ordered_fields.values
|
70
77
|
end
|
71
78
|
|
@@ -74,15 +81,13 @@ module Blueprinter
|
|
74
81
|
def add_to_ordered_fields(ordered_fields, definition, fields, view_name_filter = nil)
|
75
82
|
if definition.view?
|
76
83
|
if view_name_filter.nil? || view_name_filter == definition.name
|
77
|
-
views[definition.name].definition_order.each
|
84
|
+
views[definition.name].definition_order.each do |defined|
|
85
|
+
add_to_ordered_fields(ordered_fields, defined, fields)
|
86
|
+
end
|
78
87
|
end
|
79
88
|
else
|
80
89
|
ordered_fields[definition.name] = fields[definition.name]
|
81
90
|
end
|
82
91
|
end
|
83
|
-
|
84
|
-
def merge_fields(source_fields, included_fields)
|
85
|
-
source_fields.merge included_fields
|
86
|
-
end
|
87
92
|
end
|
88
93
|
end
|