blueprinter 0.26.0 → 1.0.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 +60 -50
- data/README.md +41 -52
- data/Rakefile +13 -1
- data/lib/blueprinter/base.rb +13 -15
- data/lib/blueprinter/blueprinter_error.rb +2 -0
- data/lib/blueprinter/configuration.rb +24 -2
- data/lib/blueprinter/deprecation.rb +5 -3
- data/lib/blueprinter/empty_types.rb +7 -9
- data/lib/blueprinter/extension.rb +22 -0
- data/lib/blueprinter/extensions.rb +37 -0
- 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/reflection.rb +71 -0
- data/lib/blueprinter/transformer.rb +4 -2
- data/lib/blueprinter/version.rb +3 -1
- data/lib/blueprinter/view.rb +7 -9
- data/lib/blueprinter/view_collection.rb +27 -11
- data/lib/blueprinter.rb +3 -0
- data/lib/generators/blueprinter/blueprint_generator.rb +37 -48
- data/lib/generators/blueprinter/templates/blueprint.rb +2 -0
- metadata +8 -173
- data/lib/tasks/blueprinter_tasks.rake +0 -4
data/Rakefile
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rdoc/task'
|
2
4
|
require 'bundler/gem_tasks'
|
3
5
|
require 'rake/testtask'
|
4
6
|
require 'rspec/core/rake_task'
|
7
|
+
require 'yard'
|
8
|
+
require 'rubocop/rake_task'
|
5
9
|
|
6
10
|
begin
|
7
11
|
require 'bundler/setup'
|
@@ -21,10 +25,18 @@ RSpec::Core::RakeTask.new(:spec) do |t|
|
|
21
25
|
t.rspec_opts = '--pattern spec/**/*_spec.rb --warnings'
|
22
26
|
end
|
23
27
|
|
28
|
+
RuboCop::RakeTask.new
|
29
|
+
|
30
|
+
YARD::Rake::YardocTask.new do |t|
|
31
|
+
t.files = Dir['lib/**/*'].reject do |file|
|
32
|
+
file.include?('lib/generators')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
24
36
|
Rake::TestTask.new(:benchmarks) do |t|
|
25
37
|
t.libs << 'spec'
|
26
38
|
t.pattern = 'spec/benchmarks/**/*_test.rb'
|
27
39
|
t.verbose = false
|
28
40
|
end
|
29
41
|
|
30
|
-
task default:
|
42
|
+
task default: %i[spec rubocop]
|
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'
|
@@ -15,10 +17,12 @@ require_relative 'helpers/base_helpers'
|
|
15
17
|
require_relative 'view'
|
16
18
|
require_relative 'view_collection'
|
17
19
|
require_relative 'transformer'
|
20
|
+
require_relative 'reflection'
|
18
21
|
|
19
22
|
module Blueprinter
|
20
23
|
class Base
|
21
24
|
include BaseHelpers
|
25
|
+
extend Reflection
|
22
26
|
|
23
27
|
# Specify a field or method name used as an identifier. Usually, this is
|
24
28
|
# something like :id
|
@@ -58,7 +62,7 @@ module Blueprinter
|
|
58
62
|
name,
|
59
63
|
extractor,
|
60
64
|
self,
|
61
|
-
block: block
|
65
|
+
block: block
|
62
66
|
)
|
63
67
|
end
|
64
68
|
|
@@ -123,7 +127,7 @@ module Blueprinter
|
|
123
127
|
options.fetch(:name) { method },
|
124
128
|
options.fetch(:extractor) { Blueprinter.configuration.extractor_default.new },
|
125
129
|
self,
|
126
|
-
options.merge(block: block)
|
130
|
+
options.merge(block: block)
|
127
131
|
)
|
128
132
|
end
|
129
133
|
|
@@ -163,7 +167,7 @@ module Blueprinter
|
|
163
167
|
method,
|
164
168
|
options.merge(
|
165
169
|
association: true,
|
166
|
-
extractor: options.fetch(:extractor) { AssociationExtractor.new }
|
170
|
+
extractor: options.fetch(:extractor) { AssociationExtractor.new }
|
167
171
|
),
|
168
172
|
&block
|
169
173
|
)
|
@@ -252,10 +256,9 @@ module Blueprinter
|
|
252
256
|
#
|
253
257
|
# @api private
|
254
258
|
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
|
259
|
+
raise BlueprinterError, "View '#{view_name}' is not defined" unless view_collection.view? view_name
|
258
260
|
|
261
|
+
object = Blueprinter.configuration.extensions.pre_render(object, self, view_name, local_options)
|
259
262
|
data = prepare_data(object, view_name, local_options)
|
260
263
|
prepend_root_and_meta(data, root, meta)
|
261
264
|
end
|
@@ -279,7 +282,6 @@ module Blueprinter
|
|
279
282
|
end
|
280
283
|
end
|
281
284
|
|
282
|
-
|
283
285
|
# Specify one transformer to be included for serialization.
|
284
286
|
# Takes a class which extends Blueprinter::Transformer
|
285
287
|
#
|
@@ -315,7 +317,6 @@ module Blueprinter
|
|
315
317
|
current_view.add_transformer(transformer)
|
316
318
|
end
|
317
319
|
|
318
|
-
|
319
320
|
# Specify another view that should be mixed into the current view.
|
320
321
|
#
|
321
322
|
# @param view_name [Symbol] the view to mix into the current view.
|
@@ -338,7 +339,6 @@ module Blueprinter
|
|
338
339
|
current_view.include_view(view_name)
|
339
340
|
end
|
340
341
|
|
341
|
-
|
342
342
|
# Specify additional views that should be mixed into the current view.
|
343
343
|
#
|
344
344
|
# @param view_name [Array<Symbol>] the views to mix into the current view.
|
@@ -361,12 +361,10 @@ module Blueprinter
|
|
361
361
|
#
|
362
362
|
# @return [Array<Symbol>] an array of view names.
|
363
363
|
|
364
|
-
|
365
364
|
def self.include_views(*view_names)
|
366
365
|
current_view.include_views(view_names)
|
367
366
|
end
|
368
367
|
|
369
|
-
|
370
368
|
# Exclude a field that was mixed into the current view.
|
371
369
|
#
|
372
370
|
# @param field_name [Symbol] the field to exclude from the current view.
|
@@ -444,13 +442,13 @@ module Blueprinter
|
|
444
442
|
# end
|
445
443
|
# end
|
446
444
|
#
|
447
|
-
# ExampleBlueprint.
|
448
|
-
# ExampleBlueprint.
|
445
|
+
# ExampleBlueprint.view?(:custom) => true
|
446
|
+
# ExampleBlueprint.view?(:doesnt_exist) => false
|
449
447
|
#
|
450
448
|
# @return [Boolean] a boolean value indicating if the view is
|
451
449
|
# supported by this Blueprint.
|
452
|
-
def self.
|
453
|
-
view_collection.
|
450
|
+
def self.view?(view_name)
|
451
|
+
view_collection.view? view_name
|
454
452
|
end
|
455
453
|
end
|
456
454
|
end
|
@@ -1,8 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'extensions'
|
4
|
+
|
1
5
|
module Blueprinter
|
2
6
|
class Configuration
|
3
|
-
attr_accessor :association_default, :datetime_format, :deprecations, :field_default, :generator, :if, :method,
|
7
|
+
attr_accessor :association_default, :datetime_format, :deprecations, :field_default, :generator, :if, :method,
|
8
|
+
:sort_fields_by, :unless, :extractor_default, :default_transformers, :custom_array_like_classes
|
4
9
|
|
5
|
-
VALID_CALLABLES = %i
|
10
|
+
VALID_CALLABLES = %i[if unless].freeze
|
6
11
|
|
7
12
|
def initialize
|
8
13
|
@deprecations = :stderror
|
@@ -16,6 +21,23 @@ module Blueprinter
|
|
16
21
|
@unless = nil
|
17
22
|
@extractor_default = AutoExtractor
|
18
23
|
@default_transformers = []
|
24
|
+
@custom_array_like_classes = []
|
25
|
+
end
|
26
|
+
|
27
|
+
def extensions
|
28
|
+
@extensions ||= Extensions.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def extensions=(list)
|
32
|
+
@extensions = Extensions.new(list)
|
33
|
+
end
|
34
|
+
|
35
|
+
def array_like_classes
|
36
|
+
@array_like_classes ||= [
|
37
|
+
Array,
|
38
|
+
defined?(ActiveRecord::Relation) && ActiveRecord::Relation,
|
39
|
+
*custom_array_like_classes
|
40
|
+
].compact
|
19
41
|
end
|
20
42
|
|
21
43
|
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
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Blueprinter
|
4
|
+
#
|
5
|
+
# Base class for all extensions. All extension methods are implemented as no-ops.
|
6
|
+
#
|
7
|
+
class Extension
|
8
|
+
#
|
9
|
+
# Called eary during "render", this method receives the object to be rendered and
|
10
|
+
# may return a modified (or new) object to be rendered.
|
11
|
+
#
|
12
|
+
# @param object [Object] The object to be rendered
|
13
|
+
# @param _blueprint [Class] The Blueprinter class
|
14
|
+
# @param _view [Symbol] The blueprint view
|
15
|
+
# @param _options [Hash] Options passed to "render"
|
16
|
+
# @return [Object] The object to continue rendering
|
17
|
+
#
|
18
|
+
def pre_render(object, _blueprint, _view, _options)
|
19
|
+
object
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Blueprinter
|
4
|
+
#
|
5
|
+
# Stores and runs Blueprinter extensions. An extension is any object that implements one or more of the
|
6
|
+
# extension methods:
|
7
|
+
#
|
8
|
+
# The Render Extension intercepts an object before rendering begins. The return value from this
|
9
|
+
# method is what is ultimately rendered.
|
10
|
+
#
|
11
|
+
# def pre_render(object, blueprint, view, options)
|
12
|
+
# # returns original, modified, or new object
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
class Extensions
|
16
|
+
def initialize(extensions = [])
|
17
|
+
@extensions = extensions
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_a
|
21
|
+
@extensions.dup
|
22
|
+
end
|
23
|
+
|
24
|
+
# Appends an extension
|
25
|
+
def <<(ext)
|
26
|
+
@extensions << ext
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# Runs the object through all Render Extensions and returns the final result
|
31
|
+
def pre_render(object, blueprint, view, options = {})
|
32
|
+
@extensions.reduce(object) do |acc, ext|
|
33
|
+
ext.pre_render(acc, blueprint, view, options)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
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
|