Class: JSI::MetaSchemaNode

Inherits:
Base
  • Object
show all
Includes:
Base::Immutable
Defined in:
lib/jsi/metaschema_node.rb

Overview

A MetaSchemaNode is a JSI instance representing a node in a document that contains a meta-schema. The root of the meta-schema is pointed to by metaschema_root_ptr. the schema describing the root of the document is pointed to by root_schema_ptr.

like JSI::Base's normal subclasses, this class represents an instance of a schema set, an instance which may itself be a schema. unlike JSI::Base, the document containing the instance and its schemas is the same, and a schema (the meta-schema) may be an instance of itself.

unlike JSI::Base's normal subclasses, the schemas describing the instance are not part of the class. Since the meta-schema describes itself, attempting to construct a class from the JSI Schema Module of a schema which is itself an instance of that class results in a causality loop. instead, a MetaSchemaNode calculates its #jsi_schemas and extends itself with their JSI Schema modules during initialization. The MetaSchemaNode of the meta-schema is extended with its own JSI Schema Module.

if the MetaSchemaNode's schemas include its self, it is extended with Schema::MetaSchema.

a MetaSchemaNode is extended with JSI::Schema when it represents a schema - this is the case when the meta-schema is one of its schemas.

Defined Under Namespace

Classes: BootstrapSchema

Instance Attribute Summary collapse

Attributes included from Base::Immutable

#jsi_node_content

Attributes inherited from Base

#jsi_content_to_immutable, #jsi_document, #jsi_ptr, #jsi_root_node

Attributes included from Schema::SchemaAncestorNode

#jsi_schema_base_uri, #jsi_schema_registry, #jsi_schema_resource_ancestors

Instance Method Summary collapse

Methods included from Base::Immutable

#jsi_mutable?

Methods inherited from Base

#/, #[], #[]=, #as_json, #described_by?, #dup, inspect, #inspect, #jmespath_search, #jsi_ancestor_nodes, #jsi_array?, #jsi_child_as_jsi_default, #jsi_child_token_in_range?, #jsi_child_use_default_default, #jsi_descendent_node, #jsi_each_child_token, #jsi_each_descendent_node, #jsi_hash?, #jsi_instance, #jsi_is_schema?, #jsi_mutable?, #jsi_node_content, #jsi_node_content_child, #jsi_parent_node, #jsi_parent_nodes, #jsi_schema_modules, #jsi_select_descendents_leaf_first, #jsi_select_descendents_node_first, #jsi_valid?, #jsi_validate, name, #pretty_print, #to_json, to_s, #to_s

Methods included from Schema::SchemaAncestorNode

#jsi_anchor_subschema, #jsi_anchor_subschemas, #jsi_resource_ancestor_uri

Constructor Details

#initialize(jsi_document, jsi_ptr: Ptr[], schema_implementation_modules:, metaschema_root_ptr: Ptr[], root_schema_ptr: Ptr[], jsi_schema_base_uri: nil, jsi_schema_registry: nil, jsi_content_to_immutable: DEFAULT_CONTENT_TO_IMMUTABLE, jsi_root_node: nil) ⇒ MetaSchemaNode

Returns a new instance of MetaSchemaNode.

Parameters:

  • jsi_document

    the document containing the meta-schema. this must be frozen recursively; MetaSchemaNode does support mutation.

  • jsi_ptr (JSI::Ptr) (defaults to: Ptr[])

    ptr to this MetaSchemaNode in jsi_document

  • schema_implementation_modules (Enumerable<Module>)

    modules which implement the functionality of the schema. These are included on the Schema#jsi_schema_module of the meta-schema. They extend any schema described by the meta-schema, including those in the document containing the meta-schema, and the meta-schema itself. see Schema#describes_schema! param schema_implementation_modules.

  • metaschema_root_ptr (JSI::Ptr) (defaults to: Ptr[])

    ptr to the root of the meta-schema in the jsi_document

  • root_schema_ptr (JSI::Ptr) (defaults to: Ptr[])

    ptr to the schema describing the root of the jsi_document



38
39
40
41
42
43
44
45
46
47
48
49
50
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
77
78
79
80
81
82
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
125
126
127
128
129
130
131
# File 'lib/jsi/metaschema_node.rb', line 38

