This file is indexed.

/usr/lib/ruby/vendor_ruby/sequel/plugins/validation_helpers.rb is in ruby-sequel 4.1.1-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
module Sequel
  module Plugins
    # The validation_helpers plugin contains instance method equivalents for most of the legacy
    # class-level validations.  The names and APIs are different, though. Example:
    #
    #   Sequel::Model.plugin :validation_helpers
    #   class Album < Sequel::Model
    #     def validate
    #       super
    #       validates_min_length 1, :num_tracks
    #     end
    #   end
    #
    # The validates_unique method has a unique API, but the other validations have the API explained here:
    #
    # Arguments:
    # atts :: Single attribute symbol or an array of attribute symbols specifying the
    #         attribute(s) to validate.
    # Options:
    # :allow_blank :: Whether to skip the validation if the value is blank.  You should
    #                 make sure all objects respond to blank if you use this option, which you can do by:
    #     Sequel.extension :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.
    # :message :: The message to use.  Can be a string which is used directly, or a
    #             proc which is called.  If the validation method takes a argument before the array of attributes,
    #             that argument is passed as an argument to the proc.
    #
    # The default validation options for all models can be modified by
    # changing the values of the Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS hash.  You
    # change change the default options on a per model basis
    # by overriding a private instance method default_validation_helpers_options.
    #
    # By changing the default options, you can setup internationalization of the
    # error messages.  For example, you would modify the default options:
    #
    #   Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS.merge!(
    #     :exact_length=>{:message=>lambda{|exact| I18n.t("errors.exact_length", :exact => exact)}},
    #     :integer=>{:message=>lambda{I18n.t("errors.integer")}},
    #     ...
    #   )
    #
    # and then use something like this in your yaml translation file:
    #
    #   en:
    #     errors:
    #       exact_length: "is not %{exact} characters"
    #       integer: "is not a number"
    #
    # Note that if you want to support internationalization of Errors#full_messages,
    # you need to override the method.  Here's an example:
    #   
    #   class Sequel::Model::Errors
    #     ATTRIBUTE_JOINER = I18n.t('errors.joiner').freeze
    #     def full_messages
    #       inject([]) do |m, kv|
    #         att, errors = *kv
    #         att.is_a?(Array) ? Array(att).map!{|v| I18n.t("attributes.#{v}")} : att = I18n.t("attributes.#{att}")
    #         errors.each {|e| m << (e.is_a?(LiteralString) ? e : "#{Array(att).join(ATTRIBUTE_JOINER)} #{e}")}
    #         m
    #       end
    #     end
    #   end
    module ValidationHelpers
      # Default validation options used by Sequel.  Can be modified to change the error
      # messages for all models (e.g. for internationalization), or to set certain
      # default options for validations (e.g. :allow_nil=>true for all validates_format).
      DEFAULT_OPTIONS = {
        :exact_length=>{:message=>lambda{|exact| "is not #{exact} characters"}},
        :format=>{:message=>lambda{|with| 'is invalid'}},
        :includes=>{:message=>lambda{|set| "is not in range or set: #{set.inspect}"}},
        :integer=>{:message=>lambda{"is not a number"}},
        :length_range=>{:message=>lambda{|range| "is too short or too long"}},
        :max_length=>{:message=>lambda{|max| "is longer than #{max} characters"}, :nil_message=>lambda{"is not present"}},
        :min_length=>{:message=>lambda{|min| "is shorter than #{min} characters"}},
        :not_null=>{:message=>lambda{"is not present"}},
        :numeric=>{:message=>lambda{"is not a number"}},
        :type=>{:message=>lambda{|klass| klass.is_a?(Array) ? "is not a valid #{klass.join(" or ").downcase}" : "is not a valid #{klass.to_s.downcase}"}},
        :presence=>{:message=>lambda{"is not present"}},
        :unique=>{:message=>lambda{'is already taken'}}
      }

      module InstanceMethods 
        # Check that the attribute values are the given exact length.
        def validates_exact_length(exact, atts, opts=OPTS)
          validatable_attributes_for_type(:exact_length, atts, opts){|a,v,m| validation_error_message(m, exact) if v.nil? || v.length != exact}
        end

        # Check the string representation of the attribute value(s) against the regular expression with.
        def validates_format(with, atts, opts=OPTS)
          validatable_attributes_for_type(:format, atts, opts){|a,v,m| validation_error_message(m, with) unless v.to_s =~ with}
        end
    
        # Check attribute value(s) is included in the given set.
        def validates_includes(set, atts, opts=OPTS)
          validatable_attributes_for_type(:includes, atts, opts){|a,v,m| validation_error_message(m, set) unless set.send(set.respond_to?(:cover?) ? :cover? : :include?, v)}
        end
    
        # Check attribute value(s) string representation is a valid integer.
        def validates_integer(atts, opts=OPTS)
          validatable_attributes_for_type(:integer, atts, opts) do |a,v,m|
            begin
              Kernel.Integer(v.to_s)
              nil
            rescue
              validation_error_message(m)
            end
          end
        end

        # Check that the attribute values length is in the specified range.
        def validates_length_range(range, atts, opts=OPTS)
          validatable_attributes_for_type(:length_range, atts, opts){|a,v,m| validation_error_message(m, range) if v.nil? || !range.send(range.respond_to?(:cover?) ? :cover? : :include?, v.length)}
        end
    
        # Check that the attribute values are not longer than the given max length.
        #
        # Accepts a :nil_message option that is the error message to use when the
        # value is nil instead of being too long.
        def validates_max_length(max, atts, opts=OPTS)
          validatable_attributes_for_type(:max_length, atts, opts){|a,v,m| v ? validation_error_message(m, max) : validation_error_message(opts[:nil_message] || DEFAULT_OPTIONS[:max_length][:nil_message]) if v.nil? || v.length > max}
        end

        # Check that the attribute values are not shorter than the given min length.
        def validates_min_length(min, atts, opts=OPTS)
          validatable_attributes_for_type(:min_length, atts, opts){|a,v,m| validation_error_message(m, min) if v.nil? || v.length < min}
        end

        # Check attribute value(s) are not NULL/nil.
        def validates_not_null(atts, opts=OPTS)
          validatable_attributes_for_type(:not_null, atts, opts){|a,v,m| validation_error_message(m) if v.nil?}
        end
        
        # Check attribute value(s) string representation is a valid float.
        def validates_numeric(atts, opts=OPTS)
          validatable_attributes_for_type(:numeric, atts, opts) do |a,v,m|
            begin
              Kernel.Float(v.to_s)
              nil
            rescue
              validation_error_message(m)
            end
          end
        end

        # Validates for all of the model columns (or just the given columns)
        # that the column value is an instance of the expected class based on
        # the column's schema type.
        def validates_schema_types(atts=keys, opts=OPTS)
          Array(atts).each do |k|
            if type = schema_type_class(k)
              validates_type(type, k, {:allow_nil=>true}.merge(opts))
            end
          end
        end

        # Check if value is an instance of a class.  If +klass+ is an array,
        # the value must be an instance of one of the classes in the array.
        def validates_type(klass, atts, opts=OPTS)
          klass = klass.to_s.constantize if klass.is_a?(String) || klass.is_a?(Symbol)
          validatable_attributes_for_type(:type, atts, opts) do |a,v,m|
            if klass.is_a?(Array) ? !klass.any?{|kls| v.is_a?(kls)} : !v.is_a?(klass)
              validation_error_message(m, klass)
            end
          end
        end

        # Check attribute value(s) is not considered blank by the database, but allow false values.
        def validates_presence(atts, opts=OPTS)
          validatable_attributes_for_type(:presence, atts, opts){|a,v,m| validation_error_message(m) if model.db.send(:blank_object?, v) && v != false}
        end
        
        # Checks that there are no duplicate values in the database for the given
        # attributes.  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_unique([:column1, :column2])
        # validates the grouping of column1 and column2 while
        #   validates_unique(:column1, :column2)
        # validates them separately.
        #
        # You can pass a block, which is yielded the dataset in which the columns
        # must be unique. So if you are doing a soft delete of records, in which
        # the name must be unique, but only for active records:
        #
        #   validates_unique(:name){|ds| ds.filter(:active)}
        #
        # You should also add a unique index in the
        # database, as this suffers from a fairly obvious race condition.
        #
        # This validation does not respect the :allow_* options that the other validations accept,
        # since it can deal with a grouping of multiple attributes.
        #
        # Possible Options:
        # :message :: The message to use (default: 'is already taken')
        # :only_if_modified :: Only check the uniqueness if the object is new or
        #                      one of the columns has been modified.
        # :where :: A callable object where call takes three arguments, a dataset,
        #           the current object, and an array of columns, and should return
        #           a modified dataset that is filtered to include only rows with
        #           the same values as the current object for each column in the array.
        #
        # If you want to to a case insensitive uniqueness validation on a database that
        # is case sensitive by default, you can use:
        #
        #   :where=>(proc do |ds, obj, cols|
        #     ds.where(cols.map do |c|
        #       v = obj.send(c)
        #       v = v.downcase if v
        #       [Sequel.function(:lower, c), v]
        #     end)
        #   end)
        def validates_unique(*atts)
          opts = default_validation_helpers_options(:unique)
          if atts.last.is_a?(Hash)
            opts = opts.merge(atts.pop)
          end
          message = validation_error_message(opts[:message])
          where = opts[:where]
          atts.each do |a|
            arr = Array(a)
            next if arr.any?{|x| errors.on(x)}
            next if opts[:only_if_modified] && !new? && !arr.any?{|x| changed_columns.include?(x)}
            ds = if where
              where.call(model.dataset, self, arr)
            else
              vals = arr.map{|x| send(x)}
              next if vals.any?{|v| v.nil?}
              model.where(arr.zip(vals))
            end
            ds = yield(ds) if block_given?
            ds = ds.exclude(pk_hash) unless new?
            errors.add(a, message) unless ds.count == 0
          end
        end
        
        private
        
        # The default options hash for the given type of validation.  Can
        # be overridden on a per-model basis for different per model defaults.
        # The hash return must include a :message option that is either a
        # proc or string.
        def default_validation_helpers_options(type)
          DEFAULT_OPTIONS[type]
        end

        # Skip validating any attribute that matches one of the allow_* options.
        # Otherwise, yield the attribute, value, and passed option :message to
        # the block.  If the block returns anything except nil or false, add it as
        # an error message for that attributes.
        def validatable_attributes(atts, opts)
          am, an, ab, m = opts.values_at(:allow_missing, :allow_nil, :allow_blank, :message)
          Array(atts).each do |a|
            next if am && !values.has_key?(a)
            v = send(a)
            next if an && v.nil?
            next if ab && v.respond_to?(:blank?) && v.blank?
            if message = yield(a, v, m)
              errors.add(a, message)
            end
          end
        end
        
        # Merge the given options with the default options for the given type
        # and call validatable_attributes with the merged options.
        def validatable_attributes_for_type(type, atts, opts, &block)
          validatable_attributes(atts, default_validation_helpers_options(type).merge(opts), &block)
        end
        
        # The validation error message to use, as a string.  If message
        # is a Proc, call it with the args.  Otherwise, assume it is a string and
        # return it.
        def validation_error_message(message, *args)
          message.is_a?(Proc) ? message.call(*args) : message
        end
      end
    end
  end
end