Module: Rospatent::InputValidator

Included in:
Client, Search
Defined in:
lib/rospatent/input_validator.rb

Overview

Module for validating input parameters and converting types

Instance Method Summary collapse

Instance Method Details

#validate_array(value, field_name, max_size: nil, element_validator: nil) ⇒ Array

Validate array parameter

Parameters:

  • value (Array, nil)

    Array to validate

  • field_name (String)

    Name of the field for error messages

  • max_size (Integer, nil) (defaults to: nil)

    Maximum array size

  • element_validator (Proc, nil) (defaults to: nil)

    Proc to validate each element

Returns:

  • (Array)

    Validated array

Raises:

  • (ValidationError)

    If array is invalid



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
# File 'lib/rospatent/input_validator.rb', line 157

def validate_array(value, field_name, max_size: nil, element_validator: nil)
  return nil if value.nil?

  unless value.is_a?(Array)
    raise Errors::ValidationError,
          "Invalid #{field_name} type. Expected Array, got #{value.class}"
  end

  raise Errors::ValidationError, "#{field_name.capitalize} cannot be empty" if value.empty?

  if max_size && value.size > max_size
    raise Errors::ValidationError,
          "#{field_name.capitalize} cannot contain more than #{max_size} items"
  end

  if element_validator
    value.each_with_index do |element, index|
      element_validator.call(element)
    rescue Errors::ValidationError => e
      raise Errors::ValidationError,
            "Invalid #{field_name}[#{index}]: #{e.message}"
    rescue StandardError => e
      raise Errors::ValidationError,
            "Invalid #{field_name}[#{index}]: #{e.message}"
    end
  end

  value
end

#validate_date(date, field_name = "date") ⇒ Date

Validate and normalize date input

Parameters:

  • date (String, Date, nil)

    Date input to validate

  • field_name (String) (defaults to: "date")

    Name of the field for error messages

Returns:

  • (Date)

    Normalized Date object

Raises:

  • (ValidationError)

    If date format is invalid



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/rospatent/input_validator.rb', line 13

def validate_date(date, field_name = "date")
  return nil if date.nil?
  return date if date.is_a?(Date)

  if date.is_a?(String)
    begin
      return Date.parse(date)
    rescue Date::Error
      raise Errors::ValidationError,
            "Invalid #{field_name} format. Expected YYYY-MM-DD or Date object"
    end
  end

  raise Errors::ValidationError,
        "Invalid #{field_name} type. Expected String or Date, got #{date.class}"
end

#validate_enum(value, allowed_values, field_name) ⇒ Symbol

Validate enum value

Parameters:

  • value (Symbol, String, nil)

    Value to validate

  • allowed_values (Array)

    Array of allowed values

  • field_name (String)

    Name of the field for error messages

Returns:

  • (Symbol)

    Validated symbol

Raises:

  • (ValidationError)

    If value is not in allowed list



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/rospatent/input_validator.rb', line 133

def validate_enum(value, allowed_values, field_name)
  return nil if value.nil?

  # Convert to symbol for consistency
  value = value.to_sym if value.respond_to?(:to_sym)

  # Convert allowed values to symbols for comparison
  allowed_symbols = allowed_values.map(&:to_sym)

  unless allowed_symbols.include?(value)
    raise Errors::ValidationError,
          "Invalid #{field_name}. Allowed values: #{allowed_values.join(', ')}"
  end

  value
end

#validate_hash(value, field_name, required_keys: [], allowed_keys: nil) ⇒ Hash

Validate hash parameter

Parameters:

  • value (Hash, nil)

    Hash to validate

  • field_name (String)

    Name of the field for error messages

  • required_keys (Array) (defaults to: [])

    Required keys in the hash

  • allowed_keys (Array, nil) (defaults to: nil)

    Allowed keys (if nil, any keys allowed)

Returns:

  • (Hash)

    Validated hash

Raises:

  • (ValidationError)

    If hash is invalid



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
# File 'lib/rospatent/input_validator.rb', line 194

def validate_hash(value, field_name, required_keys: [], allowed_keys: nil)
  return nil if value.nil?

  unless value.is_a?(Hash)
    raise Errors::ValidationError,
          "Invalid #{field_name} type. Expected Hash, got #{value.class}"
  end

  # Check required keys
  missing_keys = required_keys.map(&:to_s) - value.keys.map(&:to_s)
  unless missing_keys.empty?
    raise Errors::ValidationError,
          "Missing required #{field_name} keys: #{missing_keys.join(', ')}"
  end

  # Check allowed keys if specified
  if allowed_keys
    invalid_keys = value.keys.map(&:to_s) - allowed_keys.map(&:to_s)
    unless invalid_keys.empty?
      raise Errors::ValidationError,
            "Invalid #{field_name} keys: #{invalid_keys.join(', ')}"
    end
  end

  value
end

#validate_params(params, validations) ⇒ Hash

Validate multiple parameters at once

Examples:

validate_params(
  { limit: "10", offset: "0" },
  {
    limit: { type: :positive_integer, max_value: 100 },
    offset: { type: :positive_integer, min_value: 0 }
  }
)

Parameters:

  • params (Hash)

    Parameters to validate

  • validations (Hash)

    Validation rules for each parameter

Returns:

  • (Hash)

    Hash of validated parameters

Raises:

  • (ValidationError)

    If any validation fails



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
# File 'lib/rospatent/input_validator.rb', line 256

