File: validator.rb

package info (click to toggle)
ruby-valid 1.0.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 128 kB
  • sloc: ruby: 309; makefile: 2
file content (125 lines) | stat: -rw-r--r-- 3,620 bytes parent folder | download | duplicates (3)
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
module Validation
  module Rules
    # A hash of rules for this object
    def rules
      @rules ||= {}
    end

    # A hash of errors for this object
    def errors
      @errors ||= {}
    end

    # Define a rule for this object
    #
    # The rule parameter can be one of the following:
    #
    # * a symbol that matches to a class in the Validation::Rule namespace
    #  * e.g. rule(:field, :not_empty)
    # * a hash containing the rule as the key and it's parameters as the values
    #  * e.g. rule(:field, :length => {:minimum => 3, :maximum => 5})
    # * an array combining the two previous types
    def rule(field, rule)
      field = field.to_sym
      if rules[field].nil?
        rules[field] = []
      end

      begin
        if rule.respond_to?(:each_pair)
          add_parameterized_rule(field, rule)
        elsif rule.respond_to?(:each)
          rule.each do |r|
            if r.respond_to?(:each_pair)
              add_parameterized_rule(field, r)
            else
              r = Validation::Rule.const_get(camelize(r)).new
              add_object_to_rule(r)
              rules[field] << r
            end
          end
        else
          rule = Validation::Rule.const_get(camelize(rule)).new
          add_object_to_rule(rule)
          rules[field] << rule
        end
      rescue NameError => e
        raise InvalidRule.new(e)
      end
      self
    end

    # Determines if this object is valid. When a rule fails for a field,
    # this will stop processing further rules. In this way, you'll only get
    # one error per field
    def valid?
      valid = true

      rules.each_pair do |field, rules|
        if ! @obj.respond_to?(field)
          raise InvalidKey
        end

        rules.each do |r|
          if ! r.valid_value?(@obj.send(field))
            valid = false
            errors[field] = {:rule => r.error_key, :params => r.params}
            break
          end
        end
      end

      @valid = valid
    end

    protected

    # Adds a parameterized rule to this object
    def add_parameterized_rule(field, rule)
      rule.each_pair do |key, value|
        r = Validation::Rule.const_get(camelize(key)).new(value)
        add_object_to_rule(r)
        rules[field] << r
      end
    end

    # Adds this validation object to a rule if it can accept it
    def add_object_to_rule(rule)
      if rule.respond_to?(:obj=)
        rule.obj = @obj
      end
    end

    # Converts a symbol to a class name, taken from rails
    def camelize(term)
      string = term.to_s
      string = string.sub(/^[a-z\d]*/) { $&.capitalize }
      string.gsub(/(?:_|(\/))([a-z\d]*)/i) { $2.capitalize }.gsub('/', '::')
    end
  end

  # Validator is a simple ruby validation class. You don't use it directly
  # inside your classes like just about every other ruby validation class out
  # there. I chose to implement it in this way so I didn't automatically
  # pollute the namespace of the objects I wanted to validate.
  #
  # This also solves the problem of validating forms very nicely. Frequently
  # you will have a form that represents many different data objects in your
  # system, and you can pre-validate everything before doing any saving.
  class Validator
    include Validation::Rules

    def initialize(obj)
      @rules = self.class.rules if self.class.is_a?(Validation::Rules)
      @obj = obj
    end
  end

  # InvalidKey is raised if a rule is added to a field that doesn't exist
  class InvalidKey < RuntimeError
  end

  # InvalidRule is raised if a rule is added that doesn't exist
  class InvalidRule < RuntimeError
  end
end