deco_lite 0.1.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 +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
|