Module: Skooma::Instance::Coercible

Included in:
Attribute
Defined in:
lib/skooma/instance.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.coerce_array_items(value, items_schema) ⇒ Object



41
42
43
44
45
46
# File 'lib/skooma/instance.rb', line 41

def self.coerce_array_items(value, items_schema)
  return value unless value.is_a?(Array)
  return value unless schema_object?(items_schema)

  value.map { |item| item.is_a?(String) ? coerce_value(item, items_schema) : item }
end

.coerce_value(value, json) ⇒ Object



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
# File 'lib/skooma/instance.rb', line 13

def self.coerce_value(value, json)
  case json["type"]
  when "integer"
    begin
      Integer(value, 10)
    rescue ArgumentError
      value
    end
  when "number"
    begin
      Float(value)
    rescue ArgumentError
      value
    end
  when "boolean"
    return true if value == "true"

    (value == "false") ? false : value
  when "object"
    value
    # convert_object(value, schema)
  when "array"
    coerce_array_items(value, json["items"])
  else
    value
  end
end

.deep_coerce_value(value, json) ⇒ Object



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
# File 'lib/skooma/instance.rb', line 61

def self.deep_coerce_value(value, json)
  return value if value.nil?

  case json["type"]
  when "array"
    return value unless value.is_a?(Array)

    prefix_items = json["prefixItems"]
    items = json["items"]

    value.map.with_index do |item, index|
      schema = prefix_schema(prefix_items, index) || items
      schema_object?(schema) ? deep_coerce_value(item, schema) : item
    end
  when "object"
    return value unless value.is_a?(Hash)

    properties = json["properties"]
    additional_properties = json["additionalProperties"]

    value.each_with_object({}) do |(key, item), coerced|
      schema = properties.respond_to?(:key?) ? properties[key] : nil
      schema ||= additional_properties
      coerced[key] = schema_object?(schema) ? deep_coerce_value(item, schema) : item
    end
  else
    # Scalar schema: only scalar values are coercible. A structural value
    # here means a type mismatch (e.g. `deepObject` against a scalar
    # schema) — leave it for validation to reject rather than coerce.
    (value.is_a?(Hash) || value.is_a?(Array)) ? value : coerce_value(value, json)
  end
end

.prefix_schema(prefix_items, index) ⇒ Object

The positional subschema for ‘index` when `prefixItems` is present.



101
102
103
104
105
# File 'lib/skooma/instance.rb', line 101

def self.prefix_schema(prefix_items, index)
  return unless prefix_items.is_a?(JSONSkooma::JSONNode) && prefix_items.type == "array"

  prefix_items[index]
end

.schema_object?(node) ⇒ Boolean

True when ‘node` is a real subschema (a JSON object), excluding boolean schemas like `items: true`.

Returns:

  • (Boolean)


96
97
98
# File 'lib/skooma/instance.rb', line 96

def self.schema_object?(node)
  node.is_a?(JSONSkooma::JSONSchema) && node.type == "object"
end

Instance Method Details

#coerce(json) ⇒ Object



6
7
8
9
10
11
# File 'lib/skooma/instance.rb', line 6

def coerce(json)
  value = self&.value
  return self if value.nil?

  Coercible.coerce_value(value, json)
end

#deep_coerce(json) ⇒ Object

Recursive coercion for parameters only. Parameter values arrive as all-strings, so we descend into array items (positional ‘prefixItems` first, then `items`) and object properties (`properties` first, then `additionalProperties`), coercing each to its declared type. Request/response bodies are only shallowly coerced (top level, via `coerce` above), so a nested JSON body value like `“5”` against `integer` stays invalid.



55
56
57
58
59
# File 'lib/skooma/instance.rb', line 55

def deep_coerce(json)
  return if value.nil?

  Coercible.deep_coerce_value(value, json)
end