anyway_config 2.7.2 → 2.8.1

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +23 -5
  4. data/lib/.rbnext/2.7/anyway/loaders/yaml.rb +0 -1
  5. data/lib/.rbnext/2.7/anyway/tracing.rb +2 -2
  6. data/lib/.rbnext/2.7/anyway/type_casting.rb +1 -1
  7. data/lib/.rbnext/3.0/anyway/auto_cast.rb +2 -2
  8. data/lib/.rbnext/3.0/anyway/config.rb +16 -5
  9. data/lib/.rbnext/3.0/anyway/loaders/yaml.rb +0 -1
  10. data/lib/.rbnext/3.0/anyway/loaders.rb +9 -8
  11. data/lib/.rbnext/3.0/anyway/tracing.rb +2 -2
  12. data/lib/.rbnext/3.1/anyway/config.rb +16 -5
  13. data/lib/.rbnext/3.1/anyway/env.rb +0 -1
  14. data/lib/.rbnext/3.1/anyway/tracing.rb +2 -2
  15. data/lib/.rbnext/3.2/anyway/config.rb +16 -5
  16. data/lib/.rbnext/3.2/anyway/tracing.rb +2 -2
  17. data/lib/.rbnext/3.4/anyway/auto_cast.rb +2 -2
  18. data/lib/.rbnext/3.4/anyway/config.rb +16 -5
  19. data/lib/.rbnext/3.4/anyway/tracing.rb +2 -2
  20. data/lib/.rbnext/3.4/anyway/type_casting.rb +1 -1
  21. data/lib/anyway/config.rb +14 -3
  22. data/lib/anyway/env.rb +0 -1
  23. data/lib/anyway/loaders/doppler.rb +0 -2
  24. data/lib/anyway/loaders/env.rb +0 -2
  25. data/lib/anyway/loaders/yaml.rb +0 -1
  26. data/lib/anyway/loaders.rb +9 -8
  27. data/lib/anyway/option_parser_builder.rb +1 -1
  28. data/lib/anyway/rails/autoload.rb +0 -2
  29. data/lib/anyway/rails/loaders/credentials.rb +0 -2
  30. data/lib/anyway/rails/loaders/secrets.rb +0 -2
  31. data/lib/anyway/rails/settings.rb +2 -0
  32. data/lib/anyway/utils/which.rb +2 -1
  33. data/lib/anyway/version.rb +1 -1
  34. data/lib/anyway_config.rb +8 -3
  35. data/sig/anyway_config.rbs +3 -0
  36. metadata +3 -5
  37. data/lib/.rbnext/2.7/anyway/auto_cast.rb +0 -53
  38. data/lib/.rbnext/2.7/anyway/config.rb +0 -475
@@ -19,7 +19,7 @@ module Anyway # :nodoc:
19
19
  private
20
20
 
21
21
  def option_parser_on_args(key, flag: false, desc: nil, type: ::String)
22
- on_args = ["--#{key.to_s.tr("_", "-")}#{flag ? "" : " VALUE"}"]
22
+ on_args = ["--#{key.to_s.tr("_", "-")}#{" VALUE" unless flag}"]
23
23
  on_args << type unless flag
24
24
  on_args << desc unless desc.nil?
25
25
  on_args
@@ -4,8 +4,6 @@
4
4
  # when Anyway Config is loaded before Rails (e.g., in config/puma.rb).
5
5
  module Anyway
6
6
  module Rails
7
- using RubyNext
8
-
9
7
  class << self
10
8
  attr_reader :tracer, :name_method
11
9
  attr_accessor :disable_postponed_load_warning
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Anyway
4
- using RubyNext
5
-
6
4
  module Rails
7
5
  module Loaders
8
6
  class Credentials < Anyway::Loaders::Base
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Anyway
4
- using RubyNext
5
-
6
4
  module Rails
7
5
  module Loaders
8
6
  class Secrets < Anyway::Loaders::Base
@@ -65,10 +65,12 @@ module Anyway
65
65
  @autoload_via_zeitwerk = defined?(::Zeitwerk)
