Class: ParamsProcessor::Validate

Inherits:
Object
  • Object
show all
Defined in:
lib/params_processor/validate.rb

Class Method Summary collapse

Class Method Details

._number_typeObject



59
60
61
62
63
64
65
# File 'lib/params_processor/validate.rb', line 59

def _number_type
  case @doc.format
  when 'float'  then @str_input.match?(/^[-+]?\d*\.?\d+$/)
  when 'double' then @str_input.match?(/^[-+]?\d*\.?\d+$/)
  else true # TODO
  end or [:wrong_type, @doc.format.to_s]
end

._string_typeObject



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/params_processor/validate.rb', line 67

def _string_type
  # return false unless @input.is_a? String
  case @doc.format
  when 'date'      then parse_time!(Date)
  when 'date-time' then parse_time!(DateTime)
  when 'base64'    then Base64.strict_decode64(@input)
  when 'json'      then MultiJson.load(@input)
  else Config.strict_check ? @input.is_a?(String) : true
  end
rescue ArgumentError, MultiJson::ParseError
  false
end

.call(input, based_on:, raise: nil) ⇒ Object



9
10
11
12
# File 'lib/params_processor/validate.rb', line 9

def call(input, based_on:, raise: nil)
  @error_class = raise
  input(input).check! based_on
end

.check(msg) ⇒ Object

Raises:



177
178
179
180
181
182
183
184
185
186
187
# File 'lib/params_processor/validate.rb', line 177

def check msg
  return unless msg.is_a? Array
  @error_class.send("#{@doc.name}_#{msg.first}!") if @error_class.respond_to? "#{@doc.name}_#{msg.first}!"
  @error_class.send("#{msg.first}!") if @error_class.respond_to? msg.first
  raise ValidationFailed, Config.production_msg if Config.production_msg.present?

  test_msg = Config.send(msg.first) if Config.test
  msg = "#{Config.send(msg.first)}#{' ' + msg.last if msg.last.present?}"
  msg = " `#{@doc.name.to_sym}` " << msg
  raise ValidationFailed, test_msg || msg
end

.check!(param_doc) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/params_processor/validate.rb', line 20

def check!(param_doc)
  @doc = param_doc
  check (if_is_passed do
    check if_is_present
    break if @input.nil?# || (@doc.blankable != false && @input.blank? && @input != false)
    check_combined_types         if @doc.combined?
    check type                   if @doc.type
    check size                   if @doc.size
    check if_is_entity           if @doc.is
    check if_in_allowable_values if @doc.enum
    check if_match_pattern       if @doc.pattern
    check if_is_in_range         if @doc.range
    check_each_element           if @doc.type == 'array'
    check_each_pair              if @doc.type == 'object'
  end)
end

.check_combined_typesObject



122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/params_processor/validate.rb', line 122

def check_combined_types
  @doc.combined.each do |mode, schemas|
    results = check_each_schema(schemas)

    case mode
    when :all_of then results.all?(&:present?)
    when :one_of then results.count(true) == 1
    when :any_of then results.include?(true)
    when :not    then results.all?(&:blank?)
    end or raise ValidationFailed, " `#{@doc.name.to_sym}` #{Config.wrong_combined_type} #{mode} the specified schemas."
  end
end

.check_each_elementObject



152
153
154
155
156
157
158
159
160
161
# File 'lib/params_processor/validate.rb', line 152

def check_each_element
  return if @doc.items.blank?

  _doc, _input = @doc, @input
  items_doc = ParamDoc.new name: @doc.name, schema: @doc.items
  @input.each do |input|
    Validate.(input, based_on: items_doc, raise: @error_class)
  end
  @doc, @input = _doc, _input
end

.check_each_pairObject



163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/params_processor/validate.rb', line 163

def check_each_pair
  return if @doc.props.blank?

  _doc = @doc
  required = (@doc[:schema][:required] || [ ]).map(&:to_s)
  @doc.props.each do |name, schema|
    prop_doc = ParamDoc.new name: name, required: required.include?(name), schema: schema
    _input = @input
    Validate.(@input[name] || @input[name.to_sym], based_on: prop_doc, raise: @error_class)
    @input = _input
  end
  @doc = _doc
end

.check_each_schema(schemas) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/params_processor/validate.rb', line 135

