deco_lite 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.reek.yml +18 -0
- data/.rspec +3 -0
- data/.rubocop.yml +188 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +105 -0
- data/LICENSE.txt +21 -0
- data/README.md +193 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/deco_lite.gemspec +57 -0
- data/lib/deco_lite/field_assignable.rb +25 -0
- data/lib/deco_lite/field_conflictable.rb +23 -0
- data/lib/deco_lite/field_creatable.rb +24 -0
- data/lib/deco_lite/field_informable.rb +81 -0
- data/lib/deco_lite/field_requireable.rb +35 -0
- data/lib/deco_lite/field_retrievable.rb +13 -0
- data/lib/deco_lite/fields_optionable.rb +16 -0
- data/lib/deco_lite/hash_loadable.rb +24 -0
- data/lib/deco_lite/model.rb +43 -0
- data/lib/deco_lite/model_nameable.rb +19 -0
- data/lib/deco_lite/namespace_optionable.rb +11 -0
- data/lib/deco_lite/optionable.rb +26 -0
- data/lib/deco_lite/options.rb +41 -0
- data/lib/deco_lite/options_defaultable.rb +17 -0
- data/lib/deco_lite/options_validatable.rb +49 -0
- data/lib/deco_lite/version.rb +6 -0
- data/lib/deco_lite.rb +5 -0
- metadata +273 -0
data/deco_lite.gemspec
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'deco_lite/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'deco_lite'
|
9
|
+
spec.version = DecoLite::VERSION
|
10
|
+
spec.authors = ['Gene M. Angelo, Jr.']
|
11
|
+
spec.email = ['public.gma@gmail.com']
|
12
|
+
|
13
|
+
spec.summary = 'Dynamically creates an active model from a Hash.'
|
14
|
+
spec.description = 'Dynamically creates an active model from a Hash.'
|
15
|
+
spec.homepage = 'https://github.com/gangelo/deco_lite'
|
16
|
+
spec.license = 'MIT'
|
17
|
+
|
18
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
19
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
20
|
+
# if spec.respond_to?(:metadata)
|
21
|
+
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
22
|
+
# else
|
23
|
+
# raise 'RubyGems 2.0 or newer is required to protect against ' \
|
24
|
+
# 'public gem pushes.'
|
25
|
+
# end
|
26
|
+
|
27
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
28
|
+
f.match(%r{^(test|spec|features)/})
|
29
|
+
end
|
30
|
+
spec.bindir = 'exe'
|
31
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
|
+
spec.require_paths = ['lib']
|
33
|
+
|
34
|
+
spec.required_ruby_version = '~> 3.0.1'
|
35
|
+
|
36
|
+
spec.add_runtime_dependency 'activemodel', '~> 7.0', '>= 7.0.3.1'
|
37
|
+
spec.add_runtime_dependency 'activesupport', '~> 7.0', '>= 7.0.3.1'
|
38
|
+
spec.add_runtime_dependency 'immutable_struct_ex', '~> 0.2.0'
|
39
|
+
# spec.add_development_dependency 'benchmark-ips', '~> 2.3'
|
40
|
+
spec.add_development_dependency 'bundler', '~> 2.2', '>= 2.2.17'
|
41
|
+
# spec.add_development_dependency 'factory_bot', '~> 6.2'
|
42
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.9'
|
43
|
+
# #spec.add_development_dependency 'rake', '~> 0'
|
44
|
+
# #spec.add_development_dependency 'redcarpet', '~> 3.5', '>= 3.5.1'
|
45
|
+
spec.add_development_dependency 'reek', '~> 6.0', '>= 6.0.4'
|
46
|
+
spec.add_development_dependency 'rspec', '~> 3.10'
|
47
|
+
# This verson of rubocop is returning errors.
|
48
|
+
# spec.add_development_dependency 'rubocop', '~> 1.14'
|
49
|
+
spec.add_development_dependency 'rubocop', '~> 1.9.1'
|
50
|
+
spec.add_development_dependency 'rubocop-performance', '~> 1.11', '>= 1.11.3'
|
51
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.3'
|
52
|
+
spec.add_development_dependency 'simplecov', '~> 0.21.2'
|
53
|
+
|
54
|
+
# spec.add_development_dependency "bundler", "~> 1.16"
|
55
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
56
|
+
# spec.add_development_dependency "rspec", "~> 3.0"
|
57
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'field_creatable'
|
4
|
+
require_relative 'field_retrievable'
|
5
|
+
|
6
|
+
module DecoLite
|
7
|
+
# Defines methods to assign model field values dynamically.
|
8
|
+
module FieldAssignable
|
9
|
+
include FieldCreatable
|
10
|
+
include FieldRetrievable
|
11
|
+
|
12
|
+
def set_field_values(hash:, field_info:, options:)
|
13
|
+
field_info.each do |name, info|
|
14
|
+
value = get_field_value(hash: hash, field_info: info)
|
15
|
+
set_field_value(field_name: name, value: value, options: options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_field_value(field_name:, value:, options:)
|
20
|
+
# Create our fields before we send.
|
21
|
+
create_field_accessor field_name: field_name, options: options
|
22
|
+
send("#{field_name}=", value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'fields_optionable'
|
4
|
+
|
5
|
+
module DecoLite
|
6
|
+
# Defines methods to to manage fields that conflict with
|
7
|
+
# existing model attributes.
|
8
|
+
module FieldConflictable
|
9
|
+
include FieldsOptionable
|
10
|
+
|
11
|
+
def validate_field_conflicts!(field_name:, options:)
|
12
|
+
return unless options.strict? && field_conflict?(field_name: field_name)
|
13
|
+
|
14
|
+
raise "Field '#{field_name}' conflicts with existing attribute; " \
|
15
|
+
'this will raise an error when running in strict mode: ' \
|
16
|
+
"options: { #{OPTION_FIELDS}: :#{OPTION_FIELDS_STRICT} }."
|
17
|
+
end
|
18
|
+
|
19
|
+
def field_conflict?(field_name:)
|
20
|
+
respond_to? field_name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'field_conflictable'
|
4
|
+
|
5
|
+
module DecoLite
|
6
|
+
# Takes an array of symbols and creates attr_accessors.
|
7
|
+
module FieldCreatable
|
8
|
+
include FieldConflictable
|
9
|
+
|
10
|
+
def create_field_accessors(field_names:, options:)
|
11
|
+
return if field_names.blank?
|
12
|
+
|
13
|
+
field_names.each do |field_name|
|
14
|
+
create_field_accessor(field_name: field_name, options: options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_field_accessor(field_name:, options:)
|
19
|
+
validate_field_conflicts!(field_name: field_name, options: options)
|
20
|
+
|
21
|
+
self.class.attr_accessor(field_name) if field_name.present?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DecoLite
|
4
|
+
# Creates and returns a hash given the parameters that are used to
|
5
|
+
# dynamically create fields and assign values to a model.
|
6
|
+
module FieldInformable
|
7
|
+
# This method simply navigates the payload hash received and creates qualified
|
8
|
+
# hash key names that can be used to verify/map to our field names in this model.
|
9
|
+
# This can be used to qualify nested hash fields and saves us some headaches
|
10
|
+
# if there are nested field names with the same name:
|
11
|
+
#
|
12
|
+
# given:
|
13
|
+
#
|
14
|
+
# hash = {
|
15
|
+
# first_name: 'first_name',
|
16
|
+
# ...
|
17
|
+
# address: {
|
18
|
+
# street: '',
|
19
|
+
# ...
|
20
|
+
# }
|
21
|
+
# }
|
22
|
+
#
|
23
|
+
# get_field_info(hash: hash) #=>
|
24
|
+
#
|
25
|
+
# {
|
26
|
+
# :first_name=>{:field_name=>:first_name, :dig=>[]},
|
27
|
+
# ...
|
28
|
+
# :address_street=>{:field_name=>:street, :dig=>[:address]},
|
29
|
+
# ...
|
30
|
+
# }
|
31
|
+
#
|
32
|
+
# The generated, qualified field names expected to map to our model, because we named
|
33
|
+
# them as such.
|
34
|
+
#
|
35
|
+
# :field_name is the actual, unqualified field name found in the payload hash sent.
|
36
|
+
# :dig is the hash key by which :field_name can be found in the payload hash if need be -
|
37
|
+
# retained across recursive calls.
|
38
|
+
def get_field_info(hash:, namespace: nil, dig: [], field_info: {})
|
39
|
+
hash.each do |key, value|
|
40
|
+
if value.is_a? Hash
|
41
|
+
get_field_info hash: value,
|
42
|
+
namespace: namespace,
|
43
|
+
dig: dig << key,
|
44
|
+
field_info: field_info
|
45
|
+
dig.pop
|
46
|
+
else
|
47
|
+
set_field_info!(field_info: field_info,
|
48
|
+
key: key,
|
49
|
+
namespace: namespace,
|
50
|
+
dig: dig)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
field_info
|
55
|
+
end
|
56
|
+
|
57
|
+
def set_field_info!(field_info:, key:, namespace:, dig:)
|
58
|
+
field_key = [namespace, *dig, key].compact.join('_').to_sym
|
59
|
+
field_info[field_key] = {
|
60
|
+
field_name: key,
|
61
|
+
dig: dig.dup
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def merge_field_info!(field_info:)
|
66
|
+
@field_info.merge!(field_info)
|
67
|
+
end
|
68
|
+
|
69
|
+
def field_names
|
70
|
+
field_info&.keys || []
|
71
|
+
end
|
72
|
+
|
73
|
+
attr_reader :field_info
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
attr_writer :field_info
|
78
|
+
|
79
|
+
module_function :get_field_info, :set_field_info!, :merge_field_info!
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DecoLite
|
4
|
+
# Provides methods to manage fields that must be defined from
|
5
|
+
# the dynamically loaded data.
|
6
|
+
module FieldRequireable
|
7
|
+
# Returns field names that will be used to validate the presence of
|
8
|
+
# dynamically created fields from loaded objects.
|
9
|
+
#
|
10
|
+
# You must override this method if you want to return field names that
|
11
|
+
# are required to be present. You may simply return a static array, but
|
12
|
+
# if you want to dynamically manipulate this field, return a variable.
|
13
|
+
def required_fields
|
14
|
+
# @required_fields ||= []
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Validator for field names. This validator simply checks to make
|
19
|
+
# sure that the field was created, which can only occur if:
|
20
|
+
# A) The field was defined on the model explicitly (e.g. attr_accessor :field).
|
21
|
+
# B) The field was created as a result of loading data dynamically.
|
22
|
+
def validate_required_fields
|
23
|
+
required_fields.each do |field_name|
|
24
|
+
next if required_field_exist? field_name: field_name
|
25
|
+
|
26
|
+
errors.add(field_name, 'field is missing', type: :missing_required_field)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# :reek:ManualDispatch - method added dynamically; this is the best way to check.
|
31
|
+
def required_field_exist?(field_name:)
|
32
|
+
respond_to?(field_name) && respond_to?("#{field_name}=".to_sym)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DecoLite
|
4
|
+
# Defines methods to retrieve model field values dynamically.
|
5
|
+
module FieldRetrievable
|
6
|
+
module_function
|
7
|
+
|
8
|
+
# Returns the value of the field using fully quaified field names.
|
9
|
+
def get_field_value(hash:, field_info:)
|
10
|
+
hash.dig(*[field_info[:dig], field_info[:field_name]].flatten.compact)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DecoLite
|
4
|
+
# Defines the fields option hash key and acceptable hash key values.
|
5
|
+
module FieldsOptionable
|
6
|
+
# The option hash key for this option.
|
7
|
+
OPTION_FIELDS = :fields
|
8
|
+
# The valid option values for this option key.
|
9
|
+
OPTION_FIELDS_MERGE = :merge
|
10
|
+
OPTION_FIELDS_STRICT = :strict
|
11
|
+
# The default value for this option.
|
12
|
+
OPTION_FIELDS_DEFAULT = OPTION_FIELDS_MERGE
|
13
|
+
# The valid option key values for this option.
|
14
|
+
OPTION_FIELDS_VALUES = [OPTION_FIELDS_MERGE, OPTION_FIELDS_STRICT].freeze
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'field_assignable'
|
4
|
+
require_relative 'field_informable'
|
5
|
+
|
6
|
+
module DecoLite
|
7
|
+
# Provides methods to load and return information about a given hash.
|
8
|
+
module HashLoadable
|
9
|
+
include FieldAssignable
|
10
|
+
include FieldInformable
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def load_hash(hash:, options:)
|
15
|
+
raise ArgumentError, "Argument hash is not a Hash (#{hash.class})" unless hash.is_a? Hash
|
16
|
+
|
17
|
+
return if hash.blank?
|
18
|
+
|
19
|
+
field_info = get_field_info(hash: hash, namespace: options.namespace)
|
20
|
+
set_field_values(hash: hash, field_info: field_info, options: options)
|
21
|
+
merge_field_info! field_info: field_info
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_model'
|
4
|
+
require_relative 'field_requireable'
|
5
|
+
require_relative 'hash_loadable'
|
6
|
+
require_relative 'model_nameable'
|
7
|
+
require_relative 'optionable'
|
8
|
+
|
9
|
+
module DecoLite
|
10
|
+
# This class defines the base class for classes that create
|
11
|
+
# dynamic models that can be used as decorators.
|
12
|
+
class Model
|
13
|
+
include ActiveModel::Model
|
14
|
+
include FieldRequireable
|
15
|
+
include HashLoadable
|
16
|
+
include ModelNameable
|
17
|
+
include Optionable
|
18
|
+
|
19
|
+
validate :validate_required_fields
|
20
|
+
|
21
|
+
def initialize(options: {})
|
22
|
+
@field_info = {}
|
23
|
+
# Accept whatever options are sent, but make sure
|
24
|
+
# we have defaults set up. #options_with_defaults
|
25
|
+
# will merge options into OptionsDefaultable::DEFAULT_OPTIONS
|
26
|
+
# so we have defaults for any options not passed in through
|
27
|
+
# options.
|
28
|
+
self.options = Options.with_defaults options
|
29
|
+
end
|
30
|
+
|
31
|
+
def load(hash:, options: {})
|
32
|
+
# Merge options into the default options passed through the
|
33
|
+
# constructor; these will override any options passed in when
|
34
|
+
# this object was created, allowing us to retain any defaut
|
35
|
+
# options while loading, but also provide option customization
|
36
|
+
# of options when needed.
|
37
|
+
options = Options.with_defaults(options, defaults: self.options)
|
38
|
+
load_hash(hash: hash, options: options)
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DecoLite
|
4
|
+
# Provides class methods to return an appropriate model name.
|
5
|
+
module ModelNameable
|
6
|
+
class << self
|
7
|
+
def included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Class methods to extend.
|
13
|
+
module ClassMethods
|
14
|
+
def model_name
|
15
|
+
ActiveModel::Name.new(self, nil, to_s.gsub('::', ''))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DecoLite
|
4
|
+
# Defines the namespace option hash key
|
5
|
+
module NamespaceOptionable
|
6
|
+
# The option hash key for this option.
|
7
|
+
OPTION_NAMESPACE = :namespace
|
8
|
+
# The default value for this option - no namespace.
|
9
|
+
OPTION_NAMESPACE_DEFAULT = nil
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'immutable_struct_ex'
|
4
|
+
require_relative 'options'
|
5
|
+
require_relative 'options_validatable'
|
6
|
+
|
7
|
+
module DecoLite
|
8
|
+
# Defines methods and fields to manage options.
|
9
|
+
module Optionable
|
10
|
+
include OptionsValidatable
|
11
|
+
|
12
|
+
def options
|
13
|
+
@options || Options.default
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def options=(value)
|
19
|
+
options_hash = value.to_h
|
20
|
+
|
21
|
+
validate_options! options: options_hash
|
22
|
+
|
23
|
+
@options = Options.new(**options_hash)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'immutable_struct_ex'
|
4
|
+
require_relative 'options_defaultable'
|
5
|
+
require_relative 'options_validatable'
|
6
|
+
|
7
|
+
module DecoLite
|
8
|
+
# Defines methods to create options.
|
9
|
+
module Options
|
10
|
+
extend DecoLite::OptionsDefaultable
|
11
|
+
extend DecoLite::OptionsValidatable
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def new(**options)
|
15
|
+
immutable_struct_ex = ImmutableStructEx.new(**options) do
|
16
|
+
def merge?
|
17
|
+
fields == OPTION_FIELDS_MERGE
|
18
|
+
end
|
19
|
+
|
20
|
+
def strict?
|
21
|
+
fields == OPTION_FIELDS_STRICT
|
22
|
+
end
|
23
|
+
|
24
|
+
def namespace?
|
25
|
+
namespace || false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
validate_options! options: immutable_struct_ex.to_h
|
29
|
+
immutable_struct_ex
|
30
|
+
end
|
31
|
+
|
32
|
+
def with_defaults(options, defaults: DEFAULT_OPTIONS)
|
33
|
+
new(**defaults.to_h.merge(options.to_h))
|
34
|
+
end
|
35
|
+
|
36
|
+
def default
|
37
|
+
with_defaults({})
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'fields_optionable'
|
4
|
+
require_relative 'namespace_optionable'
|
5
|
+
|
6
|
+
module DecoLite
|
7
|
+
# Defines default options and their optionn values.
|
8
|
+
module OptionsDefaultable
|
9
|
+
include DecoLite::FieldsOptionable
|
10
|
+
include DecoLite::NamespaceOptionable
|
11
|
+
|
12
|
+
DEFAULT_OPTIONS = {
|
13
|
+
OPTION_FIELDS => OPTION_FIELDS_DEFAULT,
|
14
|
+
OPTION_NAMESPACE => OPTION_NAMESPACE_DEFAULT
|
15
|
+
}.freeze
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'fields_optionable'
|
4
|
+
require_relative 'namespace_optionable'
|
5
|
+
|
6
|
+
module DecoLite
|
7
|
+
# Methods to validate options.
|
8
|
+
module OptionsValidatable
|
9
|
+
include DecoLite::FieldsOptionable
|
10
|
+
include DecoLite::NamespaceOptionable
|
11
|
+
|
12
|
+
OPTIONS = [OPTION_FIELDS, OPTION_NAMESPACE].freeze
|
13
|
+
|
14
|
+
def validate_options!(options:)
|
15
|
+
raise ArgumentError, 'options is not a Hash' unless options.is_a? Hash
|
16
|
+
|
17
|
+
validate_options_present! options: options
|
18
|
+
|
19
|
+
validate_option_keys! options: options
|
20
|
+
validate_option_fields! fields: options[:fields]
|
21
|
+
validate_option_namespace! namespace: options[:namespace]
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate_options_present!(options:)
|
25
|
+
raise ArgumentError, 'options is blank?' if options.blank?
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_option_keys!(options:)
|
29
|
+
invalid_options = options.except(*OPTIONS)&.keys
|
30
|
+
raise ArgumentError, "One or more option keys were unrecognized: #{invalid_options}" unless invalid_options.blank?
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_option_fields!(fields:)
|
34
|
+
return if OPTION_FIELDS_VALUES.include?(fields)
|
35
|
+
|
36
|
+
raise ArgumentError,
|
37
|
+
"option :fields value or type is invalid. #{OPTION_FIELDS_VALUES} (Symbol) " \
|
38
|
+
"was expected, but '#{fields}' (#{fields.class}) was received."
|
39
|
+
end
|
40
|
+
|
41
|
+
def validate_option_namespace!(namespace:)
|
42
|
+
# :namespace is optional.
|
43
|
+
return if namespace.blank? || namespace.is_a?(Symbol)
|
44
|
+
|
45
|
+
raise ArgumentError, 'option :namespace value or type is invalid. A Symbol was expected, ' \
|
46
|
+
"but '#{namespace}' (#{namespace.class}) was received."
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|