Module: JSI::Schema
- Defined in:
- lib/jsi/schema.rb
Overview
JSI::Schema is a module which extends instances which represent JSON schemas.
the content of an instance which is a JSI::Schema (referred to in this context as schema_content) is expected to be a Hash (JSON object) or a Boolean.
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 < JSI::Base] a JSI class for this one schema
Class < JSI::Base] a JSI class for this one schema.
-
#jsi_schema_module ⇒ Module
A module representing this schema.
-
#match_to_instance(other_instance) ⇒ Set<JSI::Schema>
checks this schema for applicators ($ref, allOf, etc.) which should be applied to the given instance.
-
#new_jsi(other_instance, *a, &b) ⇒ JSI::Base
instantiates the given other_instance as a JSI::Base class for schemas matched from this schema to the other_instance.
-
#schema_id ⇒ String?
An absolute id for the schema, with a json pointer fragment.
-
#subschemas_for_index(index) ⇒ Set<JSI::Schema>
returns a set of subschemas of this schema for the given array index, from keywords
itemsandadditionalItems. -
#subschemas_for_property_name(property_name) ⇒ Set<JSI::Schema>
returns a set of subschemas of this schema for the given property name, from keywords
properties,patternProperties, andadditionalProperties. -
#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.
Class Method Details
.default_metaschema ⇒ JSI::Schema
Returns the default metaschema.
27 28 29 |
# File 'lib/jsi/schema.rb', line 27 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).
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 |
# File 'lib/jsi/schema.rb', line 51 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.
32 33 34 35 36 37 |
# File 'lib/jsi/schema.rb', line 32 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 any keys of this schema's "properties" object and any entries of this schema's array of "required" property keys.
194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/jsi/schema.rb', line 194 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 end end end |
#describes_schema? ⇒ Boolean
Returns does this schema itself describe a schema?.
148 149 150 |
# File 'lib/jsi/schema.rb', line 148 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.
209 210 211 |
# File 'lib/jsi/schema.rb', line 209 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.
229 230 231 |
# File 'lib/jsi/schema.rb', line 229 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 < JSI::Base] a JSI class for this one schema
Returns Class < JSI::Base] a JSI class for this one schema.
132 133 134 |
# File 'lib/jsi/schema.rb', line 132 def jsi_schema_class JSI.class_for_schemas(Set[self]) end |
#jsi_schema_module ⇒ Module
Returns a module representing this schema. see JSI::SchemaClasses.module_for_schema.
127 128 129 |
# File 'lib/jsi/schema.rb', line 127 def jsi_schema_module JSI::SchemaClasses.module_for_schema(self) end |
#match_to_instance(other_instance) ⇒ Set<JSI::Schema>
checks this schema for applicators ($ref, allOf, etc.) which should be applied to the given instance. returns these as a Set of JSI::Schemas.
the returned set will contain this schema itself, unless this schema contains a $ref keyword.
159 160 161 162 163 |
# File 'lib/jsi/schema.rb', line 159 def match_to_instance(other_instance) node_ptr.schema_match_ptrs_to_instance(node_document, other_instance).map do |ptr| ptr.evaluate(document_root_node).tap { |subschema| jsi_ensure_subschema_is_schema(subschema, ptr) } end.to_set end |
#new_jsi(other_instance, *a, &b) ⇒ JSI::Base
instantiates the given other_instance as a JSI::Base class for schemas matched from this schema to the other_instance.
any parameters are passed to JSI::Base#initialize, but none are normally used.
143 144 145 |
# File 'lib/jsi/schema.rb', line 143 def new_jsi(other_instance, *a, &b) JSI.class_for_schemas(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.
83 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 |
# File 'lib/jsi/schema.rb', line 83 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 schema_id = parent_auri.merge(fragment: JSI::JSON::Pointer.new(path_from_id_node).fragment).to_s schema_id else nil end end end |
#subschemas_for_index(index) ⇒ Set<JSI::Schema>
returns a set of subschemas of this schema for the given array index, from keywords
items and additionalItems.
183 184 185 186 187 188 189 |
# File 'lib/jsi/schema.rb', line 183 def subschemas_for_index(index) jsi_memoize(:subschemas_for_index, index) do |index| node_ptr.schema_subschema_ptrs_for_index(node_document, index).map do |ptr| ptr.evaluate(document_root_node).tap { |subschema| jsi_ensure_subschema_is_schema(subschema, ptr) } end.to_set end end |
#subschemas_for_property_name(property_name) ⇒ Set<JSI::Schema>
returns a set of subschemas of this schema for the given property name, from keywords
properties, patternProperties, and additionalProperties.
170 171 172 173 174 175 176 |
# File 'lib/jsi/schema.rb', line 170 def subschemas_for_property_name(property_name) jsi_memoize(:subschemas_for_property_name, property_name) do |property_name| node_ptr.schema_subschema_ptrs_for_property_name(node_document, property_name).map do |ptr| ptr.evaluate(document_root_node).tap { |subschema| jsi_ensure_subschema_is_schema(subschema, ptr) } end.to_set end end |
#validate_instance(other_instance) ⇒ true, false
Returns whether the given instance validates against this schema.
214 215 216 |
# File 'lib/jsi/schema.rb', line 214 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.
222 223 224 |
# File 'lib/jsi/schema.rb', line 222 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.
234 235 236 |
# File 'lib/jsi/schema.rb', line 234 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.
242 243 244 |
# File 'lib/jsi/schema.rb', line 242 def validate_schema! ::JSON::Validator.validate!(JSI::Typelike.as_json(node_document), [], fragment: node_ptr.fragment, validate_schema: true, list: true) end |