Module: JSI::Schema
- Included in:
- MetaSchemaNode::BootstrapSchema
- Defined in:
- lib/jsi/schema.rb,
lib/jsi/schema.rb,
lib/jsi/schema/cxt.rb,
lib/jsi/schema/issue.rb,
lib/jsi/schema/dialect.rb,
lib/jsi/schema/draft04.rb,
lib/jsi/schema/draft06.rb,
lib/jsi/schema/draft07.rb,
lib/jsi/schema/element.rb,
lib/jsi/schema/vocabulary.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: Draft04, Draft06, Draft07, Draft202012, Elements, MetaSchema, SchemaAncestorNode Classes: Cxt, Dialect, DynamicAnchorMap, Element, Error, Issue, NotAMetaSchemaError, NotASchemaError, Ref, Vocabulary
Constant Summary collapse
- ReferenceError =
Deprecated.
alias after v0.8
an exception raised when we are unable to resolve a schema reference
ResolutionError
Class Method Summary collapse
-
.ensure_metaschema(metaschema, name: nil, registry: JSI.registry) ⇒ Base + Schema + Schema::MetaSchema
private
Ensures the given param identifies a meta-schema and returns that meta-schema.
-
.ensure_schema(schema, reinstantiate_as: nil) ⇒ Schema
ensure the given object is a JSI Schema.
Instance Method Summary collapse
- #anchors ⇒ Enumerable<String>
-
#described_object_property_names ⇒ Set
any object property names this schema indicates may be present on its instances.
-
#describes_schema!(dialect = nil)
Indicates that this schema describes schemas, i.e.
-
#describes_schema? ⇒ Boolean
Does this schema itself describe a schema? I.e.
-
#dialect ⇒ Schema::Dialect
The dialect of this schema.
- #dialect_invoke_each(action_name, cxt_class = Cxt::Block, **cxt_param) { ... } ⇒ Object
-
#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_immediate_subschema_ptr {|Ptr| ... } ⇒ Object
-
#each_inplace_applicator_schema(instance, visited_refs: Util::EMPTY_ARY) {|JSI::Schema| ... } ⇒ nil
Yields each in-place applicator schema which applies to the given instance.
-
#each_inplace_child_applicator_schema(token, instance, visited_refs: Util::EMPTY_ARY, collect_evaluated: false, collect_evaluated_validate: false) {|Schema| ... } ⇒ Boolean
For each in-place applicator schema that applies to the given instance, yields each child applicator of that schema that applies to the child of the instance on the given token.
-
#id ⇒ #to_str?
the string contents of an
$id/idkeyword, or nil. - #initialize ⇒ Object
-
#instance_valid!(instance) ⇒ nil
Asserts that the given instance is valid against this schema.
-
#instance_valid?(instance) ⇒ Boolean
whether the given instance is valid against this schema.
-
#instance_validate(instance) ⇒ JSI::Validation::Result::Full
Validates the given instance against this schema, returning a result with each validation error.
- #jsi_as_child_default_as_jsi ⇒ Object
- #jsi_each_descendent_schema {|Schema| ... } ⇒ Object
-
#jsi_each_descendent_schema_same_resource {|Schema| ... } ⇒ Object
yields each descendent of this node (including itself) within the same resource that is a Schema.
-
#jsi_is_resource_root? ⇒ Boolean
is this schema the root of a schema resource?.
-
#jsi_is_schema? ⇒ Boolean
Is this a JSI Schema?.
-
#jsi_schema_module ⇒ SchemaModule
The JSI Schema Module for 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_schema_module_name ⇒ String?
- #jsi_schema_module_name_from_ancestor ⇒ String?
-
#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?.
-
#keyword_value?(keyword, value) ⇒ Boolean
Does this schema contain the given keyword with the given value?.
-
#new_jsi(instance, **kw) ⇒ Base
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 SchemaAncestorNode#jsi_resource_root) at the given pointer relative to the root of the schema resource.
-
#schema_absolute_uri ⇒ URI?
deprecated
Deprecated.
after v0.8 - use
#jsi_resource_uri -
#schema_absolute_uris ⇒ Enumerable<URI>
deprecated
Deprecated.
after v0.8 - use
#jsi_resource_uris -
#schema_content ⇒ Object
the underlying JSON data used to instantiate this JSI::Schema.
- #schema_ref(ref = ) ⇒ Schema::Ref
-
#schema_resource_root ⇒ JSI::Base
deprecated
Deprecated.
after v0.8
-
#schema_resource_root? ⇒ Boolean
deprecated
Deprecated.
after v0.8
-
#schema_uri ⇒ URI?
a nonrelative URI which refers to this schema.
-
#schema_uris ⇒ Array<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, registry: JSI.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.
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
# File 'lib/jsi/schema.rb', line 345 def (, name: nil, registry: JSI.registry) if .respond_to?(:to_str) schema = Schema::Ref.new(, registry: registry).resolve if !schema.describes_schema? raise(NotAMetaSchemaError, [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(NotAMetaSchemaError, "#{name || "param"} does not indicate a meta-schema: #{.pretty_inspect.chomp}") end end |
.ensure_schema(schema, reinstantiate_as: nil) ⇒ Schema
ensure the given object is a JSI Schema
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/jsi/schema.rb', line 300 def ensure_schema(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.each_yield_set do |is, y| is.each_inplace_applicator_schema(schema.jsi_node_content, &y) end 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( jsi_document: schema.jsi_document, jsi_ptr: schema.jsi_ptr, jsi_indicated_schemas: result_schema_indicated_schemas, jsi_base_uri: schema.jsi_base_uri, jsi_schema_resource_ancestors: schema.jsi_schema_resource_ancestors, jsi_schema_dynamic_anchor_map: schema.jsi_schema_dynamic_anchor_map, jsi_conf: schema.equal?(schema.jsi_root_node) ? schema.jsi_conf : nil, jsi_root_node: schema.equal?(schema.jsi_root_node) ? nil : schema.jsi_root_node, # bad ).send(:jsi_initialized) else msg = [] msg.concat([*(block_given? ? yield : "indicated object is not a schema:")]) msg << schema.pretty_inspect.chomp if schema.is_a?(Base) msg << "its schemas (which should include a Meta-Schema): #{schema.jsi_schemas.pretty_inspect.chomp}" end raise(NotASchemaError, msg.compact.join("\n")) end end end |
Instance Method Details
#anchors ⇒ Enumerable<String>
407 408 409 410 411 412 |
# File 'lib/jsi/schema.rb', line 407 def anchors anchors = Set[] anchors.merge(dialect_invoke_each(:anchor)) anchors.merge(dialect_invoke_each(:dynamicAnchor)) anchors.freeze 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.
805 806 807 |
# File 'lib/jsi/schema.rb', line 805 def described_object_property_names @described_object_property_names_map[schema_content: schema_content] end |
#describes_schema!(dialect = nil)
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.
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 |
# File 'lib/jsi/schema.rb', line 542 def describes_schema!(dialect = nil) # TODO rm bridge code hax dialect = dialect.first::DIALECT if dialect.is_a?(Array) && dialect.size == 1 if !dialect raise(ArgumentError, "no dialect given and no $vocabulary hash/object") if !schema_content['$vocabulary'].respond_to?(:to_hash) dialect = Schema::Dialect.from_xvocabulary(schema_content['$vocabulary'], registry: jsi_registry) end raise(TypeError) if !dialect.is_a?(Schema::Dialect) if jsi_schema_module <= Schema # this schema 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 dialect, though. if @described_dialect != dialect raise(ArgumentError, "this schema already describes a schema with different dialect") end else jsi_schema_module.include(Schema) jsi_schema_module.send(:define_method, :dialect) { dialect } proc { || jsi_schema_module.send(:define_method, :metaschema) { } }[self] jsi_schema_module.extend(SchemaModule::MetaSchemaModule) end @described_dialect = dialect extend(Schema::MetaSchema) nil end |
#describes_schema? ⇒ Boolean
Does this schema itself describe a schema? I.e. is this schema a meta-schema?
525 526 527 |
# File 'lib/jsi/schema.rb', line 525 def describes_schema? is_a?(Schema::MetaSchema) end |
#dialect_invoke_each(action_name, cxt_class = Cxt::Block, **cxt_param) { ... } ⇒ Object
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 |
# File 'lib/jsi/schema.rb', line 887 def dialect_invoke_each( action_name, cxt_class = Cxt::Block, **cxt_param, &block ) return(to_enum(__method__, action_name, cxt_class, **cxt_param)) unless block_given? cxt = cxt_class.new( schema: self, abort: false, block: block, **cxt_param, ) dialect.invoke(action_name, cxt) nil 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.
721 722 723 724 725 726 727 728 729 730 731 |
# File 'lib/jsi/schema.rb', line 721 def each_child_applicator_schema(token, instance, &block) dialect_invoke_each(:child_applicate, Cxt::ChildApplication, instance: instance, token: token, collect_evaluated: false, collect_evaluated_validate: false, evaluated: false, &block ) end |
#each_immediate_subschema_ptr {|Ptr| ... } ⇒ Object
640 641 642 643 644 |
# File 'lib/jsi/schema.rb', line 640 def each_immediate_subschema_ptr return(to_enum(__method__)) unless block_given? dialect_invoke_each(:subschema) { |ptr| yield(Ptr.ary_ptr(ptr)) } end |
#each_inplace_applicator_schema(instance, visited_refs: Util::EMPTY_ARY) {|JSI::Schema| ... } ⇒ nil
Yields each in-place applicator schema which applies to the given instance.
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
# File 'lib/jsi/schema.rb', line 692 def each_inplace_applicator_schema( instance, visited_refs: Util::EMPTY_ARY, &block ) each_immediate_inplace_applicator_schema( instance: instance, visited_refs: visited_refs, collect_evaluated: false, # child application is not invoked so no evaluated children to collect ) do |schema, ref: nil, applicate: true| if schema.equal?(self) && !ref yield(self) elsif applicate schema.each_inplace_applicator_schema( instance, visited_refs: Util.add_visited_ref(visited_refs, ref), &block ) end end end |
#each_inplace_child_applicator_schema(token, instance, visited_refs: Util::EMPTY_ARY, collect_evaluated: false, collect_evaluated_validate: false) {|Schema| ... } ⇒ Boolean
For each in-place applicator schema that applies to the given instance, yields each child applicator of that schema that applies to the child of the instance on the given token.
This method handles collection of whether the child was evaluated by any applicator
when that evaluation is needed by either this schema or the caller (per param collect_evaluated).
This is relevant to schemas containing unevaluatedProperties or unevaluatedItems.
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 |
# File 'lib/jsi/schema.rb', line 749 def each_inplace_child_applicator_schema( token, instance, visited_refs: Util::EMPTY_ARY, collect_evaluated: false, collect_evaluated_validate: false, &block ) collect_evaluated ||= application_requires_evaluated inplace_child_evaluated = false applicate_self = false each_immediate_inplace_applicator_schema( instance: instance, visited_refs: visited_refs, collect_evaluated: collect_evaluated, ) do |schema, ref: nil, applicate: true| if schema.equal?(self) && !ref applicate_self = true elsif applicate || (collect_evaluated && !inplace_child_evaluated) schema_evaluated = schema.each_inplace_child_applicator_schema( token, instance, visited_refs: Util.add_visited_ref(visited_refs, ref), collect_evaluated: collect_evaluated && !inplace_child_evaluated, collect_evaluated_validate: collect_evaluated_validate, # the `if` keyword needs to yield to here because it does affect `evaluated`, # but it does not applicate itself/its applicators, so does not yield to the given block. &(applicate ? block : proc { }) ) inplace_child_evaluated ||= collect_evaluated && schema_evaluated && (!collect_evaluated_validate || schema.instance_valid?(instance)) end end if applicate_self child_application = dialect.invoke(:child_applicate, Cxt::ChildApplication.new( schema: self, abort: false, token: token, instance: instance, collect_evaluated: collect_evaluated, collect_evaluated_validate: collect_evaluated_validate, evaluated: inplace_child_evaluated, block: block, )) child_application.evaluated else inplace_child_evaluated end end |
#id ⇒ #to_str?
the string contents of an $id/id keyword, or nil
402 403 404 |
# File 'lib/jsi/schema.rb', line 402 def id dialect_invoke_each(:id).first end |
#initialize ⇒ Object
363 364 365 366 |
# File 'lib/jsi/schema.rb', line 363 def initialize(*) super jsi_schema_initialize end |
#instance_valid!(instance) ⇒ nil
Asserts that the given instance is valid against this schema. Error::Invalid is raised if it is not.
839 840 841 |
# File 'lib/jsi/schema.rb', line 839 def instance_valid!(instance) instance_validate(instance).valid! end |
#instance_valid?(instance) ⇒ Boolean
whether the given instance is valid against this schema
827 828 829 830 831 832 |
# File 'lib/jsi/schema.rb', line 827 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::Full
Validates the given instance against this schema, returning a result with each validation error.
813 814 815 816 817 818 819 820 821 822 |
# File 'lib/jsi/schema.rb', line 813 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_as_child_default_as_jsi ⇒ Object
See Base#jsi_as_child_default_as_jsi. true for Schema, including boolean schemas.
880 881 882 |
# File 'lib/jsi/schema.rb', line 880 def jsi_as_child_default_as_jsi true end |
#jsi_each_descendent_schema {|Schema| ... } ⇒ Object
618 619 620 621 622 623 |
# File 'lib/jsi/schema.rb', line 618 def jsi_each_descendent_schema(&block) return(to_enum(__method__)) unless block_given? yield(self) dialect_invoke_each(:subschema) { |ptr| subschema(ptr).jsi_each_descendent_schema(&block) } end |
#jsi_each_descendent_schema_same_resource {|Schema| ... } ⇒ Object
yields each descendent of this node (including itself) within the same resource that is a Schema
627 628 629 630 631 632 633 634 635 636 637 |
# File 'lib/jsi/schema.rb', line 627 def jsi_each_descendent_schema_same_resource(&block) return(to_enum(__method__)) unless block_given? yield(self) dialect_invoke_each(:subschema) do |ptr| desc = subschema(ptr) if !desc.jsi_is_resource_root? desc.jsi_each_descendent_schema_same_resource(&block) end end end |
#jsi_is_resource_root? ⇒ Boolean
is this schema the root of a schema resource?
589 590 591 |
# File 'lib/jsi/schema.rb', line 589 def jsi_is_resource_root? super || jsi_resource_uris.any? end |
#jsi_is_schema? ⇒ Boolean
Is this a JSI Schema?
531 532 533 |
# File 'lib/jsi/schema.rb', line 531 def jsi_is_schema? true end |
#jsi_schema_module ⇒ SchemaModule
The JSI Schema Module for this schema. JSI instances described by this schema are instances of this module.
479 480 481 |
# File 'lib/jsi/schema.rb', line 479 def jsi_schema_module jsi_schema_module_connection 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.
489 490 491 |
# File 'lib/jsi/schema.rb', line 489 def jsi_schema_module_exec(*a, **kw, &block) jsi_schema_module.module_exec(*a, **kw, &block) end |
#jsi_schema_module_name ⇒ String?
494 495 496 497 |
# File 'lib/jsi/schema.rb', line 494 def jsi_schema_module_name # don't hit #jsi_schema_module - avoid creating module, avoid erroring for MSN::BootstrapSchema @memos[:schema_module_connection] && @memos[:schema_module_connection].name end |
#jsi_schema_module_name_from_ancestor ⇒ String?
500 501 502 |
# File 'lib/jsi/schema.rb', line 500 def jsi_schema_module_name_from_ancestor is_a?(Base) ? jsi_schema_module.name_from_ancestor : nil 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.
910 911 912 913 914 915 916 |
# File 'lib/jsi/schema.rb', line 910 def jsi_subschema_resource_ancestors if jsi_is_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?
389 390 391 392 |
# File 'lib/jsi/schema.rb', line 389 def keyword?(keyword) schema_content = jsi_node_content schema_content.respond_to?(:to_hash) && schema_content.key?(keyword) end |
#keyword_value?(keyword, value) ⇒ Boolean
Does this schema contain the given keyword with the given value?
396 397 398 |
# File 'lib/jsi/schema.rb', line 396 def keyword_value?(keyword, value) keyword?(keyword) && schema_content[keyword] == value end |
#new_jsi(instance, **kw) ⇒ Base
Instantiates a new JSI whose content comes from the given instance param.
This schema indicates the schemas of the JSI - its schemas are in-place
applicators of this schema which apply to the given instance.
All parameters are passed to JSI::SchemaSet#new_jsi.
512 513 514 515 |
# File 'lib/jsi/schema.rb', line 512 def new_jsi(instance, **kw) raise(BlockGivenError) if block_given? SchemaSet[self].new_jsi(instance, **kw) end |
#resource_root_subschema(ptr) ⇒ JSI::Schema
A schema in the same schema resource as this one (see JSI::Schema::SchemaAncestorNode#jsi_resource_root) at the given pointer relative to the root of the schema resource.
611 612 613 614 615 |
# File 'lib/jsi/schema.rb', line 611 def resource_root_subschema(ptr) Schema.ensure_schema(jsi_resource_root.jsi_descendent_node(ptr), reinstantiate_as: jsi_conf.reinstantiate_nonschemas && jsi_schemas.select(&:describes_schema?), ) end |
#schema_absolute_uri ⇒ URI?
after v0.8 - use #jsi_resource_uri
the URI of this schema, from an $id keyword, resolved against our #jsi_base_uri
417 418 419 |
# File 'lib/jsi/schema.rb', line 417 def schema_absolute_uri jsi_resource_uri end |
#schema_absolute_uris ⇒ Enumerable<URI>
after v0.8 - use #jsi_resource_uris
423 424 425 |
# File 'lib/jsi/schema.rb', line 423 def schema_absolute_uris jsi_resource_uris 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.
383 384 385 |
# File 'lib/jsi/schema.rb', line 383 def schema_content jsi_node_content end |
#schema_ref(ref = ) ⇒ Schema::Ref
519 520 521 |
# File 'lib/jsi/schema.rb', line 519 def schema_ref(ref = schema_content["$ref"]) @schema_ref_map[ref] end |
#schema_resource_root ⇒ JSI::Base
after v0.8
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.
583 584 585 |
# File 'lib/jsi/schema.rb', line 583 def schema_resource_root jsi_resource_root end |
#schema_resource_root? ⇒ Boolean
after v0.8
594 595 596 |
# File 'lib/jsi/schema.rb', line 594 def schema_resource_root? jsi_is_resource_root? end |
#schema_uri ⇒ 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.
443 444 445 |
# File 'lib/jsi/schema.rb', line 443 def schema_uri schema_uris.first end |
#schema_uris ⇒ Array<URI>
nonrelative URIs (that is, absolute, but possibly with a fragment) which refer to this schema
449 450 451 |
# File 'lib/jsi/schema.rb', line 449 def schema_uris @schema_uris_map[schema_content: schema_content] end |
#subschema(subptr) ⇒ JSI::Schema
a subschema of this Schema
602 603 604 |
# File 'lib/jsi/schema.rb', line 602 def subschema(subptr) Schema.ensure_schema(jsi_descendent_node(subptr)) { "subschema is not a schema at pointer: #{Ptr.ary_ptr(subptr).pointer}" } end |