Module: Jamf::OAPIValidate

Included in:
Validate
Defined in:
lib/jamf/oapi_validate.rb

Overview

A collection of methods implementing data constraints as defined in the OAPI3 standard. See

swagger.io/docs/specification/data-models/data-types/

This module is extended into Jamf::Validate, where these become module methods

As with that module: Some of these methods can take multiple input types, such as a String or an number. All of them will either raise an exception if the value isn’t valid, or will return a standardized form of the input (e.g. a number, even if given a String)

IMPORTANT - This module MUST be extended into Jamf::Validate.

Instance Method Summary collapse

Instance Method Details

#boolean(val, attr_name: nil, msg: nil) ⇒ Boolean

Confirm that the given value is a boolean value, accepting strings and symbols and returning real booleans as needed Accepts: true, false, ‘true’, ‘false’, ‘yes’, ‘no’, ‘t’,‘f’, ‘y’, or ‘n’ as strings or symbols, case insensitive

TODO: use this throughout ruby-jss

Parameters:

  • val (Boolean, String, Symbol)

    The value to validate

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (Boolean)

    the valid boolean



184
185
186
187
188
189
190
# File 'lib/jamf/oapi_validate.rb', line 184

def boolean(val, attr_name: nil, msg: nil)
  return val if Jamf::TRUE_FALSE.include? val
  return true if val.to_s =~ /^(t(rue)?|y(es)?)$/i
  return false if val.to_s =~ /^(f(alse)?|no?)$/i

  raise_invalid_data_error(msg || "#{attr_name} value must be boolean true or false, or an equivalent string or symbol")
end

#class_instance(val, klass:, attr_name: nil, msg: nil) ⇒ Object

validate that a value is of a specific class

Parameters:

  • val (Object)

    The value to validate

  • klass (Class, Symbol)

    The class which the val must be an instance of

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (Object)

    the valid value



161
162
163
164
165
166
167
168
169
# File 'lib/jamf/oapi_validate.rb', line 161

def class_instance(val, klass:, attr_name: nil, msg: nil)
  return val if val.instance_of? klass

  # try to instantiate the class with the value. It should raise an error
  # if not good
  klass.new val
rescue => e
  raise_invalid_data_error(msg || "#{attr_name} value must be a #{klass}, or #{klass}.new must accept it as the only parameter, but #{klass}.new raised: #{e.class}: #{e}")
end

#float(val, attr_name: nil, msg: nil) ⇒ Float

Confirm that a value is a Float or a string representation of a Float Return the Float, or raise an error

Parameters:

  • val (Object)

    the value to validate

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (Float)


243
244
245
246
247
248
249
# File 'lib/jamf/oapi_validate.rb', line 243

def float(val, attr_name: nil, msg: nil)
  val = val.to_f if val.is_a?(Integer)
  val = val.to_f if val.is_a?(String) && (val.j_float? || val.j_integer?)
  return val if val.is_a? Float

  raise_invalid_data_error(msg || "#{attr_name} value must be an floating point number")
end

#fully_validate_integer(val, attr_def:, attr_name: nil) ⇒ Object

run all the possible validations on an integer



111
112
113
114
# File 'lib/jamf/oapi_validate.rb', line 111

def fully_validate_integer(val, attr_def:, attr_name: nil)
  val = integer val, attr_name: attr_name
  validate_numeric_constraints(val, attr_def: attr_def, attr_name: attr_name)
end

#fully_validate_number(val, attr_def:, attr_name: nil) ⇒ Object

run all the possible validations on a ‘number’



117
118
119
120
121
122
123
124
125
# File 'lib/jamf/oapi_validate.rb', line 117

def fully_validate_number(val, attr_def:, attr_name: nil)
  val =
    if %w[float double].include? attr_def[:format]
      float val, attr_name: attr_name
    else
      number val, attr_name: attr_name
    end
  validate_numeric_constraints(val, attr_def: attr_def, attr_name: attr_name)
end

#fully_validate_string(val, attr_def:, attr_name: nil) ⇒ Object

run all the possible validations on a string



100
101
102
103
104
105
106
107
108
# File 'lib/jamf/oapi_validate.rb', line 100

def fully_validate_string(val, attr_def:, attr_name: nil)
  val = string val, attr_name: attr_name

  min_length val, min: attr_def[:min_length], attr_name: attr_name if attr_def[:min_length]
  max_length val, max: attr_def[:max_length], attr_name: attr_name if attr_def[:max_length]
  matches_pattern val, attr_def[:pattern], attr_name: attr_name if attr_def[:pattern]

  val