66
66
  end
67
67
 
68
+ alias_method :current_environment, :current_environment
68
69
  def current_environment
69
70
  @current_environment || ::Rails.env.to_s
70
71
  end
71
72
 
73
+ alias_method :app_root, :app_root
72
74
  def app_root
73
75
  ::Rails.root
74
76
  end
@@ -6,7 +6,8 @@ module Anyway
6
6
  # taken from https://stackoverflow.com/a/5471032
7
7
  def self.which(cmd)
8
8
  exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
9
- ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
9
+ paths = ENV["PATH"]&.split(File::PATH_SEPARATOR) || []
10
+ paths.each do |path|
10
11
  exts.each do |ext|
11
12
  exe = File.join(path, "#{cmd}#{ext}")
12
13
  return exe if File.executable?(exe) && !File.directory?(exe)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Anyway # :nodoc:
4
- VERSION = "2.7.2"
4
+ VERSION = "2.8.1"
5
5
  end
data/lib/anyway_config.rb CHANGED
@@ -37,12 +37,17 @@ module Anyway # :nodoc:
37
37
 
38
38
  # Configure default loaders
39
39
  loaders.append :yml, Loaders::YAML
40
- loaders.append :ejson, Loaders::EJSON if Utils.which("ejson")
41
- loaders.append :env, Loaders::Env
42
40
 
43
- if ENV.key?("DOPPLER_TOKEN") && ENV["ANYWAY_CONFIG_DISABLE_DOPPLER"] != "true"
41
+ # Configure optional loaders
42
+ if ENV["ANYWAY_CONFIG_DISABLE_EJSON"] != "true" && Utils.which("ejson")
43
+ loaders.append :ejson, Loaders::EJSON
44
+ end
45
+ if ENV["ANYWAY_CONFIG_DISABLE_DOPPLER"] != "true" && ENV.key?("DOPPLER_TOKEN")
44
46
  loaders.append :doppler, Loaders::Doppler
45
47
  end
48
+
49
+ # ENV must go last to take higher precedence
50
+ loaders.append :env, Loaders::Env
46
51
  end
47
52
 
48
53
  if defined?(::Rails::VERSION)
@@ -83,6 +83,8 @@ module Anyway
83
83
  def self.coerce_types: (**mappingType) -> void
84
84
  def self.coercion_mapping: -> Hash[untyped, untyped]?
85
85
  def self.disable_auto_cast!: -> void
86
+ def self.configuration_sources: -> Array[Symbol]?
87
+ def self.configuration_sources=: (Array[Symbol]) -> void
86
88
 
87
89
  attr_reader config_name: String
88
90
  attr_reader env_prefix: String
@@ -145,6 +147,7 @@ module Anyway
145
147
  def override: (Symbol id, _Loader loader) -> void
146
148
  | (Symbol id) { (**untyped) -> Hash[untyped, untyped] } -> void
147
149
  def delete: (Symbol id) -> void
150
+ def keys: () -> Array[Symbol]
148
151
  end
149
152
  end
150
153
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anyway_config
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.2
4
+ version: 2.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-01 00:00:00.000000000 Z
11
+ date: 2026-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-next-core
@@ -121,8 +121,6 @@ files:
121
121
  - LICENSE.txt
122
122
  - README.md
123
123
  - lib/.rbnext/2.6/anyway/ejson_parser.rb
124
- - lib/.rbnext/2.7/anyway/auto_cast.rb
125
- - lib/.rbnext/2.7/anyway/config.rb
126
124
  - lib/.rbnext/2.7/anyway/loaders/yaml.rb
127
125
  - lib/.rbnext/2.7/anyway/rbs.rb
128
126
  - lib/.rbnext/2.7/anyway/settings.rb
@@ -214,7 +212,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
214
212
  requirements:
215
213
  - - ">="
216
214
  - !ruby/object:Gem::Version
217
- version: '2.5'
215
+ version: '2.7'
218
216
  required_rubygems_version: !ruby/object:Gem::Requirement
219
217
  requirements:
