Class: JSI::MetaschemaNode

Inherits:
Object
  • Object
show all
Includes:
Enumerable, PathedNode, Util::FingerprintHash, Util::Memoize
Defined in:
lib/jsi/metaschema_node.rb

Overview

a MetaschemaNode is a PathedNode whose node_document contains a metaschema. as with any PathedNode the node_ptr points to the content of a node. the root of the metaschema is pointed to by metaschema_root_ptr. the schema of the root of the document is pointed to by root_schema_ptr.

like JSI::Base, this class represents an instance of a schema, an instance which may itself be a schema. unlike JSI::Base, the document containing the schema and the instance is the same, and a schema may be an instance of itself.

the document containing the metaschema, its subschemas, and instances of those subschemas is the node_document.

the schema instance is the content in the document pointed to by the MetaschemaNode's node_ptr.

unlike with JSI::Base, the schema is not part of the class, since a metaschema needs the ability to have its schema be the instance itself.

if the MetaschemaNode's schema is its self, it will be extended with JSI::Metaschema.

a MetaschemaNode is extended with JSI::Schema when it represents a schema - this is the case when its schema is the metaschema.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util::FingerprintHash

#==, #hash

Methods included from Util::Memoize

#jsi_clear_memo, #jsi_memoize

Methods included from PathedNode

#node_content, #node_ptr_deref

Constructor Details

#initialize(node_document, node_ptr: JSI::JSON::Pointer[], metaschema_root_ptr: JSI::JSON::Pointer[], root_schema_ptr: JSI::JSON::Pointer[]) ⇒ MetaschemaNode

Returns a new instance of MetaschemaNode.

Parameters:

  • node_document

    the document containing the metaschema

  • node_ptr (JSI::JSON::Pointer) (defaults to: JSI::JSON::Pointer[])

    ptr to this MetaschemaNode in node_document

  • metaschema_root_ptr (JSI::JSON::Pointer) (defaults to: JSI::JSON::Pointer[])

    ptr to the root of the metaschema in node_document

  • root_schema_ptr (JSI::JSON::Pointer) (defaults to: JSI::JSON::Pointer[])

    ptr to the schema of the root of the node_document



37
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
# File 'lib/jsi/metaschema_node.rb', line 37

def initialize(node_document, node_ptr: JSI::JSON::Pointer[], metaschema_root_ptr: JSI::JSON::Pointer[], root_schema_ptr: JSI::JSON::Pointer[])
  @node_document = node_document
  @node_ptr = node_ptr
  @metaschema_root_ptr = metaschema_root_ptr
  @root_schema_ptr = root_schema_ptr

  node_content = self.node_content

  if node_content.respond_to?(:to_hash)
    extend PathedHashNode
  elsif node_content.respond_to?(:to_ary)
    extend PathedArrayNode
  end

  instance_for_schema = node_document
  schema_ptrs = node_ptr.reference_tokens.inject(Set.new << root_schema_ptr) do |ptrs, tok|
    if instance_for_schema.respond_to?(:to_ary)
      subschema_ptrs_for_token = ptrs.map do |ptr|
        ptr.schema_subschema_ptrs_for_index(node_document, tok)
      end.inject(Set.new, &:|)
    else
      subschema_ptrs_for_token = ptrs.map do |ptr|
        ptr.schema_subschema_ptrs_for_property_name(node_document, tok)
      end.inject(Set.new, &:|)
    end
    instance_for_schema = instance_for_schema[tok]
    ptrs_for_instance = subschema_ptrs_for_token.map do |ptr|
      ptr.schema_match_ptrs_to_instance(node_document, instance_for_schema)
    end.inject(Set.new, &:|)
    ptrs_for_instance
  end

  @jsi_schemas = schema_ptrs.map do |schema_ptr|
    if schema_ptr == node_ptr
      self
    else
      new_node(node_ptr: schema_ptr)
    end
  end.to_set

  @jsi_schemas.each do |schema|
    if schema.node_ptr == metaschema_root_ptr
      extend JSI::Schema
    end
    if schema.node_ptr == node_ptr
      extend Metaschema
    end
    extend(JSI::SchemaClasses.accessor_module_for_schema(schema, conflicting_modules: [Metaschema, Schema, MetaschemaNode, PathedArrayNode, PathedHashNode]))
  end

  # workarounds
  begin # draft 4 boolean schema workaround
    # in draft 4, boolean schemas are not described in the root, but on anyOf schemas on
    # properties/additionalProperties and properties/additionalItems.
    # we need to extend those as DescribesSchema.
    addtlPropsanyOf = metaschema_root_ptr["properties"]["additionalProperties"]["anyOf"]
    addtlItemsanyOf = metaschema_root_ptr["properties"]["additionalItems"]["anyOf"]

    if !node_ptr.root? && [addtlPropsanyOf, addtlItemsanyOf].include?(node_ptr.parent)
      extend JSI::Schema::DescribesSchema
    end
  end
end

Instance Attribute Details

#jsi_schemasObject (readonly)

JSI::Schemas describing this MetaschemaNode



110
111
112
# File 'lib/jsi/metaschema_node.rb', line 110

