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
instanceparam. -
#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.
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
# File 'lib/jsi/schema.rb', line 411 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: #{metaschema.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: #{metaschema.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
372 373 374 375 376 377 378 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 |
# File 'lib/jsi/schema.rb', line 372 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.
691 692 693 |
# File 'lib/jsi/schema.rb', line 691 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.
713 714 715 |
# File 'lib/jsi/schema.rb', line 713 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.
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
# File 'lib/jsi/schema.rb', line 581 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?
563 564 565 |
# File 'lib/jsi/schema.rb', line 563 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.
701 702 703 704 705 706 707 |
# File 'lib/jsi/schema.rb', line 701 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.
670 671 672 673 674 675 676 677 678 679 680 681 682 |
# File 'lib/jsi/schema.rb', line 670 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
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
# File 'lib/jsi/schema.rb', line 490 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
429 430 431 432 |
# File 'lib/jsi/schema.rb', line 429 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.
660 661 662 |
# File 'lib/jsi/schema.rb', line 660 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
746 747 748 749 750 751 |
# File 'lib/jsi/schema.rb', line 746 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
732 733 734 735 736 737 738 739 740 741 |
# File 'lib/jsi/schema.rb', line 732 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?
569 570 571 |
# File 'lib/jsi/schema.rb', line 569 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.itemsreturns the same module asschema.items.jsi_schema_module. - method .schema which returns this schema.
529 530 531 |
# File 'lib/jsi/schema.rb', line 529 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.
539 540 541 |
# File 'lib/jsi/schema.rb', line 539 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.
803 804 805 806 807 808 809 |
# File 'lib/jsi/schema.rb', line 803 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?
449 450 451 452 |
# File 'lib/jsi/schema.rb', line 449 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.
550 551 552 |
# File 'lib/jsi/schema.rb', line 550 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.
643 644 645 |
# File 'lib/jsi/schema.rb', line 643 def resource_root_subschema(ptr) @resource_root_subschema_map[ptr: Ptr.ary_ptr(ptr)] end |
#schema_absolute_uri ⇒ Addressable::URI?
the URI of this schema, calculated from our #id, resolved against our #jsi_schema_base_uri
456 457 458 459 460 461 462 463 464 465 466 467 |
# File 'lib/jsi/schema.rb', line 456 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.
443 444 445 |
# File 'lib/jsi/schema.rb', line 443 def schema_content jsi_node_content end |
#schema_ref(keyword = "$ref") ⇒ Schema::Ref
556 557 558 559 |
# File 'lib/jsi/schema.rb', line 556 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.
614 615 616 |
# File 'lib/jsi/schema.rb', line 614 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?
620 621 622 |
# File 'lib/jsi/schema.rb', line 620 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.
473 474 475 |
# File 'lib/jsi/schema.rb', line 473 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
479 480 481 |
# File 'lib/jsi/schema.rb', line 479 def schema_uris @schema_uris_map[] end |
#subschema(subptr) ⇒ JSI::Schema
a subschema of this Schema
628 629 630 |
# File 'lib/jsi/schema.rb', line 628 def subschema(subptr) @subschema_map[subptr: Ptr.ary_ptr(subptr)] end |