end

#in_enum(val, enum:, attr_name: nil, msg: nil) ⇒ Object

Does a value exist in a given enum array?

Parameters:

  • val (Object)

    The thing that must be in the enum

  • enum (Array)

    the enum of allowed values

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (Object)

    The valid object



478
479
480
481
482
# File 'lib/jamf/oapi_validate.rb', line 478

def in_enum(val, enum:, attr_name: nil, msg: nil)
  return val if  enum.include? val

  raise_invalid_data_error(msg || "#{attr_name} value must be one of: #{enum.join ', '}")
end

#integer(val, attr_name: nil, msg: nil) ⇒ Integer

Confirm that a value is an integer or a string representation of an integer. Return the integer, or raise an error

Parameters:

  • val (Object)

    the value to validate

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (Integer)


227
228
229
230
231
232
# File 'lib/jamf/oapi_validate.rb', line 227

def integer(val, attr_name: nil, msg: nil)
  val = val.to_i if val.is_a?(String) && val.j_integer?
  return val if val.is_a? Integer

  raise_invalid_data_error(msg || "#{attr_name} value must be an integer")
end

#matches_pattern(val, pattern:, attr_name: nil, msg: nil) ⇒ Object

Does a string match a given regular expression?

Parameters:

  • val (String)

    The value to match

  • pattern (pattern)

    the regular expression

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (Object)

    The valid object



494
495
496
497
498
# File 'lib/jamf/oapi_validate.rb', line 494

def matches_pattern(val, pattern:, attr_name: nil, msg: nil)
  return val if val =~ pattern

  raise_invalid_data_error(msg || "#{attr_name} value does not match RegExp: #{pattern}")
end

#max_items(val, max:, attr_name: nil, msg: nil) ⇒ String

validate that the given value contains no more than some maximum number of items

While this is intended for Arrays, it will work for any object that responds to #size

Parameters:

  • val (Object)

    the value to validate

  • max (Object)

    the maximum number of items allowed

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (String)

    the valid value

Raises:

  • (ArgumentError)


432
433
434
435
436
437
# File 'lib/jamf/oapi_validate.rb', line 432

def max_items(val, max:, attr_name: nil, msg: nil)
  raise ArgumentError, 'max must be a number' unless max.is_a?(Numeric)
  return val if val.size <= max

  raise_invalid_data_error(msg || "#{attr_name} value must contain no more than #{max} items")
end

#max_length(val, max:, attr_name: nil, msg: nil) ⇒ String

validate that the given value’s length is less than or equal to some maximum

While this is intended for Strings, it will work for any object that responds to #length

Parameters:

  • val (Object)

    the value to validate

  • max (Object)

    the maximum length allowed

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (String)

    the valid value

Raises:

  • (ArgumentError)


392
393
394
395
396
397
# File 'lib/jamf/oapi_validate.rb', line 392

def max_length(val, max:, attr_name: nil, msg: nil)
  raise ArgumentError, 'max must be a number' unless max.is_a?(Numeric)
  return val if val.length <= max

  raise_invalid_data_error(msg || "length of #{attr_name} value must be <= #{max}")
end

#maximum(val, max:, attr_name: nil, exclusive: false, msg: nil) ⇒ String

validate that the given value is less than or equal to some maximum

While intended for Numbers, this will work for any Comparable objects

If exclusive, the max value is excluded from the range and the value must be less than the max.

Parameters:

  • val (Object)

    the thing to validate

  • max (Object)

    A value that the val must be less than or equal to

  • exclusuve (Boolean)

    Should the max be excluded from the valid range? true: val must be < max, false: val must be <= max

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (String)

    the valid value



330
331
332
333
334
335
336
337
# File 'lib/jamf/oapi_validate.rb', line 330

def maximum(val, max:, attr_name: nil, exclusive: false, msg: nil)
  if exclusive
    return val if val < max
  elsif val <= max
    return val
  end
  raise_invalid_data_error(msg || "#{attr_name} value must be <= #{max}")
end

#min_items(val, min:, attr_name: nil, msg: nil) ⇒ String

validate that the given value contains at least some minimum number of items

While this is intended for Arrays, it will work for any object that responds to #size

Parameters:

  • val (Object)

    the value to validate

  • min (Object)

    the minimum number of items allowed

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (String)

    the valid value