def jsi_schemas
  @jsi_schemas
end

#metaschema_root_ptrObject (readonly)

ptr to the root of the metaschema in the node_document



106
107
108
# File 'lib/jsi/metaschema_node.rb', line 106

def metaschema_root_ptr
  @metaschema_root_ptr
end

#node_documentObject (readonly)

document containing the metaschema. see PathedNode#node_document.



102
103
104
# File 'lib/jsi/metaschema_node.rb', line 102

def node_document
  @node_document
end

#node_ptrObject (readonly)

ptr to this metaschema node. see PathedNode#node_ptr.



104
105
106
# File 'lib/jsi/metaschema_node.rb', line 104

def node_ptr
  @node_ptr
end

#root_schema_ptrObject (readonly)

ptr to the schema of the root of the node_document



108
109
110
# File 'lib/jsi/metaschema_node.rb', line 108

def root_schema_ptr
  @root_schema_ptr
end

Instance Method Details

#[](token) ⇒ MetaschemaNode, Object

The node content's subscript value at the given token. if there is a subschema defined for that token on this MetaschemaNode's schema, returns that value as a MetaschemaNode instantiation of that subschema.

Parameters:

  • token (String, Integer, Object)

    the token to subscript

Returns:

  • (MetaschemaNode, Object)

    the node content's subscript value at the given token. if there is a subschema defined for that token on this MetaschemaNode's schema, returns that value as a MetaschemaNode instantiation of that subschema.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/jsi/metaschema_node.rb', line 126

def [](token)
  if respond_to?(:to_hash)
    token_in_range = node_content_hash_pubsend(:key?, token)
    value = node_content_hash_pubsend(:[], token)
  elsif respond_to?(:to_ary)
    token_in_range = node_content_ary_pubsend(:each_index).include?(token)
    value = node_content_ary_pubsend(:[], token)
  else
    raise(NoMethodError, "cannot subcript (using token: #{token.inspect}) from content: #{node_content.pretty_inspect.chomp}")
  end

  result = jsi_memoize(:[], token, value, token_in_range) do |token, value, token_in_range|
    if token_in_range
      value_node = new_node(node_ptr: node_ptr[token])

      if value_node.is_a?(Schema) || value.respond_to?(:to_hash) || value.respond_to?(:to_ary)
        value_node
      else
        value
      end
    else
      # I think I will not support Hash#default/#default_proc in this case.
      nil
    end
  end
  result
end

#deref(&block) ⇒ MetaschemaNode

if this MetaschemaNode is a $ref then the $ref is followed. otherwise this MetaschemaNode is returned.

Returns:



156
157
158
159
160
161
# File 'lib/jsi/metaschema_node.rb', line 156

def deref(&block)
  node_ptr_deref do |deref_ptr|
    return new_node(node_ptr: deref_ptr).tap(&(block || Util::NOOP))
  end
  return self
end

#document_root_nodeMetaschemaNode

Returns document root MetaschemaNode.

Returns:



113
114
115
# File 'lib/jsi/metaschema_node.rb', line 113

def document_root_node
  new_node(node_ptr: JSI::JSON::Pointer[])
end

#inspectString

Returns:

  • (String)


171
172
173
# File 'lib/jsi/metaschema_node.rb', line 171

def inspect
  "\#<#{object_group_text.join(' ')} #{node_content.inspect}>"
end

#jsi_fingerprintObject

Returns an opaque fingerprint of this MetaschemaNode for FingerprintHash.

Returns:

  • (Object)

    an opaque fingerprint of this MetaschemaNode for FingerprintHash



203
204
205
# File 'lib/jsi/metaschema_node.rb', line 203

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

#modified_copy {|Object| ... } ⇒ MetaschemaNode

Returns modified copy of self.

Yields:

  • (Object)

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

Returns:



166
167
168
# File 'lib/jsi/metaschema_node.rb', line 166

def modified_copy(&block)
  MetaschemaNode.new(node_ptr.modified_document_copy(node_document, &block), our_initialize_params)
end

#object_group_textArray<String>

Returns:

  • (Array<String>)


189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/jsi/metaschema_node.rb', line 189

def object_group_text
  if jsi_schemas.any?
    class_n_schemas = "#{self.class} (#{jsi_schemas.map { |s| s.node_ptr.uri }.join(' ')})"
  else
    class_n_schemas = self.class.to_s
  end
  [
    class_n_schemas,
    is_a?(Metaschema) ? "Metaschema" : is_a?(Schema) ? "Schema" : nil,
    *(node_content.respond_to?(:object_group_text) ? node_content.object_group_text : []),
  ].compact
end

#parent_nodeMetaschemaNode

Returns parent MetaschemaNode.

Returns:



118
119
120
# File 'lib/jsi/metaschema_node.rb', line 118

def parent_node
  new_node(node_ptr: node_ptr.parent)
end

#pretty_print(q) ⇒ Object



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

def pretty_print(q)
  q.text '#<'
  q.text object_group_text.join(' ')
  q.group_sub {
    q.nest(2) {
      q.breakable ' '
      q.pp node_content
    }
  }
  q.breakable ''
  q.text '>'
end