Class: Tina4::Validator

Inherits:
Object
  • Object
show all
Defined in:
lib/tina4/validator.rb

Overview

Request body validator with chainable rules.

Usage:

validator = Tina4::Validator.new(request.body)
validator.required("name", "email")
         .email("email")
         .min_length("name", 2)
         .max_length("name", 100)
         .integer("age")
         .min("age", 0)
         .max("age", 150)
         .in_list("role", ["admin", "user", "guest"])
         .regex("phone", /^\+?[\d\s\-]+$/)

unless validator.is_valid?
  return response.error("VALIDATION_FAILED", validator.errors.first[:message], 400)
end

Constant Summary collapse

EMAIL_REGEX =
/\A[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}\z/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data = {}) ⇒ Validator

Returns a new instance of Validator.



27
28
29
30
31
32
# File 'lib/tina4/validator.rb', line 27

def initialize(data = {})
  @data = data.is_a?(Hash) ? data : {}
  # Normalise keys to strings for consistent lookup
  @data = @data.transform_keys(&:to_s) unless @data.empty?
  @validation_errors = []
end

Instance Attribute Details

#validation_errorsObject (readonly)

Returns the value of attribute validation_errors.



23
24
25
# File 'lib/tina4/validator.rb', line 23

def validation_errors
  @validation_errors
end

Instance Method Details

#email(field) ⇒ Object

Check that a field contains a valid email address.



47
48
49
50
51
52
53
54
55
56
# File 'lib/tina4/validator.rb', line 47

def email(field)
  key = field.to_s
  value = @data[key]
  return self if value.nil?

  unless value.is_a?(String) && value.match?(EMAIL_REGEX)
    @validation_errors << { field: key, message: "#{key} must be a valid email address" }
  end
  self
end

#errorsObject

Return the list of validation errors (empty if valid).



162
163
164
# File 'lib/tina4/validator.rb', line 162

def errors
  @validation_errors.dup
end

#in_list(field, allowed) ⇒ Object

Check that a field’s value is one of the allowed values.



137
138
139
140
141
142
143
144
145
146
# File 'lib/tina4/validator.rb', line 137

def in_list(field, allowed)
  key = field.to_s
  value = @data[key]
  return self if value.nil?

  unless allowed.include?(value)
    @validation_errors << { field: key, message: "#{key} must be one of #{allowed}" }
  end
  self
end

#integer(field) ⇒ Object

Check that a field is an integer (or can be parsed as one).



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/tina4/validator.rb', line 83

def integer(field)
  key = field.to_s
  value = @data[key]
  return self if value.nil?

  if value.is_a?(Integer)
    return self
  end

  begin
    Integer(value)
  rescue ArgumentError, TypeError
    @validation_errors << { field: key, message: "#{key} must be an integer" }
  end
  self
end

#is_valid?Boolean Also known as: valid?

Return true if no validation errors have been recorded.

Returns:

  • (Boolean)


167
168
169
# File 'lib/tina4/validator.rb', line 167

def is_valid?
  @validation_errors.empty?
end

#max(field, maximum) ⇒ Object

Check that a numeric field is <= maximum.



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/tina4/validator.rb', line 119

def max(field, maximum)
  key = field.to_s
  value = @data[key]
  return self if value.nil?

  begin
    num = Float(value)
  rescue ArgumentError, TypeError
    return self
  end

  if num > maximum
    @validation_errors << { field: key, message: "#{key} must be at most #{maximum}" }
  end
  self
end

#max_length(field, length) ⇒ Object

Check that a string field has at most length characters.



71
72
73
74
75
76
77
78
79
80
# File 'lib/tina4/validator.rb', line 71

def max_length(field, length)
  key = field.to_s
  value = @data[key]
  return self if value.nil?

  unless value.is_a?(String) && value.length <= length
    @validation_errors << { field: key, message: "#{key} must be at most #{length} characters" }
  end
  self
end

#min(field, minimum) ⇒ Object

Check that a numeric field is >= minimum.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/tina4/validator.rb', line 101

def min(field, minimum)
  key = field.to_s
  value = @data[key]
  return self if value.nil?

  begin
    num = Float(value)
  rescue ArgumentError, TypeError
    return self
  end

  if num < minimum
    @validation_errors << { field: key, message: "#{key} must be at least #{minimum}" }
  end
  self
end

#min_length(field, length) ⇒ Object

Check that a string field has at least length characters.



59
60
61
62
63
64
65
66
67
68
# File 'lib/tina4/validator.rb', line 59

def min_length(field, length)
  key = field.to_s
  value = @data[key]
  return self if value.nil?

  unless value.is_a?(String) && value.length >= length
    @validation_errors << { field: key, message: "#{key} must be at least #{length} characters" }
  end
  self
end

#regex(field, pattern) ⇒ Object

Check that a field matches a regular expression.



149
150
151
152
153
154
155
156
157
158
159
# File 'lib/tina4/validator.rb', line 149

def regex(field, pattern)
  key = field.to_s
  value = @data[key]
  return self if value.nil?

  regexp = pattern.is_a?(Regexp) ? pattern : Regexp.new(pattern)
  unless value.is_a?(String) && value.match?(regexp)
    @validation_errors << { field: key, message: "#{key} does not match the required format" }
  end
  self
end

#required(*fields) ⇒ Object

Check that one or more fields are present and non-empty.



35
36
37
38
39
40
41
42
43
44
# File 'lib/tina4/validator.rb', line 35

def required(*fields)
  fields.each do |field|
    key = field.to_s
    value = @data[key]
    if value.nil? || (value.is_a?(String) && value.strip.empty?)
      @validation_errors << { field: key, message: "#{key} is required" }
    end
  end
  self
end