def validate_params(params, validations)
  validated = {}
  errors = {}

  validations.each do |param_name, rules|
    value = params[param_name]
    validated[param_name] = case rules[:type]
                            when :positive_integer
                              validate_positive_integer(
                                value,
                                param_name.to_s,
                                min_value: rules[:min_value] || 1,
                                max_value: rules[:max_value]
                              )
                            when :string
                              validate_string(
                                value,
                                param_name.to_s,
                                max_length: rules[:max_length]
                              )
                            when :enum
                              validate_enum(value, rules[:allowed_values], param_name.to_s)
                            when :date
                              validate_date(value, param_name.to_s)
                            when :array
                              validate_array(
                                value,
                                param_name.to_s,
                                max_size: rules[:max_size],
                                element_validator: rules[:element_validator]
                              )
                            when :hash
                              validate_hash(
                                value,
                                param_name.to_s,
                                required_keys: rules[:required_keys] || [],
                                allowed_keys: rules[:allowed_keys]
                              )
                            else
                              value
                            end
  rescue Errors::ValidationError => e
    errors[param_name] = e.message
  end

  raise Errors::ValidationError.new("Validation failed", errors) unless errors.empty?

  validated.compact
end

#validate_patent_id(document_id) ⇒ String

Validate patent ID format

Parameters:

  • document_id (String)

    Patent document ID

Returns:

  • (String)

    Validated document ID

Raises:

  • (ValidationError)

    If format is invalid



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/rospatent/input_validator.rb', line 225

def validate_patent_id(document_id)
  raise Errors::ValidationError, "Document_id is required" if document_id.nil?

  value = validate_string(document_id, "document_id")
  return nil if value.nil?

  # Regex pattern for patent IDs
  # Format: {country code (2 letters)}{publication number (alphanumeric)}{document type (letter+digits)}_{date (YYYYMMDD)}
  pattern = /^[A-Z]{2}[A-Z0-9]+[A-Z]\d*_\d{8}$/

  unless value.match?(pattern)
    raise Errors::ValidationError,
          "Invalid patent ID format. Expected format: 'XX12345Y1_YYYYMMDD' (country code + alphanumeric publication number + document type + date)"
  end

  value
end

#validate_positive_integer(value, field_name, min_value: 1, max_value: nil) ⇒ Integer

Validate positive integer

Parameters:

  • value (Integer, String, nil)

    Value to validate

  • field_name (String)

    Name of the field for error messages

  • min_value (Integer) (defaults to: 1)

    Minimum allowed value

  • max_value (Integer, nil) (defaults to: nil)

    Maximum allowed value (optional)

Returns:

  • (Integer)

    Validated integer

Raises:

  • (ValidationError)

    If value is invalid



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
# File 'lib/rospatent/input_validator.rb', line 48

def validate_positive_integer(value, field_name, min_value: 1, max_value: nil)
  return nil if value.nil?

  # Convert string to integer if possible
  if value.is_a?(String)
    begin
      value = Integer(value)
    rescue ArgumentError
      raise Errors::ValidationError,
            "Invalid #{field_name}. Expected integer, got non-numeric string"
    end
  end

  unless value.is_a?(Integer)
    raise Errors::ValidationError,
          "Invalid #{field_name} type. Expected Integer, got #{value.class}"
  end

  if value < min_value
    raise Errors::ValidationError,
          "#{field_name.capitalize} must be at least #{min_value}"
  end

  if max_value && value > max_value
    raise Errors::ValidationError,
          "#{field_name.capitalize} must be at most #{max_value}"
  end

  value
end

#validate_required_date(date, field_name = "date") ⇒ Date

Validate and normalize required date input (does not allow nil)

Parameters:

  • date (String, Date)

    Date input to validate

  • field_name (String) (defaults to: "date")

    Name of the field for error messages

Returns:

  • (Date)

    Normalized Date object

Raises:

  • (ValidationError)

    If date format is invalid or nil



35
36
37
38
39
# File 'lib/rospatent/input_validator.rb', line 35

def validate_required_date(date, field_name = "date")
  raise Errors::ValidationError, "#{field_name.capitalize} is required" if date.nil?

  validate_date(date, field_name)
end

#validate_required_string(value, field_name, max_length: nil) ⇒ String

Validate required non-empty string (does not allow nil)

Parameters:

  • value (String, nil)

    String to validate

  • field_name (String)

    Name of the field for error messages

  • max_length (Integer, nil) (defaults to: nil)

    Maximum allowed length

Returns:

  • (String)

    Validated string

Raises:

  • (ValidationError)

    If string is invalid or nil



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/rospatent/input_validator.rb', line 109

def validate_required_string(value, field_name, max_length: nil)
  raise Errors::ValidationError, "#{field_name.capitalize} is required" if value.nil?

  unless value.is_a?(String)
    raise Errors::ValidationError,
          "Invalid #{field_name} type. Expected String, got #{value.class}"
  end

  raise Errors::ValidationError, "#{field_name.capitalize} cannot be empty" if value.empty?

  if max_length && value.length > max_length
    raise Errors::ValidationError,
          "#{field_name.capitalize} cannot exceed #{max_length} characters"
  end

  value.strip
end

#validate_string(value, field_name, max_length: nil) ⇒ String

Validate non-empty string

Parameters:

  • value (String, nil)

    String to validate

  • field_name (String)

    Name of the field for error messages

  • max_length (Integer, nil) (defaults to: nil)

    Maximum allowed length

Returns:

  • (String)

    Validated string

Raises:

  • (ValidationError)

    If string is invalid



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/rospatent/input_validator.rb', line 85

def validate_string(value, field_name, max_length: nil)
  return nil if value.nil?

  unless value.is_a?(String)
    raise Errors::ValidationError,
          "Invalid #{field_name} type. Expected String, got #{value.class}"
  end

  raise Errors::ValidationError, "#{field_name.capitalize} cannot be empty" if value.empty?

  if max_length && value.length > max_length
    raise Errors::ValidationError,
          "#{field_name.capitalize} cannot exceed #{max_length} characters"
  end

  value.strip
end