Class: JSI::Base
- Inherits:
-
Object
- Object
- JSI::Base
- Includes:
- Schema::SchemaAncestorNode
- Defined in:
- lib/jsi/base.rb
Overview
A JSI::Base instance represents a node in a JSON document (its #jsi_document) at a particular location (its #jsi_ptr), described by any number of JSON Schemas (its #jsi_schemas).
JSI::Base is an abstract base class. The subclasses used to instantiate JSIs are dynamically created as needed for a given instance.
These subclasses are generally intended to be ignored by applications using this library - the purpose they serve is to include modules relevant to the instance. The modules these classes include are:
- the JSI Schema Module of each schema which describes the instance
- HashNode, ArrayNode, or StringNode if the instance is a hash/object, array, or string
- Immutable or Mutable
- Modules defining accessor methods for property names described by the schemas
Direct Known Subclasses
Defined Under Namespace
Modules: ArrayNode, HashNode, Immutable, Mutable, StringNode Classes: ChildNotPresent, Conf, SimpleNodeChildError
Instance Attribute Summary collapse
- #jsi_conf ⇒ Base::Conf readonly
-
#jsi_document ⇒ Object
readonly
document containing the instance of this JSI at our #jsi_ptr.
-
#jsi_indicated_schemas ⇒ JSI::SchemaSet
readonly
The schemas indicated as describing this instance, prior to in-place application.
-
#jsi_ptr ⇒ JSI::Ptr
readonly
Ptr pointing to this JSI's instance within our #jsi_document.
-
#jsi_root_node ⇒ JSI::Base
readonly
The root ancestor of this node.
Attributes included from Schema::SchemaAncestorNode
#jsi_base_uri, #jsi_schema_dynamic_anchor_map, #jsi_schema_resource_ancestors
Class Method Summary collapse
-
.inspect ⇒ String
A string indicating the schema module name and/or schema URI of each schema the class represents.
-
.name ⇒ String
A constant name of this class.
- .to_s ⇒ Object
Instance Method Summary collapse
-
#/(ptr) ⇒ JSI::Base
The descendent node at the given Ptr, token array, or pointer string.
-
#[](token, as_jsi: jsi_child_as_jsi_default, use_default: jsi_child_use_default_default) ⇒ Base, ...
Returns a child or children identified by param
token. -
#[]=(token, value) ⇒ Object
Assigns a child identified by the given token to the given value.
-
#as_json(options = {}) ⇒ Object
A structure coerced to JSONifiable types from the instance content.
-
#described_by?(schema) ⇒ Boolean
Is this JSI described by the given schema (or schema module)?.
-
#dup ⇒ Base
A JSI whose node content is a duplicate of this JSI's (using its #dup).
-
#encode_with(coder) ⇒ Object
Psych/YAML .dump calls this method; dumping a JSI as YAML will dump its instance.
-
#initialize(jsi_document:, jsi_ptr: , jsi_indicated_schemas:, jsi_base_uri: nil, jsi_schema_resource_ancestors: Util::EMPTY_ARY, jsi_schema_dynamic_anchor_map: Schema::DynamicAnchorMap::EMPTY, jsi_dynamic_root_map: nil, jsi_conf: nil, jsi_root_node: nil) ⇒ Base
constructor
private
initializes a JSI whose instance is in the given document at the given pointer.
-
#jmespath_search(expression, **runtime_options) ⇒ Array, ...
queries this JSI using the JMESPath Ruby gem.
-
#jsi_ancestor_nodes ⇒ Array<JSI::Base>
ancestor JSI instances from this node up to the root.
-
#jsi_array? ⇒ Boolean
Is the instance an array?.
- #jsi_as_child_default_as_jsi ⇒ Boolean
-
#jsi_child_as_jsi_default ⇒ :auto, ...
deprecated
Deprecated.
after v0.8. This is the parent node's preference whether its children are returned as JSIs, but it is better for a child to indicate whether it should be a JSI by overriding #jsi_as_child_default_as_jsi.
- #jsi_child_ensure_present(token) ⇒ nil private
- #jsi_child_node(token) ⇒ JSI::Base
-
#jsi_child_token_present?(token) ⇒ Boolean
Does the given token identify a child of this node?.
-
#jsi_child_use_default_default ⇒ true, false
The default value for the param
use_defaultof #[], controlling whether a schema default value is returned when a token refers to a child that is not in the document. -
#jsi_descendent_node(ptr) ⇒ JSI::Base
the descendent node at the given pointer.
-
#jsi_each_child_token {|String, Integer| ... } ⇒ nil, Enumerator
yields each token (array index or hash key) identifying a child node.
-
#jsi_each_descendent_node(propertyNames: false) {|JSI::Base| ... } ⇒ nil, Enumerator
yields a JSI of each node at or below this one in this JSI's document.
-
#jsi_each_descendent_schema {|Base + Schema| ... } ⇒ nil, Enumerator
yields each descendent of this node that is a JSI Schema.
-
#jsi_each_descendent_schema_same_resource {|Schema| ... } ⇒ Object
yields each descendent of this node within the same resource that is a Schema.
- #jsi_fingerprint ⇒ Object private
-
#jsi_hash? ⇒ Boolean
Is the instance a ruby Hash (JSON object)?.
-
#jsi_instance ⇒ Object
The JSON schema instance this JSI represents - the underlying JSON data used to instantiate this JSI.
-
#jsi_is_schema? ⇒ Boolean
Is this a JSI Schema?.
-
#jsi_modified_copy(**conf_kw) {|Object| ... } ⇒ Base
yields the content of this JSI's instance.
-
#jsi_mutable? ⇒ Boolean
Is this JSI mutable?.
-
#jsi_node_content ⇒ Object
the content of this node in our #jsi_document at our #jsi_ptr.
-
#jsi_node_content_child(token) ⇒ Object?
The child of the #jsi_node_content identified by the given token, or
nilif the token does not identify an existing child. -
#jsi_parent_node ⇒ JSI::Base?
the immediate parent of this JSI.
-
#jsi_parent_nodes ⇒ Array<JSI::Base>
JSI nodes above this one in the document.
-
#jsi_registry ⇒ Registry?
See SchemaSet#new_jsi param
registry. -
#jsi_resource_root ⇒ Base
The nearest ancestor (including this node) that is a resource root.
-
#jsi_schemas ⇒ JSI::SchemaSet
The set of schemas that describe this instance.
-
#jsi_select_descendents_leaf_first {|JSI::Base| ... } ⇒ JSI::Base
recursively selects descendent nodes of this JSI, returning a modified copy of self containing only descendent nodes for which the given block had a true-ish result.
-
#jsi_select_descendents_node_first {|JSI::Base| ... } ⇒ JSI::Base
recursively selects descendent nodes of this JSI, returning a modified copy of self containing only descendent nodes for which the given block had a true-ish result.
-
#jsi_valid! ⇒ nil
Asserts that this JSI is valid against its schemas.
-
#jsi_valid? ⇒ Boolean
whether this JSI's instance is valid against all of its schemas.
-
#jsi_validate ⇒ JSI::Validation::Result::Full
validates this JSI's instance against its schemas.
-
#pretty_print(q) ⇒ Object
Prints a string indicating this JSI's schemas, briefly, and its content.
-
#to_json(options = {}) ⇒ String
A JSON encoded string of the instance content.
Methods included from Schema::SchemaAncestorNode
#jsi_anchor_subschemas, #jsi_is_resource_root?, #jsi_next_base_uri, #jsi_resource_uri, #jsi_resource_uris, #jsi_schema_base_uri, #jsi_schema_registry
Constructor Details
#initialize(jsi_document:, jsi_ptr: , jsi_indicated_schemas:, jsi_base_uri: nil, jsi_schema_resource_ancestors: Util::EMPTY_ARY, jsi_schema_dynamic_anchor_map: Schema::DynamicAnchorMap::EMPTY, jsi_dynamic_root_map: nil, jsi_conf: nil, jsi_root_node: nil) ⇒ Base
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.
initializes a JSI whose instance is in the given document at the given pointer.
this is a private api - users should look elsewhere to instantiate JSIs, in particular:
- JSI.new_schema and Schema::MetaSchema#new_schema to instantiate schemas
- Schema#new_jsi to instantiate schema instances
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/jsi/base.rb', line 217 def initialize( jsi_document: , jsi_ptr: Ptr[], jsi_indicated_schemas: , jsi_base_uri: nil, jsi_schema_resource_ancestors: Util::EMPTY_ARY, jsi_schema_dynamic_anchor_map: Schema::DynamicAnchorMap::EMPTY, jsi_dynamic_root_map: nil, jsi_conf: nil, jsi_root_node: nil ) #chkbug fail(Bug, "no #jsi_schemas") unless respond_to?(:jsi_schemas) #chkbug fail(Bug) if !jsi_root_node ^ jsi_conf @jsi_conf = jsi_conf = jsi_conf || jsi_root_node.jsi_conf @jsi_document = jsi_document #chkbug fail(Bug) unless jsi_ptr.is_a?(Ptr) #chkbug fail(Bug) unless jsi_ptr.resolve_against(jsi_document).equal?(jsi_ptr) @jsi_ptr = jsi_ptr #chkbug fail(Bug) unless jsi_indicated_schemas.is_a?(SchemaSet) @jsi_indicated_schemas = jsi_indicated_schemas self.jsi_base_uri = jsi_base_uri self.jsi_schema_resource_ancestors = jsi_schema_resource_ancestors self.jsi_schema_dynamic_anchor_map = jsi_schema_dynamic_anchor_map #chkbug fail(Bug) if jsi_root_node && jsi_dynamic_root_map @jsi_dynamic_root_map = jsi_dynamic_root_map || (jsi_root_node ? jsi_root_node.jsi_dynamic_root_map : jsi_memomap(&method(:jsi_dynamic_root_compute))) @jsi_root_node = jsi_root_node || self @root_rel_ptr = @jsi_ptr.relative_to(@jsi_root_node.jsi_ptr) # @memos does not freeze if/when the node freezes @memos = {} jsi_memomaps_initialize jsi_mutability_initialize super() if jsi_instance.is_a?(JSI::Base) raise(TypeError, "a JSI::Base instance must not be another JSI::Base. received: #{jsi_instance.pretty_inspect.chomp}") end end |
Instance Attribute Details
#jsi_conf ⇒ Base::Conf (readonly)
283 284 285 |
# File 'lib/jsi/base.rb', line 283 def jsi_conf @jsi_conf end |
#jsi_document ⇒ Object (readonly)
document containing the instance of this JSI at our #jsi_ptr
267 268 269 |
# File 'lib/jsi/base.rb', line 267 def jsi_document @jsi_document end |
#jsi_indicated_schemas ⇒ JSI::SchemaSet (readonly)
The schemas indicated as describing this instance, prior to in-place application.
This is different from #jsi_schemas, which are the in-place applicator schemas
which describe this instance. for most purposes, #jsi_schemas is more relevant.
jsi_indicated_schemas does not include in-place applicator schemas, such as the
subschemas of allOf, whereas #jsi_schemas does.
this does include indicated schemas which do not apply themselves, such as $ref
schemas (on json schema drafts up to 7) - these are not included on #jsi_schemas.
314 315 316 |
# File 'lib/jsi/base.rb', line 314 def jsi_indicated_schemas @jsi_indicated_schemas end |
#jsi_ptr ⇒ JSI::Ptr (readonly)
Ptr pointing to this JSI's instance within our #jsi_document
271 272 273 |
# File 'lib/jsi/base.rb', line 271 def jsi_ptr @jsi_ptr end |
#jsi_root_node ⇒ JSI::Base (readonly)
The root ancestor of this node. This is typically the document root, though it can be a different resource root when dynamic scope is overridden.
288 289 290 |
# File 'lib/jsi/base.rb', line 288 def jsi_root_node @jsi_root_node end |
Class Method Details
.inspect ⇒ String
A string indicating the schema module name and/or schema URI of each schema the class represents.
150 151 152 153 154 155 156 157 158 |
# File 'lib/jsi/base.rb', line 150 def inspect return super unless respond_to?(:jsi_class_schemas) schema_names = jsi_class_schemas.map do |schema| mod_name = schema.jsi_schema_module_name_from_ancestor next "#{mod_name} <#{schema.jsi_resource_uri}>" if mod_name && schema.jsi_resource_uri mod_name || "<#{schema.schema_uri || schema.jsi_ptr.uri}>" end "(#{[superclass, *schema_names, *jsi_class_includes].join(' + ')})" end |
.name ⇒ String
A constant name of this class. This is generated from any schema module name or URI of each schema this class represents, or random characters.
this generated name is not too pretty but can be more helpful than an anonymous class, especially in error messages.
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/jsi/base.rb', line 171 def name return super if instance_variable_defined?(:@tried_to_name) @tried_to_name = true return super unless respond_to?(:jsi_class_schemas) alnum = proc { |id| (id % 36**4).to_s(36).rjust(4, '0').upcase } schema_names = jsi_class_schemas.map do |schema| named_ancestor, tokens = schema.jsi_schema_module.send(:named_ancestor_tokens) if named_ancestor [named_ancestor.jsi_schema_module_connection.name, *tokens].join('_') elsif schema.schema_uri schema.schema_uri.to_s else [alnum[schema.jsi_root_node.__id__], *schema.jsi_ptr.tokens].join('_') end end includes_names = jsi_class_includes.map { |m| m.name.sub(/\AJSI::Base::/, '').gsub(Util::RUBY_REJECT_NAME_RE, '_') } if schema_names.any? parts = schema_names.compact.sort.map { |n| 'X' + n.to_s } parts += includes_names const_name = Util.const_name_from_parts(parts, join: '__') const_name += "__" + alnum[__id__] if SchemaClasses.const_defined?(const_name) else const_name = (['X' + alnum[__id__]] + includes_names).join('__') end # collisions are technically possible though vanishingly unlikely SchemaClasses.const_set(const_name, self) unless SchemaClasses.const_defined?(const_name) super end |
.to_s ⇒ Object
160 161 162 |
# File 'lib/jsi/base.rb', line 160 def to_s inspect end |
Instance Method Details
#/(ptr) ⇒ JSI::Base
The descendent node at the given Ptr, token array, or pointer string.
Note that, though more convenient to type, using an operator whose meaning may not be intuitive to a reader could impair readability of code.
examples:
my_jsi / ['foo', 'bar']
my_jsi / %w(foo bar)
my_jsi / '/foo/bar'
my_schema / JSI::Ptr['additionalProperties']
my_schema / %w(properties foo items additionalProperties)
503 504 505 |
# File 'lib/jsi/base.rb', line 503 def /(ptr) jsi_descendent_node(ptr.respond_to?(:to_str) ? Ptr.from_pointer(ptr) : ptr) end |
#[](token, as_jsi: jsi_child_as_jsi_default, use_default: jsi_child_use_default_default) ⇒ Base, ...
Returns a child or children identified by param token.
658 659 660 661 662 |
# File 'lib/jsi/base.rb', line 658 def [](token, as_jsi: jsi_child_as_jsi_default, use_default: jsi_child_use_default_default) raise(BlockGivenError) if block_given? # note: overridden by Base::HashNode, Base::ArrayNode jsi_simple_node_child_error(token) end |
#[]=(token, value) ⇒ Object
Assigns a child identified by the given token to the given value. If the given value is a JSI node, its content is used; its #jsi_schemas are not.
695 696 697 698 699 700 701 702 703 704 |
# File 'lib/jsi/base.rb', line 695 def []=(token, value) unless jsi_array? || jsi_hash? jsi_simple_node_child_error(token) end if value.is_a?(Base) self[token] = value.jsi_node_content else jsi_node_content[token] = value end end |
#as_json(options = {}) ⇒ Object
A structure coerced to JSONifiable types from the instance content. Calls Util#as_json with the instance and any given options.
1014 1015 1016 |
# File 'lib/jsi/base.rb', line 1014 def as_json( = {}) Util.as_json(jsi_instance, **) end |
#described_by?(schema) ⇒ Boolean
Is this JSI described by the given schema (or schema module)?
710 711 712 713 714 715 716 717 718 |
# File 'lib/jsi/base.rb', line 710 def described_by?(schema) if schema.is_a?(Schema) jsi_schemas.include?(schema) elsif schema.is_a?(SchemaModule) jsi_schemas.include?(schema.schema) else raise(TypeError, "expected a Schema or Schema Module; got: #{schema.pretty_inspect.chomp}") end end |
#dup ⇒ Base
A JSI whose node content is a duplicate of this JSI's (using its #dup).
Note that immutable JSIs are not made mutable with #dup. The content's #dup may return an unfrozen copy, but instantiating a modified copy of this JSI involves transforming the content to immutable again (using conf to_immutable).
932 933 934 |
# File 'lib/jsi/base.rb', line 932 def dup jsi_modified_copy(&:dup) end |
#encode_with(coder) ⇒ Object
Psych/YAML .dump calls this method; dumping a JSI as YAML will dump its instance.
1027 1028 1029 1030 |
# File 'lib/jsi/base.rb', line 1027 def encode_with(coder) coder.represent_object(nil, jsi_node_content) nil end |
#jmespath_search(expression, **runtime_options) ⇒ Array, ...
queries this JSI using the JMESPath Ruby gem. see https://jmespath.org/ to learn the JMESPath query language.
the JMESPath gem is not a dependency of JSI, so must be installed / added to your Gemfile to use.
e.g. gem 'jmespath', '~> 1.5'. note that versions below 1.5 are not compatible with JSI.
831 832 833 834 835 |
# File 'lib/jsi/base.rb', line 831 def jmespath_search(expression, **) Util.require_jmespath JMESPath.search(expression, self, **) end |
#jsi_ancestor_nodes ⇒ Array<JSI::Base>
ancestor JSI instances from this node up to the root. this node itself is always its own first ancestor.
467 468 469 470 471 472 473 474 475 476 477 |
# File 'lib/jsi/base.rb', line 467 def jsi_ancestor_nodes ancestors = [] ancestor = jsi_root_node ancestors << ancestor @root_rel_ptr.tokens.each do |token| ancestor = ancestor.jsi_child_node(token) ancestors << ancestor end ancestors.reverse!.freeze end |
#jsi_array? ⇒ Boolean
Is the instance an array?
An array is typically an instance of the Array class but may be an object that supports
implicit conversion
with a #to_ary method.
775 776 777 778 |
# File 'lib/jsi/base.rb', line 775 def jsi_array? # note: overridden by Base::ArrayNode false end |
#jsi_as_child_default_as_jsi ⇒ Boolean
When accessing this node as a child (from a parent's #[] or a property reader), should the result
by default be a JSI node (this node), or its node content?
This default may be overridden using the as_jsi parameter calling the parent's #[].
Configurable using child_as_jsi.
669 670 671 672 |
# File 'lib/jsi/base.rb', line 669 def jsi_as_child_default_as_jsi # base default is false, for simple types. overridden by complex types (HashNode, ArrayNode), Schema, and others. jsi_conf.child_as_jsi end |
#jsi_child_as_jsi_default ⇒ :auto, ...
after v0.8. This is the parent node's preference whether its children are returned as JSIs, but it is better for a child to indicate whether it should be a JSI by overriding #jsi_as_child_default_as_jsi.
The default value for the param as_jsi of #[], controlling whether a child is returned as a JSI instance.
678 679 680 |
# File 'lib/jsi/base.rb', line 678 def jsi_child_as_jsi_default :auto end |
#jsi_child_ensure_present(token) ⇒ nil
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.
533 534 535 536 537 538 |
# File 'lib/jsi/base.rb', line 533 def jsi_child_ensure_present(token) if !jsi_child_token_present?(token) raise(ChildNotPresent, -"token does not identify a child that is present: #{token.inspect}\nself = #{pretty_inspect.chomp}") end nil end |
#jsi_child_node(token) ⇒ JSI::Base
567 568 569 |
# File 'lib/jsi/base.rb', line 567 def jsi_child_node(token) @child_node_by_token_map[token: token] end |
#jsi_child_token_present?(token) ⇒ Boolean
Does the given token identify a child of this node?
In other words, is the given token an array index or hash key of the instance?
Always false if this is not a complex node.
526 527 528 529 |
# File 'lib/jsi/base.rb', line 526 def jsi_child_token_present?(token) # note: overridden by Base::HashNode, Base::ArrayNode false end |
#jsi_child_use_default_default ⇒ true, false
The default value for the param use_default of #[], controlling whether a schema default value is
returned when a token refers to a child that is not in the document.
Configurable using child_use_default.
686 687 688 |
# File 'lib/jsi/base.rb', line 686 def jsi_child_use_default_default jsi_conf.child_use_default end |
#jsi_descendent_node(ptr) ⇒ JSI::Base
the descendent node at the given pointer
483 484 485 486 |
# File 'lib/jsi/base.rb', line 483 def jsi_descendent_node(ptr) tokens = Ptr.ary_ptr(ptr).resolve_against(jsi_node_content).tokens tokens.inject(self, &:jsi_child_node) end |
#jsi_each_child_token {|String, Integer| ... } ⇒ nil, Enumerator
yields each token (array index or hash key) identifying a child node. yields nothing if this node is not complex or has no children.
512 513 514 515 516 |
# File 'lib/jsi/base.rb', line 512 def jsi_each_child_token # note: overridden by Base::HashNode, Base::ArrayNode return to_enum(__method__) { 0 } unless block_given? nil end |
#jsi_each_descendent_node(propertyNames: false) {|JSI::Base| ... } ⇒ nil, Enumerator
yields a JSI of each node at or below this one in this JSI's document.
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/jsi/base.rb', line 325 def jsi_each_descendent_node(propertyNames: false, &block) unless block return to_enum(__method__, propertyNames: propertyNames) do # size Util.ycomb do |rec| proc do |node| if node.respond_to?(:to_hash) node.to_hash.inject(1) { |c, (k, child)| c + rec[child] + (propertyNames ? rec[k] : 0) } elsif node.respond_to?(:to_ary) node.to_ary.inject(1) { |c, child| c + rec[child] } else 1 end end end[jsi_node_content] end end yield self if propertyNames && is_a?(HashNode) jsi_each_propertyName do |propertyName| propertyName.jsi_each_descendent_node(propertyNames: propertyNames, &block) end end jsi_each_child_token do |token| jsi_child_node(token).jsi_each_descendent_node(propertyNames: propertyNames, &block) end nil end |
#jsi_each_descendent_schema {|Base + Schema| ... } ⇒ nil, Enumerator
yields each descendent of this node that is a JSI Schema
361 362 363 364 365 366 367 368 |
# File 'lib/jsi/base.rb', line 361 def jsi_each_descendent_schema(&block) return(to_enum(__method__)) unless block_given? # note: this never yields self; if self is a Schema, Schema#jsi_each_descendent_schema overrides this method jsi_each_child_token do |token| jsi_child_node(token).jsi_each_descendent_schema(&block) end end |
#jsi_each_descendent_schema_same_resource {|Schema| ... } ⇒ Object
yields each descendent of this node within the same resource that is a Schema
372 373 374 375 376 377 378 379 380 381 382 |
# File 'lib/jsi/base.rb', line 372 def jsi_each_descendent_schema_same_resource(&block) return(to_enum(__method__)) unless block_given? jsi_each_child_token do |token| child = jsi_child_node(token) if !child.jsi_is_resource_root? # note: if child is a Schema, Schema#jsi_each_descendent_schema_same_resource overrides Base child.jsi_each_descendent_schema_same_resource(&block) end end end |
#jsi_fingerprint ⇒ Object
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.
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
# File 'lib/jsi/base.rb', line 1034 def jsi_fingerprint { class: JSI::Base, jsi_schemas: jsi_schemas, jsi_document: jsi_document, jsi_ptr: jsi_ptr, # for instances in documents with schemas: jsi_base_uri: jsi_base_uri, jsi_root_uri: jsi_conf.root_uri, # different dynamic anchor map means dynamic references may resolve to different resources so must not be equal jsi_schema_dynamic_anchor_map: jsi_schema_dynamic_anchor_map, **jsi_conf.for_fingerprint, }.freeze end |
#jsi_hash? ⇒ Boolean
Is the instance a ruby Hash (JSON object)?
This is typically an instance of the Hash class but may be an object that supports
implicit conversion
with a #to_hash method.
787 788 789 790 |
# File 'lib/jsi/base.rb', line 787 def jsi_hash? # note: overridden by Base::HashNode false end |
#jsi_instance ⇒ Object
The JSON schema instance this JSI represents - the underlying JSON data used to instantiate this JSI. The same as #jsi_node_content - 'node content' is usually preferable terminology, to avoid ambiguity in the heavily overloaded term 'instance'.
298 299 300 |
# File 'lib/jsi/base.rb', line 298 def jsi_instance jsi_node_content end |
#jsi_is_schema? ⇒ Boolean
Is this a JSI Schema?
722 723 724 |
# File 'lib/jsi/base.rb', line 722 def jsi_is_schema? false end |
#jsi_modified_copy(**conf_kw) {|Object| ... } ⇒ Base
yields the content of this JSI's instance. the block must result in a modified copy of the yielded instance (not modified in place, which would alter this JSI as well) which will be used to instantiate and return a new JSI with the modified content.
the result may have different schemas which describe it than this JSI's schemas, if conditional applicator schemas apply differently to the modified instance.
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 |
# File 'lib/jsi/base.rb', line 736 def jsi_modified_copy(**conf_kw, &block) modified_document = @jsi_ptr.modified_document_copy(@jsi_document, &block) conf = jsi_conf.merge(**conf_kw) modified_document = conf.to_immutable.call(modified_document) if !jsi_mutable? && conf.to_immutable root_content = jsi_root_node.jsi_ptr.evaluate(modified_document) root_applied_schemas = SchemaSet.build do |y| c = y.method(:yield) # TODO drop c, just pass y, when all supported Enumerator::Yielder.method_defined?(:to_proc) jsi_root_node.jsi_indicated_schemas.each do |is| is.each_inplace_applicator_schema(root_content, &c) end end root_class = JSI::SchemaClasses.class_for_schemas(root_applied_schemas, includes: SchemaClasses.includes_for(root_content), mutable: jsi_mutable?, ) modified_jsi_root_node = root_class.new( jsi_document: modified_document, jsi_ptr: jsi_root_node.jsi_ptr, jsi_indicated_schemas: jsi_root_node.jsi_indicated_schemas, jsi_base_uri: jsi_root_node.jsi_base_uri, jsi_schema_dynamic_anchor_map: jsi_root_node.jsi_schema_dynamic_anchor_map, jsi_conf: conf, ).send(:jsi_initialized) modified_jsi_root_node.jsi_descendent_node(@root_rel_ptr) end |
#jsi_mutable? ⇒ Boolean
Is this JSI mutable?
794 795 796 |
# File 'lib/jsi/base.rb', line 794 def jsi_mutable? # note: overridden by Base::Mutable / Immutable end |
#jsi_node_content ⇒ Object
the content of this node in our #jsi_document at our #jsi_ptr. the same as #jsi_instance.
291 292 293 |
# File 'lib/jsi/base.rb', line 291 def jsi_node_content # stub method for doc, overridden by Mutable/Immutable end |
#jsi_node_content_child(token) ⇒ Object?
The child of the #jsi_node_content identified by the given token,
or nil if the token does not identify an existing child.
In other words, the element of the instance array at the given index, or the value of the instance hash/object for the given key.
548 549 550 551 |
# File 'lib/jsi/base.rb', line 548 def jsi_node_content_child(token) # note: overridden by Base::HashNode, Base::ArrayNode jsi_simple_node_child_error(token) end |
#jsi_parent_node ⇒ JSI::Base?
the immediate parent of this JSI. nil if there is no parent.
460 461 462 |
# File 'lib/jsi/base.rb', line 460 def jsi_parent_node @root_rel_ptr.root? ? nil : jsi_root_node.jsi_descendent_node(@root_rel_ptr.parent) end |
#jsi_parent_nodes ⇒ Array<JSI::Base>
JSI nodes above this one in the document.
447 448 449 450 451 452 453 454 455 |
# File 'lib/jsi/base.rb', line 447 def jsi_parent_nodes parent_nodes = [] ptr = @root_rel_ptr while !ptr.root? ptr = ptr.parent parent_nodes.push(jsi_root_node.jsi_descendent_node(ptr)) end parent_nodes.freeze end |
#jsi_registry ⇒ Registry?
See SchemaSet#new_jsi param registry
275 276 277 |
# File 'lib/jsi/base.rb', line 275 def jsi_registry jsi_conf.registry end |
#jsi_resource_root ⇒ Base
The nearest ancestor (including this node) that is a resource root.
A resource root is a schema with an absolute URI, or the document's root node (which might not be a schema and might not have an absolute URI).
842 843 844 |
# File 'lib/jsi/base.rb', line 842 def jsi_resource_root super || jsi_root_node end |
#jsi_schemas ⇒ JSI::SchemaSet
The set of schemas that describe this instance. These are the applicator schemas that apply to this instance, the result of in-place application of our #jsi_indicated_schemas.
|
|
# File 'lib/jsi/base.rb', line 258
|
#jsi_select_descendents_leaf_first {|JSI::Base| ... } ⇒ JSI::Base
recursively selects descendent nodes of this JSI, returning a modified copy of self containing only descendent nodes for which the given block had a true-ish result.
this method recursively descends child nodes before yielding each node, so leaf nodes are yielded before their parents.
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/jsi/base.rb', line 422 def jsi_select_descendents_leaf_first(&block) jsi_modified_copy do |instance| if jsi_array? || jsi_hash? res = instance.class.new jsi_each_child_token do |token| v = jsi_child_node(token).jsi_select_descendents_leaf_first(&block) if yield(v) res_v = v.jsi_node_content if jsi_array? res << res_v else res[token] = res_v end end end res else instance end end end |
#jsi_select_descendents_node_first {|JSI::Base| ... } ⇒ JSI::Base
recursively selects descendent nodes of this JSI, returning a modified copy of self containing only descendent nodes for which the given block had a true-ish result.
this method yields a node before recursively descending to its child nodes, so leaf nodes are yielded last, after their parents. if a node is not selected, its descendents are never recursed.
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 |
# File 'lib/jsi/base.rb', line 392 def jsi_select_descendents_node_first(&block) jsi_modified_copy do |instance| if jsi_array? || jsi_hash? res = instance.class.new jsi_each_child_token do |token| v = jsi_child_node(token) if yield(v) res_v = v.jsi_select_descendents_node_first(&block).jsi_node_content if jsi_array? res << res_v else res[token] = res_v end end end res else instance end end end |
#jsi_valid! ⇒ nil
Asserts that this JSI is valid against its schemas. Error::Invalid is raised if it is not.
816 817 818 |
# File 'lib/jsi/base.rb', line 816 def jsi_valid! jsi_validate.valid! end |
#jsi_valid? ⇒ Boolean
whether this JSI's instance is valid against all of its schemas
807 808 809 |
# File 'lib/jsi/base.rb', line 807 def jsi_valid? jsi_indicated_schemas.instance_valid?(self) end |
#jsi_validate ⇒ JSI::Validation::Result::Full
validates this JSI's instance against its schemas
801 802 803 |
# File 'lib/jsi/base.rb', line 801 def jsi_validate jsi_indicated_schemas.instance_validate(self) end |
#pretty_print(q) ⇒ Object
Prints a string indicating this JSI's schemas, briefly, and its content.
If described by a schema with a named schema module, that is shown. The number of schemas describing this JSI is indicated.
If this JSI is a simple type, the node's content is inspected; if complex, its children are inspected.
942 943 944 945 946 |
# File 'lib/jsi/base.rb', line 942 def pretty_print(q) jsi_pp_object_group(q, jsi_object_group_text) do q.pp jsi_instance end end |
#to_json(options = {}) ⇒ String
A JSON encoded string of the instance content. Calls Util#to_json with the instance and any given options.
1021 1022 1023 |
# File 'lib/jsi/base.rb', line 1021 def to_json( = {}) Util.to_json(jsi_instance, ) end |