def check_each_schema(schemas)
  results = [ ]
  strict_check = Config.strict_check.clone
  _doc, Config.strict_check = @doc, true
  schemas.each do |schema|
    doc = ParamDoc.new name: @doc.name, schema: schema
    begin
      Validate.(@input, based_on: doc, raise: @error_class)
      results << true
    rescue ValidationFailed
      results << false
    end
  end
  @doc, Config.strict_check = _doc, strict_check
  results
end

.if_in_allowable_valuesObject



95
96
97
98
99
100
# File 'lib/params_processor/validate.rb', line 95

def if_in_allowable_values
  case @doc.type
  when 'integer' then @doc.enum.include?(@input.to_i)
  else @doc.enum.map(&:to_s).include?(@str_input)
  end or [:not_in_allowable_values, @doc.enum.to_s.delete('\"')]
end

.if_is_entityObject



88
89
90
91
92
93
# File 'lib/params_processor/validate.rb', line 88

def if_is_entity
  case @doc.is
  when 'email'; @str_input.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]{2,}\z/i)
  else true # TODO
  end or [:is_not_entity, @doc.is.to_s]
end

.if_is_in_rangeObject



108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/params_processor/validate.rb', line 108

def if_is_in_range
  rg = @doc.range
  fmt = @doc.format.tr('-', '_').camelize.constantize if @doc.format&.match?('date')
  min = fmt ? parse_time!(fmt, rg[:min] || '1-1-1') : rg[:min]
  max = fmt ? parse_time!(fmt, rg[:max] || '9999-12-31') : rg[:max]
  @input = fmt ? parse_time!(fmt, @input) : @input.to_f

  left_op  = rg[:should_neq_min?] ? :< : :<=
  right_op = rg[:should_neq_max?] ? :< : :<=
  is_in_range = min&.send(left_op, @input)
  is_in_range &= @input.send(right_op, max)
  [:out_of_range, "#{min} #{left_op} x #{right_op} #{max}"] unless is_in_range
end

.if_is_passed(&block) ⇒ Object



37
38
39
40
# File 'lib/params_processor/validate.rb', line 37

def if_is_passed(&block)
  return [:not_passed, ''] if @doc.required && @input.nil?
  self.instance_eval(&block) unless @input.nil?
end

.if_is_presentObject



42
43
44
# File 'lib/params_processor/validate.rb', line 42

def if_is_present
  [:is_blank, ''] if @doc.blankable == false && @input.blank? && @input != false
end

.if_match_patternObject



102
103
104
105
106
# File 'lib/params_processor/validate.rb', line 102

def if_match_pattern
  unless @str_input.match?(Regexp.new(@doc.pattern))
    [:not_match_pattern, "/#{@doc.pattern}/"]
  end
end

.input(input) ⇒ Object



14
15
16
17
18
# File 'lib/params_processor/validate.rb', line 14

def input(input)
  @input     = input
  @str_input = input.to_s
  self
end

.parse_time!(cls, value = nil) ⇒ Object



189
190
191
192
193
194
195
# File 'lib/params_processor/validate.rb', line 189

def parse_time!(cls, value = nil)
  if @doc.pattern
    cls.send(:strptime, value || @input, @doc.pattern)
  else
    cls.send(:parse, value || @input)
  end
end

.sizeObject



80
81
82
83
84
85
86
# File 'lib/params_processor/validate.rb', line 80

def size
  if @doc.type.in? %w[ array object ]
    @input.size >= @doc.size[:min] && @input.size <= @doc.size[:max]
  else
    @str_input.length >= @doc.size[:min] && @str_input.length <= @doc.size[:max]
  end or [:wrong_size, @doc.size.values.join('..')]
end

.typeObject

TODO: combined type



47
48
49
50
51
52
53
54
55
56
57
# File 'lib/params_processor/validate.rb', line 47

def type
  case @doc.type
  when 'integer' then @str_input.match?(/^-?\d*$/)
  when 'boolean' then @str_input.in? %w[ true 1 false 0 ]
  when 'array'   then @input.is_a? Array
  when 'object'  then @input.is_a?(ActionController::Parameters) || @input.is_a?(Hash)
  when 'number'  then _number_type
  when 'string'  then _string_type
  else true # TODO
  end or [:wrong_type, @doc.format.to_s]
end