Class: Udb::Schema

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Includes:
Idl::Schema
Defined in:
lib/udb/schema.rb,
lib/udb/obj/parameter.rb

Constant Summary collapse

@@ref_resolvers =
T.let({}, T::Hash[Resolver, T.untyped])

Instance Method Summary collapse

Constructor Details

#initialize(schema_hash)

Parameters:

  • schema_hash (Hash{String => T.untyped})


25
26
27
# File 'lib/udb/schema.rb', line 25

def initialize(schema_hash)
  @schema_hash = schema_hash
end

Instance Method Details

#empty?Boolean

Returns:

  • (Boolean)


225
226
227
# File 'lib/udb/schema.rb', line 225

def empty?
  @schema_hash.empty?
end

#is_power_of_two?(num) ⇒ Boolean

Returns:

  • (Boolean)


287
288
289
290
# File 'lib/udb/schema.rb', line 287

def is_power_of_two?(num)
  return false if num < 1
  return (num & (num - 1)) == 0
end

#large2hex(value) ⇒ String

Convert large integers to hex str.

Parameters:

  • value (Numeric, Boolean, String, nil)

Returns:

  • (String)


207
208
209
210
211
212
213
214
215
# File 'lib/udb/schema.rb', line 207

def large2hex(value)
  if value.nil?
    ""
  elsif value.is_a?(Integer)
    (value > 999) ? "0x" + value.to_s(16) : value.to_s
  else
    value.to_s
  end
end

#max_valInteger

Returns The maximum value the schema allows. Only valid if #max_val_known? is true.

Returns:

  • (Integer)

    The maximum value the schema allows. Only valid if #max_val_known? is true



261
262
263
264
265
266
267
268
269
270
271
# File 'lib/udb/schema.rb', line 261

def max_val
  if @schema_hash.key?("const")
    @schema_hash["const"]
  elsif @schema_hash.key?("enum")
    @schema_hash["enum"].max
  elsif @schema_hash.key?("maximum")
    @schema_hash["maximum"]
  else
    raise "unexpected"
  end
end

#max_val_known?Boolean

Returns if the maximum value of the schema is known, i.e., is a restricted integer.

Returns:

  • (Boolean)

    if the maximum value of the schema is known, i.e., is a restricted integer



243
244
245
246
247
248
# File 'lib/udb/schema.rb', line 243

def max_val_known?
  to_idl_type.kind == :bits && \
    (@schema_hash.key?("const") || \
     @schema_hash.key?("maximum") || \
     @schema_hash.key?("enum"))
end

#merge(other_schema) ⇒ Schema

Parameters:

  • other_schema (Schema, Hash{String => T.untyped})

Returns:



218
219
220
221
222
# File 'lib/udb/schema.rb', line 218

def merge(other_schema)
  other_hash = other_schema.is_a?(Schema) ? other_schema.instance_variable_get(:@schema_hash) : other_schema

  Schema.new(@schema_hash.merge(other_hash))
end

#min_valInteger

Returns The minimum value the schema allows. Only valid if #min_val_known? is true.

Returns:

  • (Integer)

    The minimum value the schema allows. Only valid if #min_val_known? is true



275
276
277
278
279
280
281
282
283
284
285
# File 'lib/udb/schema.rb', line 275

def min_val
  if @schema_hash.key?("const")
    @schema_hash["const"]
  elsif @schema_hash.key?("enum")
    @schema_hash["enum"].min
  elsif @schema_hash.key?("minimum")
    @schema_hash["minimum"]
  else
    raise "unexpected"
  end
end

#min_val_known?Boolean

Returns if the minimum value of the schema is known, i.e., is a restricted integer.

Returns:

  • (Boolean)

    if the minimum value of the schema is known, i.e., is a restricted integer



252
253
254
255
256
257
# File 'lib/udb/schema.rb', line 252

def min_val_known?
  to_idl_type.kind == :bits && \
    (@schema_hash.key?("const") || \
     @schema_hash.key?("minimum") || \
     @schema_hash.key?("enum"))
end

#num_bits(min, max) ⇒ Object

If min to max range represents an unsigned number of bits, return the number of bits. Otherwise return 0



294
295
296
297
# File 'lib/udb/schema.rb', line 294

def num_bits(min, max)
  return 0 unless min == 0
  is_power_of_two?(max + 1) ? max.bit_length : 0
end

#single_value?Boolean

Returns:

  • (Boolean)


230
231
232
# File 'lib/udb/schema.rb', line 230

def single_value?
  @schema_hash.key?("const")
end

#to_hHash{String => T.untyped}

Returns Hash representation of the JSON Schema.

Returns:

  • (Hash{String => T.untyped})

    Hash representation of the JSON Schema



43
# File 'lib/udb/schema.rb', line 43

def to_h = @schema_hash

#to_idl_typeIdl::Type

Returns THe IDL-equivalent type for this schema object.

Returns:

  • (Idl::Type)

    THe IDL-equivalent type for this schema object



301
302
303
# File 'lib/udb/schema.rb', line 301