220
218
  - - ">="
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Anyway
4
- module AutoCast
5
- # Regexp to detect array values
6
- # Array value is a values that contains at least one comma
7
- # and doesn't start/end with quote or curly braces
8
- ARRAY_RXP = /\A[^'"{].*\s*,\s*.*[^'"}]\z/
9
-
10
- class << self
11
- def call(val)
12
- return val unless val.is_a?(::Hash) || val.is_a?(::String)
13
-
14
- case val
15
- when Hash
16
- val.transform_values { |_1| it = _1;call(it) }
17
- when ARRAY_RXP
18
- val.split(/\s*,\s*/).map { |_1| it = _1;call(it) }
19
- when /\A(true|t|yes|y)\z/i
20
- true
21
- when /\A(false|f|no|n)\z/i
22
- false
23
- when /\A(nil|null)\z/i
24
- nil
25
- when /\A\d+\z/
26
- val.to_i
27
- when /\A\d*\.\d+\z/
28
- val.to_f
29
- when /\A['"].*['"]\z/
30
- val.gsub(/(\A['"]|['"]\z)/, "")
31
- else
32
- val
33
- end
34
- end
35
-
36
- def cast_hash(obj)
37
- obj.transform_values do |val|
38
- val.is_a?(::Hash) ? cast_hash(val) : call(val)
39
- end
40
- end
41
-
42
- def coerce(_key, val)
43
- call(val)
44
- end
45
- end
46
- end
47
-
48
- module NoCast
49
- def self.call(val) ; val; end
50
-
51
- def self.coerce(_key, val) ; val; end
52
- end
53
- end
@@ -1,475 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "anyway/optparse_config"
4
- require "anyway/dynamic_config"
5
-
6
- module Anyway # :nodoc:
7
- using RubyNext
8
- using Anyway::Ext::DeepDup
9
- using Anyway::Ext::DeepFreeze
10
- using Anyway::Ext::Hash
11
- using Anyway::Ext::FlattenNames
12
-
13
- using(Module.new do
14
- refine Object do
15
- def vm_object_id() ; (object_id << 1).to_s(16); end
16
- end
17
- end)
18
-
19
- # Base config class
20
- # Provides `attr_config` method to describe
21
- # configuration parameters and set defaults
22
- class Config
23
- PARAM_NAME = /^[a-z_](\w+)?$/
24
-
25
- # List of names that couldn't be used as config names
26
- # (the class instance methods we use)
27
- RESERVED_NAMES = %i[
28
- config_name
29
- env_prefix
30
- as_env
31
- values
32
- class
33
- clear
34
- deconstruct_keys
35
- dig
36
- dup
37
- initialize
38
- load
39
- load_from_sources
40
- option_parser
41
- pretty_print
42
- raise_validation_error
43
- reload
44
- resolve_config_path
45
- tap
46
- to_h
47
- to_source_trace
48
- write_config_attr
49
- __type_caster__
50
- ].freeze
51
-
52
- class Error < StandardError; end
53
-
54
- class ValidationError < Error; end
55
-
56
- include OptparseConfig
57
- include DynamicConfig
58
-
59
- class BlockCallback
60
- attr_reader :block
61
-
62
- def initialize(block)
63
- @block = block
64
- end
65
-
66
- def apply_to(config)
67
- config.instance_exec(&block)
68
- end
69
- end
70
-
71
- class NamedCallback
72
- attr_reader :name
73
-
74
- def initialize(name)
75
- @name = name
76
- end
77
-
78
- def apply_to(config) ; config.send(name); end
79
- end
80
-
81
- class << self
82
- def attr_config(*args, **hargs)
83
- new_defaults = hargs.deep_dup
84
- new_defaults.stringify_keys!
85
-
86
- defaults.merge! new_defaults
87
-
88
- new_keys = ((args + new_defaults.keys) - config_attributes)
89
-
90
- validate_param_names! new_keys.map(&:to_s)
91
-
92
- new_keys.map!(&:to_sym)
93
-
94
- unless (reserved_names = (new_keys & RESERVED_NAMES)).empty?
95
- raise ArgumentError, "Can not use the following reserved names as config attrubutes: " \
96
- "#{reserved_names.sort.map(&:to_s).join(", ")}"
97
- end
98
-
99
- config_attributes.push(*new_keys)
100
-
101
- define_config_accessor(*new_keys)
102
-
103
- # Define predicate methods ("param?") for attributes
104
- # having `true` or `false` as default values
105
- new_defaults.each do |key, val|
106
- next unless val.is_a?(TrueClass) || val.is_a?(FalseClass)
107
- alias_method :"#{key}?", :"#{key}"
108
- end
109
- end
110
-
111
- def defaults
112
- return @defaults if instance_variable_defined?(:@defaults)
113
-
114
- @defaults = if superclass < Anyway::Config
115
- superclass.defaults.deep_dup
116
- else
117
- new_empty_config
118
- end
119
- end
120
-
121
- def config_attributes
122
- return @config_attributes if instance_variable_defined?(:@config_attributes)
123
-
124
- @config_attributes = if superclass < Anyway::Config
125
- superclass.config_attributes.dup
126
- else
127
- []
128
- end
129
- end
130
-
131
- def required(*names, env: nil, **nested)
132
- unknown_names = names + nested.keys - config_attributes
133
- raise ArgumentError, "Unknown config param: #{unknown_names.join(",")}" if unknown_names.any?
134
-
135
- return unless Settings.matching_env?(env)
136
-
137
- required_attributes.push(*names)
138
- required_attributes.push(*nested.flatten_names)
139
- end
140
-
141
- def required_attributes
142
- return @required_attributes if instance_variable_defined?(:@required_attributes)
143
-
144
- @required_attributes = if superclass < Anyway::Config
145
- superclass.required_attributes.dup
146
- else
147
- []
148
- end
149
- end
150
-
151
- def on_load(*names, &block)
152
- raise ArgumentError, "Either methods or block should be specified, not both" if block && !names.empty?
153
-
154
- if block
155
- load_callbacks << BlockCallback.new(block)
156
- else
157
- load_callbacks.push(*names.map { |_1| it = _1;NamedCallback.new(it) })
158
- end
159
- end
160
-
161
- def load_callbacks
162
- return @load_callbacks if instance_variable_defined?(:@load_callbacks)
163
-
164
- @load_callbacks = if superclass <= Anyway::Config
165
- superclass.load_callbacks.dup
166
- else
167
- []
168
- end
169
- end
170
-
171
- def config_name(val = nil)
172
- return (@explicit_config_name = val.to_s) unless val.nil?
173
-
174
- return @config_name if instance_variable_defined?(:@config_name)
175
-
176
- @config_name = explicit_config_name || build_config_name
177
- end
178
-
179
- def explicit_config_name
180
- return @explicit_config_name if instance_variable_defined?(:@explicit_config_name)
181
-
182
- @explicit_config_name =
183
- if superclass.respond_to?(:explicit_config_name)
184
- superclass.explicit_config_name
185
- end
186
- end
187
-
188
- def explicit_config_name?() ; !explicit_config_name.nil?; end
189
-
190
- def env_prefix(val = nil)
191
- return (@env_prefix = val.to_s.upcase) unless val.nil?
192
-
193
- return @env_prefix if instance_variable_defined?(:@env_prefix)
194
-
195
- @env_prefix = if superclass < Anyway::Config && superclass.explicit_config_name?
196
- superclass.env_prefix
197
- else
198
- config_name.upcase
199
- end
200
- end
201
-
202
- def loader_options(val = nil)
203
- return (@loader_options = val) unless val.nil?
204
-
205
- return @loader_options if instance_variable_defined?(:@loader_options)
206
-
207
- @loader_options = if superclass < Anyway::Config
208
- superclass.loader_options
209
- else
210
- {}
211
- end
212
- end
213
-
214
- def new_empty_config() ; {}; end
215
-
216
- def coerce_types(mapping)
217
- Utils.deep_merge!(coercion_mapping, mapping)
218
-
219
- mapping.each do |key, val|
220
- type = val.is_a?(::Hash) ? val[:type] : val
221
- next if type != :boolean
222
-
223
- alias_method :"#{key}?", :"#{key}"
224
- end
225
- end
226
-
227
- def coercion_mapping
228
- return @coercion_mapping if instance_variable_defined?(:@coercion_mapping)
229
-
230
- @coercion_mapping = if superclass < Anyway::Config
231
- superclass.coercion_mapping.deep_dup
232
- else
233
- {}
234
- end
235
- end
236
-
237
- def type_caster(val = nil)
238
- return @type_caster unless val.nil?
239
-
240
- @type_caster ||=
241
- if coercion_mapping.empty?
242
- fallback_type_caster
243
- else
244
- ::Anyway::TypeCaster.new(coercion_mapping, fallback: fallback_type_caster)
245
- end
246
- end
247
-
248
- def fallback_type_caster(val = nil)
249
- return (@fallback_type_caster = val) unless val.nil?
250
-
251
- return @fallback_type_caster if instance_variable_defined?(:@fallback_type_caster)
252
-
253
- @fallback_type_caster = if superclass < Anyway::Config
254
- superclass.fallback_type_caster.deep_dup
255
- else
256
- ::Anyway::AutoCast
257
- end
258
- end
259
-
260
- def disable_auto_cast!
261
- @fallback_type_caster = ::Anyway::NoCast
262
- end
263
-
264
- private
265
-
266
- def define_config_accessor(*names)
267
- names.each do |name|
268
- accessors_module.module_eval <<~RUBY, __FILE__, __LINE__ + 1
269
- def #{name}=(val)
270
- __trace__&.record_value(val, "#{name}", **Tracing.current_trace_source)
271
- values[:#{name}] = val
272
- end
273
-
274
- def #{name}
275
- values[:#{name}]
276
- end
277
- RUBY
278
- end
279
- end
280
-
281
- def accessors_module
282
- return @accessors_module if instance_variable_defined?(:@accessors_module)
283
-
284
- @accessors_module = Module.new.tap do |mod|
285
- include mod
286
- end
287
- end
288
-
289
- def build_config_name
290
- unless name
291
- raise "Please, specify config name explicitly for anonymous class " \
292
- "via `config_name :my_config`"
293
- end
294
-
295
- # handle two cases:
296
- # - SomeModule::Config => "some_module"
297
- # - SomeConfig => "some"
298
- unless name =~ /^(\w+)(::)?Config$/
299
- raise "Couldn't infer config name, please, specify it explicitly " \
300
- "via `config_name :my_config`"
301
- end
302
-
303
- # TODO(v3.0): Replace downcase with underscore
304
- Regexp.last_match[1].tap(&:downcase!)
305
- end
306
-
307
- def validate_param_names!(names)
308
- invalid_names = names.reject { |name| name =~ PARAM_NAME }
309
- return if invalid_names.empty?
310
-
311
- raise ArgumentError, "Invalid attr_config name: #{invalid_names.join(", ")}.\n" \
312
- "Valid names must satisfy /#{PARAM_NAME.source}/."
313
- end
314
- end
315
-
316
- on_load :validate_required_attributes!
317
-
318
- attr_reader :config_name, :env_prefix
319
-
320
- # Instantiate config instance.
321
- #
322
- # Example:
323
- #
324
- # my_config = Anyway::Config.new()
325
- #
326
- # # provide some values explicitly
327
- # my_config = Anyway::Config.new({some: :value})
328
- #
329
- def initialize(overrides = nil)
330
- @config_name = self.class.config_name
331
-
332
- raise ArgumentError, "Config name is missing" unless @config_name
333
-
334
- @env_prefix = self.class.env_prefix
335
- @values = {}
336
-
337
- load(overrides)
338
- end
339
-
340
- def reload(overrides = nil)
341
- clear
342
- load(overrides)
343
- self
344
- end
345
-
346
- def clear
347
- values.clear
348
- @__trace__ = nil
349
- self
350
- end
351
-
352
- def load(overrides = nil)
353
- base_config = self.class.defaults.deep_dup
354
-
355
- trace = Tracing.capture do
356
- Tracing.trace!(:defaults) { base_config }
357
-
358
- config_path = resolve_config_path(config_name, env_prefix)
359
-
360
- load_from_sources(
361
- base_config,
362
- name: config_name,
363
- env_prefix: env_prefix,
364
- config_path: config_path,
365
- **self.class.loader_options
366
- )
367
-
368
- if overrides
369
- Tracing.trace!(:load) { overrides }
370
-
371
- Utils.deep_merge!(base_config, overrides)
372
- end
373
- end
374
-
375
- base_config.each do |key, val|
376
- write_config_attr(key.to_sym, val)
377
- end
378
-
379
- # Trace may contain unknown attributes
380
- trace&.keep_if { |key| self.class.config_attributes.include?(key.to_sym) }
381
-
382
- # Run on_load callbacks
383
- self.class.load_callbacks.each { |_1| it = _1;it.apply_to(self) }
384
-
385
- # Set trace after we write all the values to
386
- # avoid changing the source to accessor
387
- @__trace__ = trace
388
-
389
- self
390
- end
391
-
392
- def load_from_sources(base_config, **opts)
393
- Anyway.loaders.each do |(_id, loader)|
394
- Utils.deep_merge!(base_config, loader.call(**opts))
395
- end
396
- base_config
397
- end
398
-
399
- def dig(*__rest__) ; values.dig(*__rest__); end
400
-
401
- def to_h() ; values.deep_dup.deep_freeze; end
402
-
403
- def dup
404
- self.class.allocate.tap do |new_config|
405
- %i[config_name env_prefix __trace__].each do |ivar|
406
- new_config.instance_variable_set(:"@#{ivar}", send(ivar).dup)
407
- end
408
- new_config.instance_variable_set(:@values, values.deep_dup)
409
- end
410
- end
411
-
412
- def resolve_config_path(name, env_prefix)
413
- Anyway.env.fetch(env_prefix).delete("conf") || Settings.default_config_path.call(name)
414
- end
415
-
416
- def deconstruct_keys(keys) ; values.deconstruct_keys(keys); end
417
-
418
- def to_source_trace() ; __trace__&.to_h; end
419
-
420
- def inspect
421
- "#<#{self.class}:0x#{vm_object_id.rjust(16, "0")} config_name=\"#{config_name}\" env_prefix=\"#{env_prefix}\" " \
422
- "values=#{values.inspect}>"
423
- end
424
-
425
- def pretty_print(q)
426
- q.object_group self do
427
- q.nest(1) do
428
- q.breakable
429
- q.text "config_name=#{config_name.inspect}"
430
- q.breakable
431
- q.text "env_prefix=#{env_prefix.inspect}"
432
- q.breakable
433
- q.text "values:"
434
- q.pp __trace__
435
- end
436
- end
437
- end
438
-
439
- def as_env
440
- Env.from_hash(to_h, prefix: env_prefix)
441
- end
442
-
443
- private
444
-
445
- attr_reader :values, :__trace__
446
-
447
- def validate_required_attributes!
448
- return if Settings.suppress_required_validations
449
-
450
- self.class.required_attributes.select do |name|
451
- val = values.dig(*name.to_s.split(".").map(&:to_sym))
452
- val.nil? || (val.is_a?(String) && val.empty?)
453
- end.then do |missing|
454
- next if missing.empty?
455
- raise_validation_error "The following config parameters for `#{self.class.name}(config_name: #{self.class.config_name})` are missing or empty: #{missing.join(", ")}"
456
- end
457
- end
458
-
459
- def write_config_attr(key, val)
460
- key = key.to_sym
461
- return unless self.class.config_attributes.include?(key)
462
-
463
- val = __type_caster__.coerce(key, val)
464
- public_send(:"#{key}=", val)
465
- end
466
-
467
- def raise_validation_error(msg)
468
- raise ValidationError, msg
469
- end
470
-
471
- def __type_caster__
472
- self.class.type_caster
473
- end
474
- end
475
- end