This file is indexed.

/usr/lib/ruby/vendor_ruby/sequel/plugins/validation_class_methods.rb is in ruby-sequel 3.33.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
module Sequel
  extension :blank

  module Plugins
    # Sequel's built-in validation_class_methods plugin adds backwards compatibility
    # for the legacy class-level validation methods (e.g. validates_presence_of :column).
    #
    # It is recommended to use the validation_helpers plugin instead of this one,
    # as it is less complex and more flexible.  However, this plugin provides reflection
    # support, since it is class-level, while the instance-level validation_helpers
    # plugin does not.
    # 
    # Usage:
    #
    #   # Add the validation class methods to all model subclasses (called before loading subclasses)
    #   Sequel::Model.plugin :validation_class_methods
    #
    #   # Add the validation class methods to the Album class
    #   Album.plugin :validation_class_methods
    module ValidationClassMethods
      # Setup the validations hash for the given model.
      def self.apply(model)
        model.class_eval do
          @validation_mutex = Mutex.new
          @validations = {}
          @validation_reflections = {}
        end
      end

      module ClassMethods
        # A hash of validations for this model class.  Keys are column symbols,
        # values are arrays of validation procs.
        attr_reader :validations

        # A hash of validation reflections for this model class.  Keys are column
        # symbols, values are an array of two element arrays, with the first element
        # being the validation type symbol and the second being a hash of validation
        # options.
        attr_reader :validation_reflections

        # The Generator class is used to generate validation definitions using 
        # the validates {} idiom.
        class Generator
          # Initializes a new generator.
          def initialize(receiver ,&block)
            @receiver = receiver
            instance_eval(&block)
          end
      
          # Delegates method calls to the receiver by calling receiver.validates_xxx.
          def method_missing(m, *args, &block)
            @receiver.send(:"validates_#{m}", *args, &block)
          end
        end
    
        # Returns true if validations are defined.
        def has_validations?
          !validations.empty?
        end

        # Setup the validations and validation_reflections hash in the subclass.
        def inherited(subclass)
          super
          vr = @validation_reflections
          subclass.class_eval do
            @validation_mutex = Mutex.new
            @validations = {}
            h = {}
            vr.each{|k,v| h[k] = v.dup}
            @validation_reflections = h
          end
        end
    
        # Instructs the model to skip validations defined in superclasses
        def skip_superclass_validations
          @skip_superclass_validations = true
        end
        
        # Instructs the model to skip validations defined in superclasses
        def skip_superclass_validations?
          defined?(@skip_superclass_validations) && @skip_superclass_validations
        end

        # Defines validations by converting a longhand block into a series of 
        # shorthand definitions. For example:
        #
        #   class MyClass < Sequel::Model
        #     validates do
        #       length_of :name, :minimum => 6
        #       length_of :password, :minimum => 8
        #     end
        #   end
        #
        # is equivalent to:
        #   class MyClass < Sequel::Model
        #     validates_length_of :name, :minimum => 6
        #     validates_length_of :password, :minimum => 8
        #   end
        def validates(&block)
          Generator.new(self, &block)
        end
    
        # Validates the given instance.
        def validate(o)
          superclass.validate(o) if superclass.respond_to?(:validate) && !skip_superclass_validations?
          validations.each do |att, procs|
            v = case att
            when Array
              att.collect{|a| o.send(a)}
            else
              o.send(att)
            end
            procs.each {|tag, p| p.call(o, att, v)}
          end
        end
        
        # Validates acceptance of an attribute.  Just checks that the value
        # is equal to the :accept option. This method is unique in that
        # :allow_nil is assumed to be true instead of false.
        #
        # Possible Options:
        # * :accept - The value required for the object to be valid (default: '1')
        # * :message - The message to use (default: 'is not accepted')
        def validates_acceptance_of(*atts)
          opts = {
            :message => 'is not accepted',
            :allow_nil => true,
            :accept => '1',
            :tag => :acceptance,
          }.merge!(extract_options!(atts))
          reflect_validation(:acceptance, opts, atts)
          atts << opts
          validates_each(*atts) do |o, a, v|
            o.errors.add(a, opts[:message]) unless v == opts[:accept]
          end
        end
    
        # Validates confirmation of an attribute. Checks that the object has
        # a _confirmation value matching the current value.  For example:
        #
        #   validates_confirmation_of :blah
        #
        # Just makes sure that object.blah = object.blah_confirmation.  Often used for passwords
        # or email addresses on web forms.
        #
        # Possible Options:
        # * :message - The message to use (default: 'is not confirmed')
        def validates_confirmation_of(*atts)
          opts = {
            :message => 'is not confirmed',
            :tag => :confirmation,
          }.merge!(extract_options!(atts))
          reflect_validation(:confirmation, opts, atts)
          atts << opts
          validates_each(*atts) do |o, a, v|
            o.errors.add(a, opts[:message]) unless v == o.send(:"#{a}_confirmation")
          end
        end
    
        # Adds a validation for each of the given attributes using the supplied
        # block. The block must accept three arguments: instance, attribute and 
        # value, e.g.:
        #
        #   validates_each :name, :password do |object, attribute, value|
        #     object.errors.add(attribute, 'is not nice') unless value.nice?
        #   end
        #
        # Possible Options:
        # * :allow_blank - Whether to skip the validation if the value is blank. 
        # * :allow_missing - Whether to skip the validation if the attribute isn't a key in the
        #   values hash.  This is different from allow_nil, because Sequel only sends the attributes
        #   in the values when doing an insert or update.  If the attribute is not present, Sequel
        #   doesn't specify it, so the database will use the table's default value.  This is different
        #   from having an attribute in values with a value of nil, which Sequel will send as NULL.
        #   If your database table has a non NULL default, this may be a good option to use.  You
        #   don't want to use allow_nil, because if the attribute is in values but has a value nil,
        #   Sequel will attempt to insert a NULL value into the database, instead of using the
        #   database's default.
        # * :allow_nil - Whether to skip the validation if the value is nil.
        # * :if - A symbol (indicating an instance_method) or proc (which is instance_evaled)
        #   skipping this validation if it returns nil or false.
        # * :tag - The tag to use for this validation.
        def validates_each(*atts, &block)
          opts = extract_options!(atts)
          blk = if (i = opts[:if]) || (am = opts[:allow_missing]) || (an = opts[:allow_nil]) || (ab = opts[:allow_blank])
            proc do |o,a,v|
              next if i && !validation_if_proc(o, i)
              next if an && Array(v).all?{|x| x.nil?}
              next if ab && Array(v).all?{|x| x.blank?}
              next if am && Array(a).all?{|x| !o.values.has_key?(x)}
              block.call(o,a,v)
            end
          else
            block
          end
          tag = opts[:tag]
          atts.each do |a| 
            a_vals = @validation_mutex.synchronize{validations[a] ||= []}
            if tag && (old = a_vals.find{|x| x[0] == tag})
              old[1] = blk
            else
              a_vals << [tag, blk]
            end
          end
        end
    
        # Validates the format of an attribute, checking the string representation of the
        # value against the regular expression provided by the :with option.
        #
        # Possible Options:
        # * :message - The message to use (default: 'is invalid')
        # * :with - The regular expression to validate the value with (required).
        def validates_format_of(*atts)
          opts = {
            :message => 'is invalid',
            :tag => :format,
          }.merge!(extract_options!(atts))
          
          unless opts[:with].is_a?(Regexp)
            raise ArgumentError, "A regular expression must be supplied as the :with option of the options hash"
          end
          
          reflect_validation(:format, opts, atts)
          atts << opts
          validates_each(*atts) do |o, a, v|
            o.errors.add(a, opts[:message]) unless v.to_s =~ opts[:with]
          end
        end
    
        # Validates the length of an attribute.
        #
        # Possible Options:
        # * :is - The exact size required for the value to be valid (no default)
        # * :maximum - The maximum size allowed for the value (no default)
        # * :message - The message to use (no default, overrides :nil_message, :too_long, :too_short, and :wrong_length
        #   options if present)
        # * :minimum - The minimum size allowed for the value (no default)
        # * :nil_message - The message to use use if :maximum option is used and the value is nil (default: 'is not present')
        # * :too_long - The message to use use if it the value is too long (default: 'is too long')
        # * :too_short - The message to use use if it the value is too short (default: 'is too short')
        # * :within - The array/range that must include the size of the value for it to be valid (no default)
        # * :wrong_length - The message to use use if it the value is not valid (default: 'is the wrong length')
        def validates_length_of(*atts)
          opts = {
            :nil_message  => 'is not present',
            :too_long     => 'is too long',
            :too_short    => 'is too short',
            :wrong_length => 'is the wrong length'
          }.merge!(extract_options!(atts))
          
          opts[:tag] ||= ([:length] + [:maximum, :minimum, :is, :within].reject{|x| !opts.include?(x)}).join('-').to_sym
          reflect_validation(:length, opts, atts)
          atts << opts
          validates_each(*atts) do |o, a, v|
            if m = opts[:maximum]
              o.errors.add(a, opts[:message] || (v ? opts[:too_long] : opts[:nil_message])) unless v && v.size <= m
            end
            if m = opts[:minimum]
              o.errors.add(a, opts[:message] || opts[:too_short]) unless v && v.size >= m
            end
            if i = opts[:is]
              o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && v.size == i
            end
            if w = opts[:within]
              o.errors.add(a, opts[:message] || opts[:wrong_length]) unless v && w.send(w.respond_to?(:cover?) ? :cover? : :include?, v.size)
            end
          end
        end
    
        # Validates whether an attribute is not a string.  This is generally useful
        # in conjunction with raise_on_typecast_failure = false, where you are
        # passing in string values for non-string attributes (such as numbers and dates).
        # If typecasting fails (invalid number or date), the value of the attribute will
        # be a string in an invalid format, and if typecasting succeeds, the value will
        # not be a string.
        #
        # Possible Options:
        # * :message - The message to use (default: 'is a string' or 'is not a valid (integer|datetime|etc.)' if the type is known)
        def validates_not_string(*atts)
          opts = {
            :tag => :not_string,
          }.merge!(extract_options!(atts))
          reflect_validation(:not_string, opts, atts)
          atts << opts
          validates_each(*atts) do |o, a, v|
            if v.is_a?(String)
              unless message = opts[:message]
                message = if sch = o.db_schema[a] and typ = sch[:type]
                  "is not a valid #{typ}"
                else
                  "is a string"
                end
              end
              o.errors.add(a, message)
            end
          end
        end
    
        # Validates whether an attribute is a number.
        #
        # Possible Options:
        # * :message - The message to use (default: 'is not a number')
        # * :only_integer - Whether only integers are valid values (default: false)
        def validates_numericality_of(*atts)
          opts = {
            :message => 'is not a number',
            :tag => :numericality,
          }.merge!(extract_options!(atts))
          reflect_validation(:numericality, opts, atts)
          atts << opts
          validates_each(*atts) do |o, a, v|
            begin
              if opts[:only_integer]
                Kernel.Integer(v.to_s)
              else
                Kernel.Float(v.to_s)
              end
            rescue
              o.errors.add(a, opts[:message])
            end
          end
        end
    
        # Validates the presence of an attribute.  Requires the value not be blank,
        # with false considered present instead of absent.
        #
        # Possible Options:
        # * :message - The message to use (default: 'is not present')
        def validates_presence_of(*atts)
          opts = {
            :message => 'is not present',
            :tag => :presence,
          }.merge!(extract_options!(atts))
          reflect_validation(:presence, opts, atts)
          atts << opts
          validates_each(*atts) do |o, a, v|
            o.errors.add(a, opts[:message]) if v.blank? && v != false
          end
        end
        
        # Validates that an attribute is within a specified range or set of values.
        #
        # Possible Options:
        # * :in - An array or range of values to check for validity (required)
        # * :message - The message to use (default: 'is not in range or set: <specified range>')
        def validates_inclusion_of(*atts)
          opts = extract_options!(atts)
          n = opts[:in]
          unless n && (n.respond_to?(:cover?) || n.respond_to?(:include?))
            raise ArgumentError, "The :in parameter is required, and must respond to cover? or include?"
          end
          opts[:message] ||= "is not in range or set: #{n.inspect}"
          reflect_validation(:inclusion, opts, atts)
          atts << opts
          validates_each(*atts) do |o, a, v|
            o.errors.add(a, opts[:message]) unless n.send(n.respond_to?(:cover?) ? :cover? : :include?, v)
          end
        end
    
        # Validates only if the fields in the model (specified by atts) are
        # unique in the database.  Pass an array of fields instead of multiple
        # fields to specify that the combination of fields must be unique,
        # instead of that each field should have a unique value.
        #
        # This means that the code:
        #   validates_uniqueness_of([:column1, :column2])
        # validates the grouping of column1 and column2 while
        #   validates_uniqueness_of(:column1, :column2)
        # validates them separately.
        #
        # You should also add a unique index in the
        # database, as this suffers from a fairly obvious race condition.
        #
        # Possible Options:
        # * :message - The message to use (default: 'is already taken')
        def validates_uniqueness_of(*atts)
          opts = {
            :message => 'is already taken',
            :tag => :uniqueness,
          }.merge!(extract_options!(atts))
    
          reflect_validation(:uniqueness, opts, atts)
          atts << opts
          validates_each(*atts) do |o, a, v|
            error_field = a
            a = Array(a)
            v = Array(v)
            ds = o.class.filter(a.zip(v))
            num_dups = ds.count
            allow = if num_dups == 0
              # No unique value in the database
              true
            elsif num_dups > 1
              # Multiple "unique" values in the database!!
              # Someone didn't add a unique index
              false
            elsif o.new?
              # New record, but unique value already exists in the database
              false
            elsif ds.first === o
              # Unique value exists in database, but for the same record, so the update won't cause a duplicate record
              true
            else
              false
            end
            o.errors.add(error_field, opts[:message]) unless allow
          end
        end
    
        private
    
        # Removes and returns the last member of the array if it is a hash. Otherwise,
        # an empty hash is returned This method is useful when writing methods that
        # take an options hash as the last parameter.
        def extract_options!(array)
          array.last.is_a?(Hash) ? array.pop : {}
        end

        # Add the validation reflection to the class's validations.
        def reflect_validation(type, opts, atts)
          atts.each do |att|
            (validation_reflections[att] ||= []) << [type, opts]
          end
        end

        # Handle the :if option for validations
        def validation_if_proc(o, i)
          case i
          when Symbol then o.send(i)
          when Proc then o.instance_eval(&i)
          when nil then true
          else raise(::Sequel::Error, "invalid value for :if validation option")
          end
        end
      end
    
      module InstanceMethods
        # Validates the object.
        def validate
          model.validate(self)
        end
      end
    end
  end
end