def to_idl_type
  T.must(Idl::Type.from_json_schema(@schema_hash))
end

#to_pretty_s(schema_hash = @schema_hash) ⇒ String

Returns A human-readable description of the schema.

Parameters:

  • schema_hash (Hash{String => T.untyped}) (defaults to: @schema_hash)

Returns:

  • (String)

    A human-readable description of the schema

Raises:

  • (ArgumentError)


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/udb/schema.rb', line 95

def to_pretty_s(schema_hash = @schema_hash)
  raise ArgumentError, "Expecting non-empty hash" if schema_hash.empty?

  if schema_hash.key?("const")
    large2hex(schema_hash["const"])
  elsif schema_hash.key?("enum")
    "[#{schema_hash["enum"].join(', ')}]"
  elsif schema_hash.key?("$ref")
    if schema_hash["$ref"].split("/").last == "uint32"
      "32-bit integer"
    elsif schema_hash["$ref"].split("/").last == "uint64"
      "64-bit integer"
    else
      raise "unhandled type ref: #{schema_hash["$ref"]}"
    end
  elsif schema_hash.key?("not")
    if schema_hash["not"].key?("const")
      "#{large2hex(schema_hash["not"]["const"])}"
    elsif schema_hash["not"].key?("anyOf")
      if schema_hash["not"]["anyOf"].all? { |h| h.key?("const") }
        "#{schema_hash["not"]["anyOf"].map { |h| large2hex(h["const"]) }.join(" or ")}"
      else
        raise "unhandled exclusion: #{schema_hash}"
      end
    else
      raise "unhandled exclusion: #{schema_hash}"
    end
  elsif schema_hash.key?("allOf")
    schema_hash["allOf"].map { |hsh| to_pretty_s(hsh) }.join(", ")
  elsif schema_hash.key?("type")
    case schema_hash["type"]
    when "integer"
      min = schema_hash["minimum"]
      minstr = large2hex(min)
      max = schema_hash["maximum"]
      maxstr = large2hex(max)
      if min && max
        sz = num_bits(min, max)
        (sz > 0) ? "#{sz}-bit integer" : "#{minstr} to #{maxstr}"
      elsif min
        "&#8805; #{minstr}"
      elsif max
        "&#8804; #{maxstr}"
      else
        "integer"
      end
    when "string"
      format = schema_hash["format"]
      pattern = schema_hash["pattern"]
      if format
        format
      elsif pattern
        "string matching #{pattern}"
      else
        "string"
      end
    when "boolean"
      "boolean"
    when "array"
      items = schema_hash["items"]
      min_items = schema_hash["minItems"]
      max_items = schema_hash["maxItems"]
      size_str = if min_items && max_items
                   if min_items == max_items
                     "#{min_items}-element "
                   else
                     "#{min_items}-element to #{max_items}-element "
                   end
      elsif min_items
        "at least #{min_items}-element "
      elsif max_items
        "at most #{max_items}-element "
      else
        ""
      end

      array_str = if items.nil?
                    size_str + "array"
      else
        if items.is_a?(Hash)
          "#{size_str}array of #{to_pretty_s(items)}"
        elsif items.is_a?(Array)
          str = size_str + "array where: +\n"
          items.each_with_index do |item, index|
            str = str + "&nbsp;&nbsp;[#{index}] is #{to_pretty_s(item)} +\n"
          end
          additional_items = schema_hash["additionalItems"]
          if additional_items
            str = str + "additional items are: +\n&nbsp;&nbsp;" +
              to_pretty_s(additional_items)
          end
          str
        else
          raise "to_pretty_s unknown array items #{items} in #{schema_hash}"
        end
      end

      if schema_hash.key?("contains")
        array_str = array_str + " Contains : [#{to_pretty_s(schema_hash["contains"])}]"
      end

      array_str
    else
      raise "to_pretty_s unknown type #{schema_hash["type"]} in #{schema_hash}"
    end
  else
    raise "Unsupported schema for #{schema_hash}"
  end
end

#type_prettyString

Returns:

  • (String)


89
90
91
# File 'lib/udb/schema.rb', line 89

def type_pretty
  type_pretty_helper(@schema_hash)
end

#validate(rb_value, udb_resolver:) ⇒ Boolean

Parameters:

  • rb_value (T.untyped)
  • udb_resolver (Resolver)

Returns:

  • (Boolean)


30
31
32
33
34
35
36
37
38
39
# File 'lib/udb/schema.rb', line 30

def validate(rb_value, udb_resolver:)
  @@ref_resolvers[udb_resolver] ||= TopLevelDatabaseObject.create_json_schemer_resolver(udb_resolver)
  schemer = JSONSchemer.schema(
    @schema_hash,
    regexp_resolver: "ecma",
    ref_resolver: @@ref_resolvers[udb_resolver],
    insert_property_defaults: true
  )
  schemer.valid?(rb_value)
end

#valueObject

Returns:

  • (Object)


235
236
237
238
239
# File 'lib/udb/schema.rb', line 235

def value
  raise "Schema is not a single value" unless single_value?

  @schema_hash["const"]
end