Module: JSI::Schema
- Included in:
- MetaSchemaNode::BootstrapSchema
- Defined in:
- lib/jsi/schema.rb,
lib/jsi/schema.rb,
lib/jsi/schema/issue.rb,
lib/jsi/schema/draft04.rb,
lib/jsi/schema/draft06.rb,
lib/jsi/schema/draft07.rb
Overview
JSI::Schema is a module which extends Base instances which represent JSON schemas.
This module is included on the JSI Schema module of any schema that describes other schemas, i.e. is a meta-schema (a MetaSchema). Therefore, any JSI instance described by a schema which is a MetaSchema is a schema and is extended by this module.
The content of an instance which is a JSI::Schema (referred to in this context as schema_content) is typically a Hash (JSON object) or a boolean.
Defined Under Namespace
Modules: Application, BigMoneyId, Draft04, Draft06, Draft07, IdWithAnchor, MetaSchema, OldId, SchemaAncestorNode, Validation Classes: Error, Issue, NotASchemaError, Ref, ReferenceError
Class Method Summary collapse
-
.ensure_metaschema(metaschema, name: nil, schema_registry: JSI.schema_registry) ⇒ Base + Schema + Schema::MetaSchema
private
Ensures the given param identifies a meta-schema and returns that meta-schema.
-
.ensure_schema(schema, msg: "indicated object is not a schema:", reinstantiate_as: nil) ⇒ Schema
ensure the given object is a JSI Schema.
Instance Method Summary collapse
-
#child_applicator_schemas(token, instance) ⇒ JSI::SchemaSet
a set of child applicator subschemas of this schema which apply to the child of the given instance on the given token.
-
#described_object_property_names ⇒ Set
any object property names this schema indicates may be present on its instances.
-
#describes_schema!(schema_implementation_modules)
Indicates that this schema describes schemas, i.e.
-
#describes_schema? ⇒ Boolean
Does this schema itself describe a schema? I.e.
-
#each_child_applicator_schema(token, instance) {|JSI::Schema| ... } ⇒ nil, Enumerator
yields each child applicator subschema (from properties, items, etc.) which applies to the child of the given instance on the given token.
-
#each_inplace_applicator_schema(instance, visited_refs: Util::EMPTY_ARY) {|JSI::Schema| ... } ⇒ nil, Enumerator
yields each inplace applicator schema which applies to the given instance.
-
#each_schema_uri {|Addressable::URI| ... } ⇒ Enumerator?
see #schema_uris.
- #initialize ⇒ Object
-
#inplace_applicator_schemas(instance) ⇒ JSI::SchemaSet
a set of inplace applicator schemas of this schema (from $ref, allOf, etc.) which apply to the given instance.
-
#instance_valid?(instance) ⇒ Boolean
whether the given instance is valid against this schema.
-
#instance_validate(instance) ⇒ JSI::Validation::Result
validates the given instance against this schema.
-
#jsi_is_schema? ⇒ Boolean
Is this a JSI Schema?.
-
#jsi_schema_module ⇒ SchemaModule
a module which extends all instances of this schema.
-
#jsi_schema_module_exec(*a, **kw, &block) ⇒ Object
Evaluates the given block in the context of this schema's JSI schema module.
-
#jsi_subschema_resource_ancestors ⇒ Array<JSI::Schema>
private
schema resources which are ancestors of any subschemas below this schema.
-
#keyword?(keyword) ⇒ Boolean
does this schema contain the given keyword?.
-
#new_jsi(instance, **kw) ⇒ JSI::Base subclass
Instantiates a new JSI whose content comes from the given
instance
param. -
#resource_root_subschema(ptr) ⇒ JSI::Schema
a schema in the same schema resource as this one (see #schema_resource_root) at the given pointer relative to the root of the schema resource.
-
#schema_absolute_uri ⇒ Addressable::URI?
the URI of this schema, calculated from our
#id
, resolved against our#jsi_schema_base_uri
. -
#schema_content ⇒ Object
the underlying JSON data used to instantiate this JSI::Schema.
- #schema_ref(keyword = "$ref") ⇒ Schema::Ref
-
#schema_resource_root ⇒ JSI::Base
a resource containing this schema.
-
#schema_resource_root? ⇒ Boolean
is this schema the root of a schema resource?.
-
#schema_uri ⇒ Addressable::URI?
a nonrelative URI which refers to this schema.
-
#schema_uris ⇒ Array<Addressable::URI>
nonrelative URIs (that is, absolute, but possibly with a fragment) which refer to this schema.
-
#subschema(subptr) ⇒ JSI::Schema
a subschema of this Schema.
Class Method Details
.ensure_metaschema(metaschema, name: nil, schema_registry: JSI.schema_registry) ⇒ Base + Schema + Schema::MetaSchema
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Ensures the given param identifies a meta-schema and returns that meta-schema.
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 |
# File 'lib/jsi/schema.rb', line 418 def (, name: nil, schema_registry: JSI.schema_registry) if .respond_to?(:to_str) schema = Schema::Ref.new(, schema_registry: schema_registry).deref_schema if !schema.describes_schema? raise(TypeError, [name, "URI indicates a schema that is not a meta-schema: #{.pretty_inspect.chomp}"].compact.join(" ")) end schema elsif .is_a?(SchemaModule::MetaSchemaModule) .schema elsif .is_a?(Schema::MetaSchema) else raise(TypeError, "#{name || "param"} does not indicate a meta-schema: #{.pretty_inspect.chomp}") end end |
.ensure_schema(schema, msg: "indicated object is not a schema:", reinstantiate_as: nil) ⇒ Schema
ensure the given object is a JSI Schema
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
# File 'lib/jsi/schema.rb', line 379 def ensure_schema(schema, msg: "indicated object is not a schema:", reinstantiate_as: nil) if schema.is_a?(Schema) schema else if reinstantiate_as && schema.is_a?(JSI::Base) # TODO warn; behavior is undefined and I hate this implementation result_schema_indicated_schemas = SchemaSet.new(schema.jsi_indicated_schemas + reinstantiate_as) result_schema_applied_schemas = result_schema_indicated_schemas.inplace_applicator_schemas(schema.jsi_node_content) result_schema_class = JSI::SchemaClasses.class_for_schemas(result_schema_applied_schemas, includes: SchemaClasses.includes_for(schema.jsi_node_content), mutable: schema.jsi_mutable?, ) result_schema_class.new(schema.jsi_document, jsi_ptr: schema.jsi_ptr, jsi_indicated_schemas: result_schema_indicated_schemas, jsi_schema_base_uri: schema.jsi_schema_base_uri, jsi_schema_resource_ancestors: schema.jsi_schema_resource_ancestors, jsi_schema_registry: schema.jsi_schema_registry, jsi_content_to_immutable: schema.jsi_content_to_immutable, jsi_root_node: schema.jsi_ptr.root? ? nil : schema.jsi_root_node, # bad ) else raise(NotASchemaError, [ *msg, schema.pretty_inspect.chomp, ].join("\n")) end end end |
Instance Method Details
#child_applicator_schemas(token, instance) ⇒ JSI::SchemaSet
a set of child applicator subschemas of this schema which apply to the child of the given instance on the given token.
692 693 694 |
# File 'lib/jsi/schema.rb', line 692 def child_applicator_schemas(token, instance) SchemaSet.new(each_child_applicator_schema(token, instance)) end |
#described_object_property_names ⇒ Set
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.
714 715 716 |
# File 'lib/jsi/schema.rb', line 714 def described_object_property_names @described_object_property_names_map[] end |
#describes_schema!(schema_implementation_modules)
This method returns an undefined value.
Indicates that this schema describes schemas, i.e. it is a meta-schema. this schema is extended with MetaSchema and its #jsi_schema_module is extended with JSI::SchemaModule::MetaSchemaModule, and the JSI Schema Module will include JSI::Schema and the given modules.
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 |
# File 'lib/jsi/schema.rb', line 588 def describes_schema!(schema_implementation_modules) schema_implementation_modules = Util.ensure_module_set(schema_implementation_modules) if describes_schema? # this schema, or one equal to it, has already had describes_schema! called on it. # this is to be avoided, but is not particularly a problem. # it is a bug if it was called different times with different schema_implementation_modules, though. unless jsi_schema_module.schema_implementation_modules == schema_implementation_modules raise(ArgumentError, "this schema already describes a schema with different schema_implementation_modules") end else jsi_schema_module.include(Schema) schema_implementation_modules.each do |mod| jsi_schema_module.include(mod) end jsi_schema_module.extend(SchemaModule::MetaSchemaModule) end @schema_implementation_modules = schema_implementation_modules extend(Schema::MetaSchema) nil end |
#describes_schema? ⇒ Boolean
Does this schema itself describe a schema? I.e. is this schema a meta-schema?
570 571 572 |
# File 'lib/jsi/schema.rb', line 570 def describes_schema? jsi_schema_module <= JSI::Schema || false end |
#each_child_applicator_schema(token, instance) {|JSI::Schema| ... } ⇒ nil, Enumerator
yields each child applicator subschema (from properties, items, etc.) which applies to the child of the given instance on the given token.
702 703 704 705 706 707 708 |
# File 'lib/jsi/schema.rb', line 702 def each_child_applicator_schema(token, instance, &block) return to_enum(__method__, token, instance) unless block internal_child_applicate_keywords(token, instance, &block) nil end |
#each_inplace_applicator_schema(instance, visited_refs: Util::EMPTY_ARY) {|JSI::Schema| ... } ⇒ nil, Enumerator
yields each inplace applicator schema which applies to the given instance.
671 672 673 674 675 676 677 678 679 680 681 682 683 |
# File 'lib/jsi/schema.rb', line 671 def each_inplace_applicator_schema( instance, visited_refs: Util::EMPTY_ARY, &block ) return to_enum(__method__, instance, visited_refs: visited_refs) unless block catch(:jsi_application_done) do internal_inplace_applicate_keywords(instance, visited_refs, &block) end nil end |
#each_schema_uri {|Addressable::URI| ... } ⇒ Enumerator?
see #schema_uris
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 |
# File 'lib/jsi/schema.rb', line 497 def each_schema_uri return to_enum(__method__) unless block_given? yield schema_absolute_uri if schema_absolute_uri ancestor_schemas = jsi_subschema_resource_ancestors.reverse_each.select do |resource| resource.schema_absolute_uri end anchored = respond_to?(:anchor) ? anchor : nil ancestor_schemas.each do |ancestor_schema| if anchored if ancestor_schema.jsi_anchor_subschema(anchor) == self yield(ancestor_schema.schema_absolute_uri.merge(fragment: anchor).freeze) else anchored = false end end relative_ptr = jsi_ptr.relative_to(ancestor_schema.jsi_ptr) yield(ancestor_schema.schema_absolute_uri.merge(fragment: relative_ptr.fragment).freeze) end nil end |
#initialize ⇒ Object
436 437 438 439 |
# File 'lib/jsi/schema.rb', line 436 def initialize(*) super jsi_schema_initialize end |
#inplace_applicator_schemas(instance) ⇒ JSI::SchemaSet
a set of inplace applicator schemas of this schema (from $ref, allOf, etc.) which apply to the given instance.
the returned set will contain this schema itself, unless this schema contains a $ref keyword.
661 662 663 |
# File 'lib/jsi/schema.rb', line 661 def inplace_applicator_schemas(instance) SchemaSet.new(each_inplace_applicator_schema(instance)) end |
#instance_valid?(instance) ⇒ Boolean
whether the given instance is valid against this schema
747 748 749 750 751 752 |
# File 'lib/jsi/schema.rb', line 747 def instance_valid?(instance) if instance.is_a?(SchemaAncestorNode) instance = instance.jsi_node_content end internal_validate_instance(Ptr[], instance, validate_only: true).valid? end |
#instance_validate(instance) ⇒ JSI::Validation::Result
validates the given instance against this schema
733 734 735 736 737 738 739 740 741 742 |
# File 'lib/jsi/schema.rb', line 733 def instance_validate(instance) if instance.is_a?(SchemaAncestorNode) instance_ptr = instance.jsi_ptr instance_document = instance.jsi_document else instance_ptr = Ptr[] instance_document = instance end internal_validate_instance(instance_ptr, instance_document) end |
#jsi_is_schema? ⇒ Boolean
Is this a JSI Schema?
576 577 578 |
# File 'lib/jsi/schema.rb', line 576 def jsi_is_schema? true end |
#jsi_schema_module ⇒ SchemaModule
a module which extends all instances of this schema. this may be opened by the application to add methods to schema instances.
some functionality is also defined on the module itself (its singleton class, not for its instances):
- the module is extended with JSI::SchemaModule, which defines .new_jsi to instantiate instances of this schema (see #new_jsi).
- properties described by this schema's metaschema are defined as methods to get subschemas' schema
modules, so for example
schema.jsi_schema_module.items
returns the same module asschema.items.jsi_schema_module
. - method .schema which returns this schema.
536 537 538 |
# File 'lib/jsi/schema.rb', line 536 def jsi_schema_module JSI::SchemaClasses.module_for_schema(self) end |
#jsi_schema_module_exec(*a, **kw, &block) ⇒ Object
Evaluates the given block in the context of this schema's JSI schema module. Any arguments passed to this method will be passed to the block. shortcut to invoke Module#module_exec on our #jsi_schema_module.
546 547 548 |
# File 'lib/jsi/schema.rb', line 546 def jsi_schema_module_exec(*a, **kw, &block) jsi_schema_module.module_exec(*a, **kw, &block) end |
#jsi_subschema_resource_ancestors ⇒ Array<JSI::Schema>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
schema resources which are ancestors of any subschemas below this schema. this may include this schema if this is a schema resource root.
804 805 806 807 808 809 810 |
# File 'lib/jsi/schema.rb', line 804 def jsi_subschema_resource_ancestors if schema_resource_root? jsi_schema_resource_ancestors.dup.push(self).freeze else jsi_schema_resource_ancestors end end |
#keyword?(keyword) ⇒ Boolean
does this schema contain the given keyword?
456 457 458 459 |
# File 'lib/jsi/schema.rb', line 456 def keyword?(keyword) schema_content = jsi_node_content schema_content.respond_to?(:to_hash) && schema_content.key?(keyword) end |
#new_jsi(instance, **kw) ⇒ JSI::Base subclass
Instantiates a new JSI whose content comes from the given instance
param.
This schema indicates the schemas of the JSI - its schemas are inplace
applicators of this schema which apply to the given instance.
557 558 559 |
# File 'lib/jsi/schema.rb', line 557 def new_jsi(instance, **kw) SchemaSet[self].new_jsi(instance, **kw) end |
#resource_root_subschema(ptr) ⇒ JSI::Schema
a schema in the same schema resource as this one (see #schema_resource_root) at the given pointer relative to the root of the schema resource.
647 648 649 650 651 652 |
# File 'lib/jsi/schema.rb', line 647 def resource_root_subschema(ptr) ptr = Ptr.ary_ptr(ptr) Schema.ensure_schema(schema_resource_root.jsi_descendent_node(ptr), reinstantiate_as: jsi_schemas.select(&:describes_schema?) ) end |
#schema_absolute_uri ⇒ Addressable::URI?
the URI of this schema, calculated from our #id
, resolved against our #jsi_schema_base_uri
463 464 465 466 467 468 469 470 471 472 473 474 |
# File 'lib/jsi/schema.rb', line 463 def schema_absolute_uri if respond_to?(:id_without_fragment) && id_without_fragment if jsi_schema_base_uri jsi_schema_base_uri.join(id_without_fragment).freeze elsif id_without_fragment.absolute? id_without_fragment else # TODO warn / schema_error nil end end end |
#schema_content ⇒ Object
the underlying JSON data used to instantiate this JSI::Schema. this is an alias for Base#jsi_node_content, named for clarity in the context of working with a schema.
450 451 452 |
# File 'lib/jsi/schema.rb', line 450 def schema_content jsi_node_content end |
#schema_ref(keyword = "$ref") ⇒ Schema::Ref
563 564 565 566 |
# File 'lib/jsi/schema.rb', line 563 def schema_ref(keyword = "$ref") raise(ArgumentError, "keyword not present: #{keyword}") unless keyword?(keyword) @schema_ref_map[keyword: keyword, value: schema_content[keyword]] end |
#schema_resource_root ⇒ JSI::Base
a resource containing this schema.
If any ancestor, or this schema itself, is a schema with an absolute uri (see #schema_absolute_uri), the resource root is the closest schema with an absolute uri.
If no ancestor schema has an absolute uri, the schema_resource_root is the document's root node. In this case, the resource root may or may not be a schema itself.
621 622 623 |
# File 'lib/jsi/schema.rb', line 621 def schema_resource_root jsi_subschema_resource_ancestors.last || jsi_root_node end |
#schema_resource_root? ⇒ Boolean
is this schema the root of a schema resource?
627 628 629 |
# File 'lib/jsi/schema.rb', line 627 def schema_resource_root? jsi_ptr.root? || !!schema_absolute_uri end |
#schema_uri ⇒ Addressable::URI?
a nonrelative URI which refers to this schema.
nil
if no ancestor of this schema defines an id.
see #schema_uris for all URIs known to refer to this schema.
480 481 482 |
# File 'lib/jsi/schema.rb', line 480 def schema_uri schema_uris.first end |
#schema_uris ⇒ Array<Addressable::URI>
nonrelative URIs (that is, absolute, but possibly with a fragment) which refer to this schema
486 487 488 |
# File 'lib/jsi/schema.rb', line 486 def schema_uris @schema_uris_map[] end |
#subschema(subptr) ⇒ JSI::Schema
a subschema of this Schema
635 636 637 638 639 640 |
# File 'lib/jsi/schema.rb', line 635 def subschema(subptr) subptr = Ptr.ary_ptr(subptr) Schema.ensure_schema(jsi_descendent_node(subptr), msg: [ "subschema is not a schema at pointer: #{subptr.pointer}" ]) end |