Raises:

  • (ArgumentError)


412
413
414
415
416
417
# File 'lib/jamf/oapi_validate.rb', line 412

def min_items(val, min:, attr_name: nil, msg: nil)
  raise ArgumentError, 'min must be a number' unless min.is_a?(Numeric)
  return val if val.size >= min

  raise_invalid_data_error(msg || "#{attr_name} value must contain at least #{min} items")
end

#min_length(val, min:, attr_name: nil, msg: nil) ⇒ String

validate that the given value’s length is greater than or equal to some minimum

While this is intended for Strings, it will work for any object that responds to #length

Parameters:

  • val (Object)

    the value to validate

  • min (Object)

    The minimum length allowed

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (String)

    the valid value

Raises:

  • (ArgumentError)


372
373
374
375
376
377
# File 'lib/jamf/oapi_validate.rb', line 372

def min_length(val, min:, attr_name: nil, msg: nil)
  raise ArgumentError, 'min must be a number' unless min.is_a?(Numeric)
  return val if val.length >= min

  raise_invalid_data_error(msg || "length of #{attr_name} value must be >= #{min}")
end

#minimum(val, min:, attr_name: nil, exclusive: false, msg: nil) ⇒ String

validate that the given value is greater than or equal to some minimum

If exclusive, the min value is excluded from the range and the value must be greater than the min.

While intended for Numbers, this will work for any Comparable objects

Parameters:

  • val (Object)

    the thing to validate

  • min (Object)

    A value that the val must be greater than or equal to

  • exclusuve (Boolean)

    Should the min be excluded from the valid range? true: val must be > min, false: val must be >= min

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (String)

    the valid value



303
304
305
306
307
308
309
310
# File 'lib/jamf/oapi_validate.rb', line 303

def minimum(val, min:, attr_name: nil, exclusive: false, msg: nil)
  if exclusive
    return val if val > min
  elsif val >= min
    return val
  end
  raise_invalid_data_error(msg || "#{attr_name} value must be >= #{min}")
end

#multiple_of(val, multiplier:, attr_name: nil, msg: nil) ⇒ String

Validate that a given number is multiple of some other given number

Parameters:

  • val (Number)

    the number to validate

  • multiplier (Number)

    the number what the val must be a multiple of. this must be positive.

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (String)

    the valid value

Raises:

  • (ArgumentError)


350
351
352
353
354
355
356
357
# File 'lib/jamf/oapi_validate.rb', line 350

def multiple_of(val, multiplier:, attr_name: nil, msg: nil)
  raise ArgumentError, 'multiplier must be a positive number' unless multiplier.is_a?(Numeric) && multiplier.positive?
  raise Jamf::InvalidDataError, 'Value must be a number' unless val.is_a?(Numeric)

  return val if (val % multiplier).zero?

  raise_invalid_data_error(msg || "#{attr_name} value must be a multiple of #{multiplier}")
end

#not_nil(val, attr_name: nil, msg: nil) ⇒ Object

validate that a value is not nil

Parameters:

  • val (Object)

    the value to validate

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (Object)

    the valid value



462
463
464
465
466
# File 'lib/jamf/oapi_validate.rb', line 462

def not_nil(val, attr_name: nil, msg: nil)
  return val unless val.nil?

  raise_invalid_data_error(msg || "#{attr_name} value may not be nil")
end

#number(val, attr_name: nil, msg: nil) ⇒ Integer

Confirm that a value is an number or a string representation of an number. Return the number, or raise an error

Parameters:

  • val (Object)

    the value to validate

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:

  • (Integer)


201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/jamf/oapi_validate.rb', line 201

def number(val, attr_name: nil, msg: nil)
  if val.ia_a?(Integer) || val.is_a?(Float)
    return val

  elsif val.is_a?(String)

    if val.j_integer?
      return val.to_i
    elsif val.j_float?
      return val.to_f
    end

  end

  raise_invalid_data_error(msg || "#{attr_name} value must be a number")
end

#oapi_attr(val, attr_def:, attr_name: nil) ⇒ Boolean

Validate that a value is valid based on its definition in an objects OAPI_PROPERTIES constant.

Parameters:

  • val (Object)

    The value to validate

  • klass (Class, Symbol)

    The class which the val must be

  • msg (String)

    A custom error message when the value is invalid

Returns:

  • (Boolean)

    the valid boolean



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
# File 'lib/jamf/oapi_validate.rb', line 56

