activemodel 5.2.3

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 (67) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +114 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +264 -0
  5. data/lib/active_model.rb +77 -0
  6. data/lib/active_model/attribute.rb +248 -0
  7. data/lib/active_model/attribute/user_provided_default.rb +52 -0
  8. data/lib/active_model/attribute_assignment.rb +57 -0
  9. data/lib/active_model/attribute_methods.rb +478 -0
  10. data/lib/active_model/attribute_mutation_tracker.rb +124 -0
  11. data/lib/active_model/attribute_set.rb +114 -0
  12. data/lib/active_model/attribute_set/builder.rb +126 -0
  13. data/lib/active_model/attribute_set/yaml_encoder.rb +41 -0
  14. data/lib/active_model/attributes.rb +111 -0
  15. data/lib/active_model/callbacks.rb +153 -0
  16. data/lib/active_model/conversion.rb +111 -0
  17. data/lib/active_model/dirty.rb +343 -0
  18. data/lib/active_model/errors.rb +517 -0
  19. data/lib/active_model/forbidden_attributes_protection.rb +31 -0
  20. data/lib/active_model/gem_version.rb +17 -0
  21. data/lib/active_model/lint.rb +118 -0
  22. data/lib/active_model/locale/en.yml +36 -0
  23. data/lib/active_model/model.rb +99 -0
  24. data/lib/active_model/naming.rb +318 -0
  25. data/lib/active_model/railtie.rb +14 -0
  26. data/lib/active_model/secure_password.rb +129 -0
  27. data/lib/active_model/serialization.rb +192 -0
  28. data/lib/active_model/serializers/json.rb +146 -0
  29. data/lib/active_model/translation.rb +70 -0
  30. data/lib/active_model/type.rb +53 -0
  31. data/lib/active_model/type/big_integer.rb +15 -0
  32. data/lib/active_model/type/binary.rb +52 -0
  33. data/lib/active_model/type/boolean.rb +38 -0
  34. data/lib/active_model/type/date.rb +57 -0
  35. data/lib/active_model/type/date_time.rb +51 -0
  36. data/lib/active_model/type/decimal.rb +70 -0
  37. data/lib/active_model/type/float.rb +36 -0
  38. data/lib/active_model/type/helpers.rb +7 -0
  39. data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +41 -0
  40. data/lib/active_model/type/helpers/mutable.rb +20 -0
  41. data/lib/active_model/type/helpers/numeric.rb +37 -0
  42. data/lib/active_model/type/helpers/time_value.rb +68 -0
  43. data/lib/active_model/type/helpers/timezone.rb +19 -0
  44. data/lib/active_model/type/immutable_string.rb +32 -0
  45. data/lib/active_model/type/integer.rb +70 -0
  46. data/lib/active_model/type/registry.rb +70 -0
  47. data/lib/active_model/type/string.rb +26 -0
  48. data/lib/active_model/type/time.rb +51 -0
  49. data/lib/active_model/type/value.rb +126 -0
  50. data/lib/active_model/validations.rb +439 -0
  51. data/lib/active_model/validations/absence.rb +33 -0
  52. data/lib/active_model/validations/acceptance.rb +106 -0
  53. data/lib/active_model/validations/callbacks.rb +122 -0
  54. data/lib/active_model/validations/clusivity.rb +54 -0
  55. data/lib/active_model/validations/confirmation.rb +80 -0
  56. data/lib/active_model/validations/exclusion.rb +49 -0
  57. data/lib/active_model/validations/format.rb +114 -0
  58. data/lib/active_model/validations/helper_methods.rb +15 -0
  59. data/lib/active_model/validations/inclusion.rb +47 -0
  60. data/lib/active_model/validations/length.rb +129 -0
  61. data/lib/active_model/validations/numericality.rb +189 -0
  62. data/lib/active_model/validations/presence.rb +39 -0
  63. data/lib/active_model/validations/validates.rb +174 -0
  64. data/lib/active_model/validations/with.rb +147 -0
  65. data/lib/active_model/validator.rb +183 -0
  66. data/lib/active_model/version.rb +10 -0
  67. metadata +125 -0
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModel
4
+ module Type
5
+ class Value
6
+ attr_reader :precision, :scale, :limit
7
+
8
+ def initialize(precision: nil, limit: nil, scale: nil)
9
+ @precision = precision
10
+ @scale = scale
11
+ @limit = limit
12
+ end
13
+
14
+ def type # :nodoc:
15
+ end
16
+
17
+ # Converts a value from database input to the appropriate ruby type. The
18
+ # return value of this method will be returned from
19
+ # ActiveRecord::AttributeMethods::Read#read_attribute. The default
20
+ # implementation just calls Value#cast.
21
+ #
22
+ # +value+ The raw input, as provided from the database.
23
+ def deserialize(value)
24
+ cast(value)
25
+ end
26
+
27
+ # Type casts a value from user input (e.g. from a setter). This value may
28
+ # be a string from the form builder, or a ruby object passed to a setter.
29
+ # There is currently no way to differentiate between which source it came
30
+ # from.
31
+ #
32
+ # The return value of this method will be returned from
33
+ # ActiveRecord::AttributeMethods::Read#read_attribute. See also:
34
+ # Value#cast_value.
35
+ #
36
+ # +value+ The raw input, as provided to the attribute setter.
37
+ def cast(value)
38
+ cast_value(value) unless value.nil?
39
+ end
40
+
41
+ # Casts a value from the ruby type to a type that the database knows how
42
+ # to understand. The returned value from this method should be a
43
+ # +String+, +Numeric+, +Date+, +Time+, +Symbol+, +true+, +false+, or
44
+ # +nil+.
45
+ def serialize(value)
46
+ value
47
+ end
48
+
49
+ # Type casts a value for schema dumping. This method is private, as we are
50
+ # hoping to remove it entirely.
51
+ def type_cast_for_schema(value) # :nodoc:
52
+ value.inspect
53
+ end
54
+
55
+ # These predicates are not documented, as I need to look further into
56
+ # their use, and see if they can be removed entirely.
57
+ def binary? # :nodoc:
58
+ false
59
+ end
60
+
61
+ # Determines whether a value has changed for dirty checking. +old_value+
62
+ # and +new_value+ will always be type-cast. Types should not need to
63
+ # override this method.
64
+ def changed?(old_value, new_value, _new_value_before_type_cast)
65
+ old_value != new_value
66
+ end
67
+
68
+ # Determines whether the mutable value has been modified since it was
69
+ # read. Returns +false+ by default. If your type returns an object
70
+ # which could be mutated, you should override this method. You will need
71
+ # to either:
72
+ #
73
+ # - pass +new_value+ to Value#serialize and compare it to
74
+ # +raw_old_value+
75
+ #
76
+ # or
77
+ #
78
+ # - pass +raw_old_value+ to Value#deserialize and compare it to
79
+ # +new_value+
80
+ #
81
+ # +raw_old_value+ The original value, before being passed to
82
+ # +deserialize+.
83
+ #
84
+ # +new_value+ The current value, after type casting.
85
+ def changed_in_place?(raw_old_value, new_value)
86
+ false
87
+ end
88
+
89
+ def value_constructed_by_mass_assignment?(_value) # :nodoc:
90
+ false
91
+ end
92
+
93
+ def force_equality?(_value) # :nodoc:
94
+ false
95
+ end
96
+
97
+ def map(value) # :nodoc:
98
+ yield value
99
+ end
100
+
101
+ def ==(other)
102
+ self.class == other.class &&
103
+ precision == other.precision &&
104
+ scale == other.scale &&
105
+ limit == other.limit
106
+ end
107
+ alias eql? ==
108
+
109
+ def hash
110
+ [self.class, precision, scale, limit].hash
111
+ end
112
+
113
+ def assert_valid_value(*)
114
+ end
115
+
116
+ private
117
+
118
+ # Convenience method for types which do not need separate type casting
119
+ # behavior for user and database inputs. Called by Value#cast for
120
+ # values except +nil+.
121
+ def cast_value(value) # :doc:
122
+ value
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,439 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/array/extract_options"
4
+ require "active_support/core_ext/hash/keys"
5
+ require "active_support/core_ext/hash/except"
6
+
7
+ module ActiveModel
8
+ # == Active \Model \Validations
9
+ #
10
+ # Provides a full validation framework to your objects.
11
+ #
12
+ # A minimal implementation could be:
13
+ #
14
+ # class Person
15
+ # include ActiveModel::Validations
16
+ #
17
+ # attr_accessor :first_name, :last_name
18
+ #
19
+ # validates_each :first_name, :last_name do |record, attr, value|
20
+ # record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
21
+ # end
22
+ # end
23
+ #
24
+ # Which provides you with the full standard validation stack that you
25
+ # know from Active Record:
26
+ #
27
+ # person = Person.new
28
+ # person.valid? # => true
29
+ # person.invalid? # => false
30
+ #
31
+ # person.first_name = 'zoolander'
32
+ # person.valid? # => false
33
+ # person.invalid? # => true
34
+ # person.errors.messages # => {first_name:["starts with z."]}
35
+ #
36
+ # Note that <tt>ActiveModel::Validations</tt> automatically adds an +errors+
37
+ # method to your instances initialized with a new <tt>ActiveModel::Errors</tt>
38
+ # object, so there is no need for you to do this manually.
39
+ module Validations
40
+ extend ActiveSupport::Concern
41
+
42
+ included do
43
+ extend ActiveModel::Naming
44
+ extend ActiveModel::Callbacks
45
+ extend ActiveModel::Translation
46
+
47
+ extend HelperMethods
48
+ include HelperMethods
49
+
50
+ attr_accessor :validation_context
51
+ private :validation_context=
52
+ define_callbacks :validate, scope: :name
53
+
54
+ class_attribute :_validators, instance_writer: false, default: Hash.new { |h, k| h[k] = [] }
55
+ end
56
+
57
+ module ClassMethods
58
+ # Validates each attribute against a block.
59
+ #
60
+ # class Person
61
+ # include ActiveModel::Validations
62
+ #
63
+ # attr_accessor :first_name, :last_name
64
+ #
65
+ # validates_each :first_name, :last_name, allow_blank: true do |record, attr, value|
66
+ # record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
67
+ # end
68
+ # end
69
+ #
70
+ # Options:
71
+ # * <tt>:on</tt> - Specifies the contexts where this validation is active.
72
+ # Runs in all validation contexts by default +nil+. You can pass a symbol
73
+ # or an array of symbols. (e.g. <tt>on: :create</tt> or
74
+ # <tt>on: :custom_validation_context</tt> or
75
+ # <tt>on: [:create, :custom_validation_context]</tt>)
76
+ # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
77
+ # * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
78
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
79
+ # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
80
+ # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
81
+ # proc or string should return or evaluate to a +true+ or +false+ value.
82
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to
83
+ # determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
84
+ # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
85
+ # method, proc or string should return or evaluate to a +true+ or +false+
86
+ # value.
87
+ def validates_each(*attr_names, &block)
88
+ validates_with BlockValidator, _merge_attributes(attr_names), &block
89
+ end
90
+
91
+ VALID_OPTIONS_FOR_VALIDATE = [:on, :if, :unless, :prepend].freeze # :nodoc:
92
+
93
+ # Adds a validation method or block to the class. This is useful when
94
+ # overriding the +validate+ instance method becomes too unwieldy and
95
+ # you're looking for more descriptive declaration of your validations.
96
+ #
97
+ # This can be done with a symbol pointing to a method:
98
+ #
99
+ # class Comment
100
+ # include ActiveModel::Validations
101
+ #
102
+ # validate :must_be_friends
103
+ #
104
+ # def must_be_friends
105
+ # errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
106
+ # end
107
+ # end
108
+ #
109
+ # With a block which is passed with the current record to be validated:
110
+ #
111
+ # class Comment
112
+ # include ActiveModel::Validations
113
+ #
114
+ # validate do |comment|
115
+ # comment.must_be_friends
116
+ # end
117
+ #
118
+ # def must_be_friends
119
+ # errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
120
+ # end
121
+ # end
122
+ #
123
+ # Or with a block where self points to the current record to be validated:
124
+ #
125
+ # class Comment
126
+ # include ActiveModel::Validations
127
+ #
128
+ # validate do
129
+ # errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
130
+ # end
131
+ # end
132
+ #
133
+ # Note that the return value of validation methods is not relevant.
134
+ # It's not possible to halt the validate callback chain.
135
+ #
136
+ # Options:
137
+ # * <tt>:on</tt> - Specifies the contexts where this validation is active.
138
+ # Runs in all validation contexts by default +nil+. You can pass a symbol
139
+ # or an array of symbols. (e.g. <tt>on: :create</tt> or
140
+ # <tt>on: :custom_validation_context</tt> or
141
+ # <tt>on: [:create, :custom_validation_context]</tt>)
142
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
143
+ # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
144
+ # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
145
+ # proc or string should return or evaluate to a +true+ or +false+ value.
146
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to
147
+ # determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
148
+ # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
149
+ # method, proc or string should return or evaluate to a +true+ or +false+
150
+ # value.
151
+ #
152
+ # NOTE: Calling +validate+ multiple times on the same method will overwrite previous definitions.
153
+ #
154
+ def validate(*args, &block)
155
+ options = args.extract_options!
156
+
157
+ if args.all? { |arg| arg.is_a?(Symbol) }
158
+ options.each_key do |k|
159
+ unless VALID_OPTIONS_FOR_VALIDATE.include?(k)
160
+ raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{VALID_OPTIONS_FOR_VALIDATE.map(&:inspect).join(', ')}. Perhaps you meant to call `validates` instead of `validate`?")
161
+ end
162
+ end
163
+ end
164
+
165
+ if options.key?(:on)
166
+ options = options.dup
167
+ options[:on] = Array(options[:on])
168
+ options[:if] = Array(options[:if])
169
+ options[:if].unshift ->(o) {
170
+ !(options[:on] & Array(o.validation_context)).empty?
171
+ }
172
+ end
173
+
174
+ set_callback(:validate, *args, options, &block)
175
+ end
176
+
177
+ # List all validators that are being used to validate the model using
178
+ # +validates_with+ method.
179
+ #
180
+ # class Person
181
+ # include ActiveModel::Validations
182
+ #
183
+ # validates_with MyValidator
184
+ # validates_with OtherValidator, on: :create
185
+ # validates_with StrictValidator, strict: true
186
+ # end
187
+ #
188
+ # Person.validators
189
+ # # => [
190
+ # # #<MyValidator:0x007fbff403e808 @options={}>,
191
+ # # #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
192
+ # # #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
193
+ # # ]
194
+ def validators
195
+ _validators.values.flatten.uniq
196
+ end
197
+
198
+ # Clears all of the validators and validations.
199
+ #
200
+ # Note that this will clear anything that is being used to validate
201
+ # the model for both the +validates_with+ and +validate+ methods.
202
+ # It clears the validators that are created with an invocation of
203
+ # +validates_with+ and the callbacks that are set by an invocation
204
+ # of +validate+.
205
+ #
206
+ # class Person
207
+ # include ActiveModel::Validations
208
+ #
209
+ # validates_with MyValidator
210
+ # validates_with OtherValidator, on: :create
211
+ # validates_with StrictValidator, strict: true
212
+ # validate :cannot_be_robot
213
+ #
214
+ # def cannot_be_robot
215
+ # errors.add(:base, 'A person cannot be a robot') if person_is_robot
216
+ # end
217
+ # end
218
+ #
219
+ # Person.validators
220
+ # # => [
221
+ # # #<MyValidator:0x007fbff403e808 @options={}>,
222
+ # # #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
223
+ # # #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
224
+ # # ]
225
+ #
226
+ # If one runs <tt>Person.clear_validators!</tt> and then checks to see what
227
+ # validators this class has, you would obtain:
228
+ #
229
+ # Person.validators # => []
230
+ #
231
+ # Also, the callback set by <tt>validate :cannot_be_robot</tt> will be erased
232
+ # so that:
233
+ #
234
+ # Person._validate_callbacks.empty? # => true
235
+ #
236
+ def clear_validators!
237
+ reset_callbacks(:validate)
238
+ _validators.clear
239
+ end
240
+
241
+ # List all validators that are being used to validate a specific attribute.
242
+ #
243
+ # class Person
244
+ # include ActiveModel::Validations
245
+ #
246
+ # attr_accessor :name , :age
247
+ #
248
+ # validates_presence_of :name
249
+ # validates_inclusion_of :age, in: 0..99
250
+ # end
251
+ #
252
+ # Person.validators_on(:name)
253
+ # # => [
254
+ # # #<ActiveModel::Validations::PresenceValidator:0x007fe604914e60 @attributes=[:name], @options={}>,
255
+ # # ]
256
+ def validators_on(*attributes)
257
+ attributes.flat_map do |attribute|
258
+ _validators[attribute.to_sym]
259
+ end
260
+ end
261
+
262
+ # Returns +true+ if +attribute+ is an attribute method, +false+ otherwise.
263
+ #
264
+ # class Person
265
+ # include ActiveModel::Validations
266
+ #
267
+ # attr_accessor :name
268
+ # end
269
+ #
270
+ # User.attribute_method?(:name) # => true
271
+ # User.attribute_method?(:age) # => false
272
+ def attribute_method?(attribute)
273
+ method_defined?(attribute)
274
+ end
275
+
276
+ # Copy validators on inheritance.
277
+ def inherited(base) #:nodoc:
278
+ dup = _validators.dup
279
+ base._validators = dup.each { |k, v| dup[k] = v.dup }
280
+ super
281
+ end
282
+ end
283
+
284
+ # Clean the +Errors+ object if instance is duped.
285
+ def initialize_dup(other) #:nodoc:
286
+ @errors = nil
287
+ super
288
+ end
289
+
290
+ # Returns the +Errors+ object that holds all information about attribute
291
+ # error messages.
292
+ #
293
+ # class Person
294
+ # include ActiveModel::Validations
295
+ #
296
+ # attr_accessor :name
297
+ # validates_presence_of :name
298
+ # end
299
+ #
300
+ # person = Person.new
301
+ # person.valid? # => false
302
+ # person.errors # => #<ActiveModel::Errors:0x007fe603816640 @messages={name:["can't be blank"]}>
303
+ def errors
304
+ @errors ||= Errors.new(self)
305
+ end
306
+
307
+ # Runs all the specified validations and returns +true+ if no errors were
308
+ # added otherwise +false+.
309
+ #
310
+ # class Person
311
+ # include ActiveModel::Validations
312
+ #
313
+ # attr_accessor :name
314
+ # validates_presence_of :name
315
+ # end
316
+ #
317
+ # person = Person.new
318
+ # person.name = ''
319
+ # person.valid? # => false
320
+ # person.name = 'david'
321
+ # person.valid? # => true
322
+ #
323
+ # Context can optionally be supplied to define which callbacks to test
324
+ # against (the context is defined on the validations using <tt>:on</tt>).
325
+ #
326
+ # class Person
327
+ # include ActiveModel::Validations
328
+ #
329
+ # attr_accessor :name
330
+ # validates_presence_of :name, on: :new
331
+ # end
332
+ #
333
+ # person = Person.new
334
+ # person.valid? # => true
335
+ # person.valid?(:new) # => false
336
+ def valid?(context = nil)
337
+ current_context, self.validation_context = validation_context, context
338
+ errors.clear
339
+ run_validations!
340
+ ensure
341
+ self.validation_context = current_context
342
+ end
343
+
344
+ alias_method :validate, :valid?
345
+
346
+ # Performs the opposite of <tt>valid?</tt>. Returns +true+ if errors were
347
+ # added, +false+ otherwise.
348
+ #
349
+ # class Person
350
+ # include ActiveModel::Validations
351
+ #
352
+ # attr_accessor :name
353
+ # validates_presence_of :name
354
+ # end
355
+ #
356
+ # person = Person.new
357
+ # person.name = ''
358
+ # person.invalid? # => true
359
+ # person.name = 'david'
360
+ # person.invalid? # => false
361
+ #
362
+ # Context can optionally be supplied to define which callbacks to test
363
+ # against (the context is defined on the validations using <tt>:on</tt>).
364
+ #
365
+ # class Person
366
+ # include ActiveModel::Validations
367
+ #
368
+ # attr_accessor :name
369
+ # validates_presence_of :name, on: :new
370
+ # end
371
+ #
372
+ # person = Person.new
373
+ # person.invalid? # => false
374
+ # person.invalid?(:new) # => true
375
+ def invalid?(context = nil)
376
+ !valid?(context)
377
+ end
378
+
379
+ # Runs all the validations within the specified context. Returns +true+ if
380
+ # no errors are found, raises +ValidationError+ otherwise.
381
+ #
382
+ # Validations with no <tt>:on</tt> option will run no matter the context. Validations with
383
+ # some <tt>:on</tt> option will only run in the specified context.
384
+ def validate!(context = nil)
385
+ valid?(context) || raise_validation_error
386
+ end
387
+
388
+ # Hook method defining how an attribute value should be retrieved. By default
389
+ # this is assumed to be an instance named after the attribute. Override this
390
+ # method in subclasses should you need to retrieve the value for a given
391
+ # attribute differently:
392
+ #
393
+ # class MyClass
394
+ # include ActiveModel::Validations
395
+ #
396
+ # def initialize(data = {})
397
+ # @data = data
398
+ # end
399
+ #
400
+ # def read_attribute_for_validation(key)
401
+ # @data[key]
402
+ # end
403
+ # end
404
+ alias :read_attribute_for_validation :send
405
+
406
+ private
407
+
408
+ def run_validations!
409
+ _run_validate_callbacks
410
+ errors.empty?
411
+ end
412
+
413
+ def raise_validation_error # :doc:
414
+ raise(ValidationError.new(self))
415
+ end
416
+ end
417
+
418
+ # = Active Model ValidationError
419
+ #
420
+ # Raised by <tt>validate!</tt> when the model is invalid. Use the
421
+ # +model+ method to retrieve the record which did not validate.
422
+ #
423
+ # begin
424
+ # complex_operation_that_internally_calls_validate!
425
+ # rescue ActiveModel::ValidationError => invalid
426
+ # puts invalid.model.errors
427
+ # end
428
+ class ValidationError < StandardError
429
+ attr_reader :model
430
+
431
+ def initialize(model)
432
+ @model = model
433
+ errors = @model.errors.full_messages.join(", ")
434
+ super(I18n.t(:"#{@model.class.i18n_scope}.errors.messages.model_invalid", errors: errors, default: :"errors.messages.model_invalid"))
435
+ end
436
+ end
437
+ end
438
+
439
+ Dir[File.expand_path("validations/*.rb", __dir__)].each { |file| require file }