Module: JSI::Schema
- Includes:
- Memoize
- Defined in:
- lib/jsi/schema.rb
Overview
JSI::Schema represents a JSON Schema. initialized from a Hash-like schema object, JSI::Schema is a relatively simple class to abstract useful methods applied to a JSON Schema.
Defined Under Namespace
Modules: DescribesSchema Classes: Error, NotASchemaError
Class Method Summary collapse
-
.default_metaschema ⇒ JSI::Schema
The default metaschema.
-
.from_object(schema_object) ⇒ JSI::Schema
(also: new)
instantiates a given schema object as a JSI::Schema.
-
.supported_metaschemas ⇒ Array<JSI::Schema>
Supported metaschemas.
Instance Method Summary collapse
-
#described_object_property_names ⇒ Set
Any object property names this schema indicates may be present on its instances.
-
#describes_schema? ⇒ Boolean
Does this schema itself describe a schema?.
-
#fully_validate_instance(other_instance, errors_as_objects: false) ⇒ Array
Array of schema validation errors for the given instance against this schema.
-
#fully_validate_schema(errors_as_objects: false) ⇒ Array
Array of schema validation errors for this schema, validated against its metaschema.
-
#jsi_schema_class ⇒ Class subclassing JSI::Base
Shortcut for JSI.class_for_schema(schema).
-
#jsi_schema_module ⇒ Module
A module representing this schema.
-
#match_to_instance(other_instance) ⇒ JSI::Schema
if this schema is a oneOf, allOf, anyOf schema, #match_to_instance finds one of the subschemas that matches the given instance and returns it.
-
#new_jsi(other_instance, *a, &b) ⇒ JSI::Base
calls #new on the class for this schema with the given arguments.
-
#schema_id ⇒ String?
An absolute id for the schema, with a json pointer fragment.
-
#subschema_for_index(index) ⇒ JSI::Schema?
A subschema from
itemsoradditionalItemsfor the given token. -
#subschema_for_property(property_name) ⇒ JSI::Schema?
A subschema from
properties,patternProperties, oradditionalPropertiesfor the given token. -
#validate_instance(other_instance) ⇒ true, false
Whether the given instance validates against this schema.
-
#validate_instance!(other_instance) ⇒ true
If this method does not raise, it returns true to indicate the instance is valid against this schema.
-
#validate_schema ⇒ true, false
Whether this schema validates against its metaschema.
-
#validate_schema! ⇒ true
If this method does not raise, it returns true to indicate this schema is valid against its metaschema.
Methods included from Memoize
Class Method Details
.default_metaschema ⇒ JSI::Schema
Returns the default metaschema.
28 29 30 |
# File 'lib/jsi/schema.rb', line 28 def JSI::JSONSchemaOrgDraft06.schema end |
.from_object(schema_object) ⇒ JSI::Schema Also known as: new
instantiates a given schema object as a JSI::Schema.
schemas are instantiated according to their '$schema' property if specified. otherwise their schema will be the default_metaschema.
if the given schema_object is a JSI::Base but not already a JSI::Schema, an error will be raised. JSI::Base should already extend a given instance with JSI::Schema when its schema describes a schema (by extending with JSI::Schema::DescribesSchema).
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/jsi/schema.rb', line 52 def from_object(schema_object) if schema_object.is_a?(Schema) schema_object elsif schema_object.is_a?(JSI::Base) raise(NotASchemaError, "the given schema_object is a JSI::Base, but is not a JSI::Schema: #{schema_object.pretty_inspect.chomp}") elsif schema_object.respond_to?(:to_hash) schema_object = JSI.deep_stringify_symbol_keys(schema_object) if schema_object.key?('$schema') && schema_object['$schema'].respond_to?(:to_str) if schema_object['$schema'] == schema_object['$id'] || schema_object['$schema'] == schema_object['id'] MetaschemaNode.new(schema_object) else = .detect { |ms| schema_object['$schema'] == ms['$id'] || schema_object['$schema'] == ms['id'] } unless raise(NotImplementedError, "metaschema not supported: #{schema_object['$schema']}") end .new_jsi(schema_object) end else .new_jsi(schema_object) end elsif [true, false].include?(schema_object) .new_jsi(schema_object) else raise(TypeError, "cannot instantiate Schema from: #{schema_object.pretty_inspect.chomp}") end end |
.supported_metaschemas ⇒ Array<JSI::Schema>
Returns supported metaschemas.
33 34 35 36 37 38 |
# File 'lib/jsi/schema.rb', line 33 def [ JSI::JSONSchemaOrgDraft04.schema, JSI::JSONSchemaOrgDraft06.schema, ] end |
Instance Method Details
#described_object_property_names ⇒ Set
Returns any object property names this schema indicates may be present on its instances. this includes, if present: keys of this schema's "properties" object; entries of this schema's array of "required" property keys. if this schema has allOf subschemas, those schemas are checked (recursively) for their described object property names.
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/jsi/schema.rb', line 205 def described_object_property_names jsi_memoize(:described_object_property_names) do Set.new.tap do |property_names| if node_content.respond_to?(:to_hash) && node_content['properties'].respond_to?(:to_hash) property_names.merge(node_content['properties'].keys) end if node_content.respond_to?(:to_hash) && node_content['required'].respond_to?(:to_ary) property_names.merge(node_content['required'].to_ary) end # we should look at dependencies (TODO). if respond_to?(:to_hash) && self['allOf'].respond_to?(:to_ary) self['allOf'].select{ |s| s.is_a?(JSI::Schema) }.map(&:deref).map do |allOf_schema| property_names.merge(allOf_schema.described_object_property_names) end end end end end |
#describes_schema? ⇒ Boolean
Returns does this schema itself describe a schema?.
147 148 149 |
# File 'lib/jsi/schema.rb', line 147 def describes_schema? is_a?(JSI::Schema::DescribesSchema) end |
#fully_validate_instance(other_instance, errors_as_objects: false) ⇒ Array
Returns array of schema validation errors for the given instance against this schema.
226 227 228 |
# File 'lib/jsi/schema.rb', line 226 def fully_validate_instance(other_instance, errors_as_objects: false) ::JSON::Validator.fully_validate(JSI::Typelike.as_json(node_document), JSI::Typelike.as_json(other_instance), fragment: node_ptr.fragment, errors_as_objects: errors_as_objects) end |
#fully_validate_schema(errors_as_objects: false) ⇒ Array
Returns array of schema validation errors for this schema, validated against its metaschema. a default metaschema is assumed if the schema does not specify a $schema.
246 247 248 |
# File 'lib/jsi/schema.rb', line 246 def fully_validate_schema(errors_as_objects: false) ::JSON::Validator.fully_validate(JSI::Typelike.as_json(node_document), [], fragment: node_ptr.fragment, validate_schema: true, list: true, errors_as_objects: errors_as_objects) end |
#jsi_schema_class ⇒ Class subclassing JSI::Base
Returns shortcut for JSI.class_for_schema(schema).
134 135 136 |
# File 'lib/jsi/schema.rb', line 134 def jsi_schema_class JSI.class_for_schema(self) end |
#jsi_schema_module ⇒ Module
Returns a module representing this schema. see JSI::SchemaClasses.module_for_schema.
129 130 131 |
# File 'lib/jsi/schema.rb', line 129 def jsi_schema_module JSI::SchemaClasses.module_for_schema(self) end |
#match_to_instance(other_instance) ⇒ JSI::Schema
if this schema is a oneOf, allOf, anyOf schema, #match_to_instance finds one of the subschemas that matches the given instance and returns it. if there are no matching *Of schemas, this schema is returned.
157 158 159 160 161 162 163 164 165 166 |
# File 'lib/jsi/schema.rb', line 157 def match_to_instance(other_instance) ptr = node_ptr ptr = ptr.deref(node_document) ptr = ptr.schema_match_ptr_to_instance(node_document, other_instance) if ptr ptr.evaluate(document_root_node).tap { |subschema| jsi_ensure_subschema_is_schema(subschema, ptr) } else self end end |
#new_jsi(other_instance, *a, &b) ⇒ JSI::Base
calls #new on the class for this schema with the given arguments. for parameters, see JSI::Base#initialize documentation.
142 143 144 |
# File 'lib/jsi/schema.rb', line 142 def new_jsi(other_instance, *a, &b) JSI.class_for_schema(match_to_instance(other_instance)).new(other_instance, *a, &b) end |
#schema_id ⇒ String?
Returns an absolute id for the schema, with a json pointer fragment. nil if no parent of this schema defines an id.
84 85 86 87 88 89 90 91 92 93 94 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 |
# File 'lib/jsi/schema.rb', line 84 def schema_id return @schema_id if instance_variable_defined?(:@schema_id) @schema_id = begin # start from self and ascend parents looking for an 'id' property. # append a fragment to that id (appending to an existing fragment if there # is one) consisting of the path from that parent to our schema_node. node_for_id = self path_from_id_node = [] done = false while !done node_content_for_id = node_for_id.node_content if node_for_id.is_a?(JSI::Schema) && node_content_for_id.respond_to?(:to_hash) parent_id = node_content_for_id.key?('$id') && node_content_for_id['$id'].respond_to?(:to_str) ? node_content_for_id['$id'].to_str : node_content_for_id.key?('id') && node_content_for_id['id'].respond_to?(:to_str) ? node_content_for_id['id'].to_str : nil end if parent_id || node_for_id.node_ptr.root? done = true else path_from_id_node.unshift(node_for_id.node_ptr.reference_tokens.last) node_for_id = node_for_id.parent_node end end if parent_id parent_auri = Addressable::URI.parse(parent_id) if parent_auri.fragment # add onto the fragment parent_id_path = JSI::JSON::Pointer.from_fragment('#' + parent_auri.fragment).reference_tokens path_from_id_node = parent_id_path + path_from_id_node parent_auri.fragment = nil #else: no fragment so parent_id good as is end fragment = JSI::JSON::Pointer.new(path_from_id_node).fragment schema_id = parent_auri.to_s + fragment schema_id else nil end end end |
#subschema_for_index(index) ⇒ JSI::Schema?
Returns a subschema from items or additionalItems for the given token.
186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/jsi/schema.rb', line 186 def subschema_for_index(index) jsi_memoize(:subschema_for_index, index) do |index| ptr = node_ptr ptr = ptr.deref(node_document) ptr = ptr.schema_subschema_ptr_for_index(node_document, index) if ptr ptr = ptr.deref(node_document) ptr.evaluate(document_root_node).tap { |subschema| jsi_ensure_subschema_is_schema(subschema, ptr) } else nil end end end |
#subschema_for_property(property_name) ⇒ JSI::Schema?
Returns a subschema from properties, patternProperties, or additionalProperties for the given token.
170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/jsi/schema.rb', line 170 def subschema_for_property(property_name) jsi_memoize(:subschema_for_property, property_name) do |property_name| ptr = node_ptr ptr = ptr.deref(node_document) ptr = ptr.schema_subschema_ptr_for_property_name(node_document, property_name) if ptr ptr = ptr.deref(node_document) ptr.evaluate(document_root_node).tap { |subschema| jsi_ensure_subschema_is_schema(subschema, ptr) } else nil end end end |
#validate_instance(other_instance) ⇒ true, false
Returns whether the given instance validates against this schema.
231 232 233 |
# File 'lib/jsi/schema.rb', line 231 def validate_instance(other_instance) ::JSON::Validator.validate(JSI::Typelike.as_json(node_document), JSI::Typelike.as_json(other_instance), fragment: node_ptr.fragment) end |
#validate_instance!(other_instance) ⇒ true
Returns if this method does not raise, it returns true to indicate the instance is valid against this schema.
239 240 241 |
# File 'lib/jsi/schema.rb', line 239 def validate_instance!(other_instance) ::JSON::Validator.validate!(JSI::Typelike.as_json(node_document), JSI::Typelike.as_json(other_instance), fragment: node_ptr.fragment) end |
#validate_schema ⇒ true, false
Returns whether this schema validates against its metaschema.
251 252 253 |
# File 'lib/jsi/schema.rb', line 251 def validate_schema ::JSON::Validator.validate(JSI::Typelike.as_json(node_document), [], fragment: node_ptr.fragment, validate_schema: true, list: true) end |
#validate_schema! ⇒ true
Returns if this method does not raise, it returns true to indicate this schema is valid against its metaschema.
259 260 261 |
# File 'lib/jsi/schema.rb', line 259 def validate_schema! ::JSON::Validator.validate!(JSI::Typelike.as_json(node_document), [], fragment: node_ptr.fragment, validate_schema: true, list: true) end |