def oapi_attr(val, attr_def:, attr_name: nil)
  # check that the new val is not nil unless nil is OK
  val = not_nil(val, attr_name: attr_name) unless attr_def[:nil_ok]

  # if the new val is nil here, then nil is OK andd we shouldn't
  # check anything else
  return val if val.nil?

  val =
    case attr_def[:class]
    when :j_id
      Jamf::Validate.j_id value, attr_name: attr_name

    when Class
      class_instance val, klass: attr_def[:class], attr_name: attr_name

    when :boolean
      boolean val, attr_name: attr_name

    when :string
      fully_validate_string(val, attr_def: attr_def, attr_name: attr_name)

    when :integer
      fully_validate_integer(val, attr_def: attr_def, attr_name: attr_name)

    when :number
      fully_validate_number(val, attr_def: attr_def, attr_name: attr_name)

    when :hash
      hash val, attr_name: attr_name

    end # case

  # Now that the val is in whatever correct format after the above tests,
  # we test for enum membership if needed
  # otherwise, just return the val
  if attr_def[:enum]
    in_enum val, enum: attr_def[:enum], attr_name: attr_name
  else
    val
  end
end

#object(val, attr_name: nil, msg: nil) ⇒ Hash

Confirm that a value is a Hash Return the Hash, or raise an error

Parameters:

  • val (Object)

    the value to validate

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

Returns:



260
261
262
263
264
# File 'lib/jamf/oapi_validate.rb', line 260

def object(val, attr_name: nil, msg: nil)
  return val if val.is_a? Hash

  raise_invalid_data_error(msg || "#{attr_name} value must be a Hash")
end

#string(val, attr_name: nil, msg: nil, to_s: false) ⇒ Hash

Confirm that a value is a String Return the String, or raise an error

Parameters:

  • val (Object)

    the value to validate

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

  • to_s: (Boolean) (defaults to: false)

    If true, this method always succeds and returns the result of calling #to_s on the value

Returns:



278
279
280
281
282
283
# File 'lib/jamf/oapi_validate.rb', line 278

def string(val, attr_name: nil, msg: nil, to_s: false)
  val = val.to_s if to_s
  return val if val.is_a? String

  raise_invalid_data_error(msg || "#{attr_name} value must be a String")
end

#unique_array(val, attr_name: nil, msg: nil) ⇒ Object

validate that an array has only unique items, no duplicate values

Parameters:

  • val (Array)

    The array to validate

  • msg (String) (defaults to: nil)

    A custom error message when the value is invalid

  • return (Array)

    the valid array

Raises:

  • (ArgumentError)


447
448
449
450
451
452
# File 'lib/jamf/oapi_validate.rb', line 447

def unique_array(val, attr_name: nil, msg: nil)
  raise ArgumentError, 'Value must be an Array' unless val.is_a?(Array)
  return val if val.uniq.size == val.size

  raise_invalid_data_error(msg || "#{attr_name} value must contain only unique items")
end

#validate_array_constraints(val, attr_def:, attr_name: nil) ⇒ Object

run the array constraint validations for an array value. The individual array items must already be validated



143
144
145
146
147
148
149
# File 'lib/jamf/oapi_validate.rb', line 143

def validate_array_constraints(val, attr_def:, attr_name: nil)
  min_items val, min: attr_def[:minItems], attr_name: attr_name if attr_def[:minItems]
  max_items val, max: attr_def[:maxItems], attr_name: attr_name if attr_def[:maxItems]
  unique_array val, attr_name: attr_name if attr_def[:uniqueItems]

  val
end

#validate_numeric_constraints(val, attr_def:, attr_name: nil) ⇒ Object

run the numeric constraint validations for any numeric value The number itself must already be validated



129
130
131
132
133
134
135
136
137
138
139
# File 'lib/jamf/oapi_validate.rb', line 129

def validate_numeric_constraints(val, attr_def:, attr_name: nil)
  ex_min = attr_def[:exclusive_minimum]
  ex_max = attr_def[:exclusive_maximum]
  mult_of = attr_def[:multiple_of]

  minimum val, min: attr_def[:minimum], exclusive: ex_min, attr_name: attr_name if attr_def[:minimum]
  maximum val, max: attr_def[:maximum], exclusive: ex_max, attr_name: attr_name if attr_def[:maximum]
  multiple_of val, multiplier: mult_of, attr_name: attr_name if mult_of

  val
end