Skip to content

Commit

Permalink
Merge remote-tracking branches 'origin/node', 'origin/indicated', 'or…
Browse files Browse the repository at this point in the history
…igin/new', 'origin/jsi_each_propertyName', 'origin/memomap', 'origin/misc', 'origin/test' and 'origin/deprecated' into HEAD

node               #267
indicated           #248
new                  #268
jsi_each_propertyName #256
memomap              #266
misc                #265
test               #269
deprecated        #270
  • Loading branch information
notEthan committed Jan 31, 2023
8 parents ed1fecc + 068dc94 + 451b547 + 7a437e1 + 89f1571 + 2a94adb + c208454 + 480e81d commit 1c9cc7c
Show file tree
Hide file tree
Showing 29 changed files with 467 additions and 206 deletions.
4 changes: 1 addition & 3 deletions lib/jsi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
require "bigdecimal"
require "addressable/uri"

require "jsi/util"

module JSI
# generally put in code paths that are not expected to be valid control flow paths.
# rather a NotImplementedCorrectlyError. but that's too long.
Expand All @@ -28,8 +26,8 @@ class Bug < NotImplementedError
# @private
SCHEMAS_PATH = RESOURCES_PATH.join('schemas')

autoload :Util, 'jsi/util'
autoload :Ptr, 'jsi/ptr'
autoload :Typelike, 'jsi/util/typelike'
autoload :Schema, 'jsi/schema'
autoload :SchemaSet, 'jsi/schema_set'
autoload :Base, 'jsi/base'
Expand Down
53 changes: 31 additions & 22 deletions lib/jsi/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def name
def initialize(jsi_document,
jsi_ptr: Ptr[],
jsi_root_node: nil,
jsi_indicated_schemas: ,
jsi_schema_base_uri: nil,
jsi_schema_resource_ancestors: Util::EMPTY_ARY
)
Expand All @@ -146,6 +147,7 @@ def initialize(jsi_document,
raise(Bug, "jsi_root_node ptr is not root") if !jsi_root_node.jsi_ptr.root?
@jsi_root_node = jsi_root_node
end
self.jsi_indicated_schemas = jsi_indicated_schemas
self.jsi_schema_base_uri = jsi_schema_base_uri
self.jsi_schema_resource_ancestors = jsi_schema_resource_ancestors

Expand Down Expand Up @@ -180,6 +182,20 @@ def jsi_node_content
# the JSON schema instance this JSI represents - the underlying JSON data used to instantiate this JSI
alias_method :jsi_instance, :jsi_node_content

# the schemas indicated as describing this instance, prior to inplace application.
#
# this is different from {#jsi_schemas}, which are the inplace applicator schemas
# which describe this instance. for most purposes, `#jsi_schemas` is more relevant.
#
# `jsi_indicated_schemas` does not include inplace 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`.
#
# @return [JSI::SchemaSet]
attr_reader :jsi_indicated_schemas

# yields a JSI of each node at or below this one in this JSI's document.
#
# returns an Enumerator if no block is given.
Expand Down Expand Up @@ -228,9 +244,6 @@ def jsi_select_descendents_node_first(&block)
end
end

# @deprecated after v0.6
alias_method :jsi_select_children_node_first, :jsi_select_descendents_node_first

# 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.
#
Expand Down Expand Up @@ -261,9 +274,6 @@ def jsi_select_descendents_leaf_first(&block)
end
end

# @deprecated after v0.6
alias_method :jsi_select_children_leaf_first, :jsi_select_descendents_leaf_first

# an array of JSI instances above this one in the document.
#
# @return [Array<JSI::Base>]
Expand All @@ -274,7 +284,7 @@ def jsi_parent_nodes
parent.tap do
parent = parent[token, as_jsi: true]
end
end.reverse
end.reverse!.freeze
end

# the immediate parent of this JSI. nil if there is no parent.
Expand Down Expand Up @@ -366,20 +376,22 @@ def [](token, as_jsi: :auto, use_default: true)
end

begin
subinstance_schemas = jsi_subinstance_schemas_memos[token: token, instance: jsi_node_content, subinstance: value]
child_indicated_schemas = jsi_schemas.child_applicator_schemas(token, jsi_node_content)
child_applied_schemas = child_indicated_schemas.inplace_applicator_schemas(value)

if token_in_range
jsi_subinstance_as_jsi(value, subinstance_schemas, as_jsi) do
jsi_subinstance_as_jsi(value, child_applied_schemas, as_jsi) do
jsi_subinstance_memos[
token: token,
subinstance_schemas: subinstance_schemas,
child_indicated_schemas: child_indicated_schemas,
child_applied_schemas: child_applied_schemas,
includes: SchemaClasses.includes_for(value),
]
end
else
if use_default
defaults = Set.new
subinstance_schemas.each do |subinstance_schema|
child_applied_schemas.each do |subinstance_schema|
if subinstance_schema.keyword?('default')
defaults << subinstance_schema.jsi_node_content['default']
end
Expand Down Expand Up @@ -436,7 +448,7 @@ def jsi_schema_modules
def jsi_modified_copy(&block)
if @jsi_ptr.root?
modified_document = @jsi_ptr.modified_document_copy(@jsi_document, &block)
jsi_schemas.new_jsi(modified_document,
jsi_indicated_schemas.new_jsi(modified_document,
uri: jsi_schema_base_uri,
)
else
Expand Down Expand Up @@ -475,13 +487,13 @@ def jsi_hash?
#
# @return [JSI::Validation::FullResult]
def jsi_validate
jsi_schemas.instance_validate(self)
jsi_indicated_schemas.instance_validate(self)
end

# whether this JSI's instance is valid against all of its schemas
# @return [Boolean]
def jsi_valid?
jsi_schemas.instance_valid?(self)
jsi_indicated_schemas.instance_valid?(self)
end

# queries this JSI using the [JMESPath Ruby](https://rubygems.org/gems/jmespath) gem.
Expand Down Expand Up @@ -569,26 +581,23 @@ def jsi_fingerprint
jsi_ptr: jsi_ptr,
# for instances in documents with schemas:
jsi_resource_ancestor_uri: jsi_resource_ancestor_uri,
# only defined for JSI::Schema instances:
jsi_schema_instance_modules: is_a?(Schema) ? jsi_schema_instance_modules : nil,
}
end
include Util::FingerprintHash

private

def jsi_subinstance_schemas_memos
jsi_memomap(:subinstance_schemas, key_by: -> (i) { i[:token] }) do |token: , instance: , subinstance: |
jsi_schemas.child_applicator_schemas(token, instance).inplace_applicator_schemas(subinstance)
end
def jsi_indicated_schemas=(jsi_indicated_schemas)
@jsi_indicated_schemas = SchemaSet.ensure_schema_set(jsi_indicated_schemas)
end

def jsi_subinstance_memos
jsi_memomap(:subinstance, key_by: -> (i) { i[:token] }) do |token: , subinstance_schemas: , includes: |
jsi_class = JSI::SchemaClasses.class_for_schemas(subinstance_schemas, includes: includes)
jsi_memomap(:subinstance, key_by: -> (i) { i[:token] }) do |token: , child_indicated_schemas: , child_applied_schemas: , includes: |
jsi_class = JSI::SchemaClasses.class_for_schemas(child_applied_schemas, includes: includes)
jsi_class.new(@jsi_document,
jsi_ptr: @jsi_ptr[token],
jsi_root_node: @jsi_root_node,
jsi_indicated_schemas: child_indicated_schemas,
jsi_schema_base_uri: jsi_resource_ancestor_uri,
jsi_schema_resource_ancestors: is_a?(Schema) ? jsi_subschema_resource_ancestors : jsi_schema_resource_ancestors,
)
Expand Down
23 changes: 22 additions & 1 deletion lib/jsi/base/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,34 @@ def to_a(**kw)

alias_method :entries, :to_a

# instantiates and yields each property name (hash key) as a JSI described by any `propertyNames` schemas.
#
# @yield [JSI::Base]
# @return [nil, Enumerator] an Enumerator if invoked without a block; otherwise nil
def jsi_each_propertyName
return to_enum(__method__) { jsi_node_content_hash_pubsend(:size) } unless block_given?

property_schemas = SchemaSet.build do |schemas|
jsi_schemas.each do |s|
if s.keyword?('propertyNames') && s['propertyNames'].is_a?(Schema)
schemas << s['propertyNames']
end
end
end
jsi_node_content_hash_pubsend(:each_key) do |key|
yield property_schemas.new_jsi(key)
end

nil
end

# a jsonifiable representation of the node content
# @return [Object]
def as_json(*opt)
# include Enumerable (above) means, if ActiveSupport is loaded, its undesirable #as_json is included
# https://github.com/rails/rails/blob/v7.0.0/activesupport/lib/active_support/core_ext/object/json.rb#L139-L143
# although Base#as_json does clobber activesupport's, I want as_json defined correctly on the module too.
Typelike.as_json(jsi_node_content, *opt)
Util.as_json(jsi_node_content, *opt)
end
end

Expand Down
24 changes: 11 additions & 13 deletions lib/jsi/jsi_coder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ def initialize(schema, array: false)
# instance(s), or nil if data is nil
def load(data)
return nil if data.nil?
object = if @array

if @array
unless data.respond_to?(:to_ary)
raise TypeError, "expected array-like column data; got: #{data.class}: #{data.inspect}"
end
data.to_ary.map { |el| load_object(el) }
else
load_object(data)
end
object
end

# dumps the object for the database
Expand All @@ -61,19 +61,17 @@ def load(data)
# @return [Object, Array, nil] the schema instance(s) of the JSI(s), or nil if object is nil
def dump(object)
return nil if object.nil?
jsonifiable = begin
if @array
unless object.respond_to?(:to_ary)
raise(TypeError, "expected array-like attribute; got: #{object.class}: #{object.inspect}")
end
object.to_ary.map do |el|
dump_object(el)
end
else
dump_object(object)

if @array
unless object.respond_to?(:to_ary)
raise(TypeError, "expected array-like attribute; got: #{object.class}: #{object.inspect}")
end
object.to_ary.map do |el|
dump_object(el)
end
else
dump_object(object)
end
jsonifiable
end

private
Expand Down
12 changes: 5 additions & 7 deletions lib/jsi/metaschema_node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,6 @@ def initialize(

jsi_node_content = self.jsi_node_content

if jsi_node_content.respond_to?(:to_hash)
extend HashNode
end
if jsi_node_content.respond_to?(:to_ary)
extend ArrayNode
end

instance_for_schemas = jsi_document
bootstrap_schema_class = JSI::SchemaClasses.bootstrap_schema_class(schema_implementation_modules)
root_bootstrap_schema = bootstrap_schema_class.new(
Expand Down Expand Up @@ -111,6 +104,11 @@ def initialize(
describes_schema!(schema_implementation_modules)
end

extends_for_instance = JSI::SchemaClasses.includes_for(jsi_node_content)
extends_for_instance.each do |m|
extend m
end

@jsi_schemas.each do |schema|
extend schema.jsi_schema_module
end
Expand Down
3 changes: 0 additions & 3 deletions lib/jsi/ptr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,6 @@ def relative_to(ancestor_ptr)
Ptr.new(tokens[ancestor_ptr.tokens.size..-1])
end

# @deprecated after v0.6
alias_method :ptr_relative_to, :relative_to

# a pointer with the tokens of this one plus the given `ptr`'s.
# @param ptr [JSI::Ptr, #to_ary]
# @return [JSI::Ptr]
Expand Down
Loading

0 comments on commit 1c9cc7c

Please sign in to comment.