def initialize(
    jsi_document,
    jsi_ptr: Ptr[],
    schema_implementation_modules: ,
    metaschema_root_ptr: Ptr[],
    root_schema_ptr: Ptr[],
    jsi_schema_base_uri: nil,
    jsi_schema_registry: nil,
    jsi_content_to_immutable: DEFAULT_CONTENT_TO_IMMUTABLE,
    jsi_root_node: nil
)
  super(jsi_document,
    jsi_ptr: jsi_ptr,
    jsi_indicated_schemas: SchemaSet[],
    jsi_schema_base_uri: jsi_schema_base_uri,
    jsi_schema_registry: jsi_schema_registry,
    jsi_content_to_immutable: jsi_content_to_immutable,
    jsi_root_node: jsi_root_node,
  )

  @schema_implementation_modules = schema_implementation_modules = Util.ensure_module_set(schema_implementation_modules)
  @metaschema_root_ptr = metaschema_root_ptr
  @root_schema_ptr = root_schema_ptr

  if jsi_ptr.root? && jsi_schema_base_uri
    raise(NotImplementedError, "unsupported jsi_schema_base_uri on meta-schema document root")
  end

  #chkbug raise(Bug, 'MetaSchemaNode instance must be frozen') unless jsi_node_content.frozen?

  extends = Set[]

  instance_for_schemas = jsi_document
  bootstrap_schema_class = JSI::SchemaClasses.bootstrap_schema_class(schema_implementation_modules)
  root_bootstrap_schema = bootstrap_schema_class.new(
    jsi_document,
    jsi_ptr: root_schema_ptr,
    jsi_schema_base_uri: nil, # supplying jsi_schema_base_uri on root bootstrap schema is not supported
  )
  our_bootstrap_indicated_schemas = jsi_ptr.tokens.inject(SchemaSet[root_bootstrap_schema]) do |bootstrap_indicated_schemas, tok|
    bootstrap_schemas = bootstrap_indicated_schemas.inplace_applicator_schemas(instance_for_schemas)
    child_indicated_schemas = bootstrap_schemas.child_applicator_schemas(tok, instance_for_schemas)
    instance_for_schemas = instance_for_schemas[tok]
    child_indicated_schemas
  end
  @indicated_schemas_map = jsi_memomap { bootstrap_schemas_to_msn(our_bootstrap_indicated_schemas) }

  our_bootstrap_schemas = our_bootstrap_indicated_schemas.inplace_applicator_schemas(instance_for_schemas)

  describes_self = false
  our_bootstrap_schemas.each do |bootstrap_schema|
    if bootstrap_schema.jsi_ptr == metaschema_root_ptr
      # this is described by the meta-schema, i.e. this is a schema
      extend Schema
      schema_implementation_modules.each do |schema_implementation_module|
        extend schema_implementation_module
      end
      extends += schema_implementation_modules
    end
    if bootstrap_schema.jsi_ptr == jsi_ptr
      # this is the meta-schema (it is described by itself)
      describes_self = true
    end
  end

  @jsi_schemas = bootstrap_schemas_to_msn(our_bootstrap_schemas)

  # note: jsi_schemas must already be set for jsi_schema_module to be used/extended
  if describes_self
    describes_schema!(schema_implementation_modules)
  end

  extends_for_instance = JSI::SchemaClasses.includes_for(jsi_node_content)
  extends.merge(extends_for_instance)
  extends.freeze

  conflicting_modules = Set[self.class] + extends + @jsi_schemas.map(&:jsi_schema_module)
  reader_modules = @jsi_schemas.map do |schema|
    JSI::SchemaClasses.schema_property_reader_module(schema, conflicting_modules: conflicting_modules)
  end

  readers = reader_modules.map(&:jsi_property_readers).inject(Set[], &:merge).freeze
  define_singleton_method(:jsi_property_readers) { readers }

  reader_modules.each { |reader_module| extend reader_module }

  extends_for_instance.each do |m|
    extend m
  end

  @jsi_schemas.each do |schema|
    extend schema.jsi_schema_module
  end
end

Instance Attribute Details

#jsi_schemasJSI::SchemaSet (readonly)

JSI Schemas describing this MetaSchemaNode

Returns:



147
148
149
# File 'lib/jsi/metaschema_node.rb', line 147

def jsi_schemas
  @jsi_schemas
end

#metaschema_root_ptrJSI::Ptr (readonly)

ptr to the root of the meta-schema in the jsi_document

Returns:



139
140
141
# File 'lib/jsi/metaschema_node.rb', line 139

def metaschema_root_ptr
  @metaschema_root_ptr
end

#root_schema_ptrJSI::Ptr (readonly)

ptr to the schema of the root of the jsi_document

Returns:



143
144
145
# File 'lib/jsi/metaschema_node.rb', line 143

def root_schema_ptr
  @root_schema_ptr
end

#schema_implementation_modulesSet<Module> (readonly)

Set of modules to apply to schemas that are instances of (described by) the meta-schema

Returns:

  • (Set<Module>)


135
136
137
# File 'lib/jsi/metaschema_node.rb', line 135

def schema_implementation_modules
  @schema_implementation_modules
end

Instance Method Details

#jsi_fingerprintObject

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.

see Util::Private::FingerprintHash



205
206
207
# File 'lib/jsi/metaschema_node.rb', line 205

def jsi_fingerprint
  {class: self.class, jsi_document: jsi_document}.merge(our_initialize_params).freeze
end

#jsi_indicated_schemasJSI::SchemaSet

Returns:



151
152
153
# File 'lib/jsi/metaschema_node.rb', line 151

def jsi_indicated_schemas
  @indicated_schemas_map[]
end

#jsi_modified_copy {|Object| ... } ⇒ MetaSchemaNode

instantiates a new MetaSchemaNode whose instance is a modified copy of this MetaSchemaNode's instance

Yields:

  • (Object)

    the node content of the instance. the block should result in a (nondestructively) modified copy of this.

Returns:



175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/jsi/metaschema_node.rb', line 175

def jsi_modified_copy(&block)
  if jsi_ptr.root?
    modified_document = jsi_ptr.modified_document_copy(jsi_document, &block)
    modified_document = jsi_content_to_immutable.call(modified_document) if jsi_content_to_immutable
    MetaSchemaNode.new(modified_document, **our_initialize_params)
  else
    modified_jsi_root_node = jsi_root_node.jsi_modified_copy do |root|
      jsi_ptr.modified_document_copy(root, &block)
    end
    modified_jsi_root_node.jsi_descendent_node(jsi_ptr)
  end
end