jsi 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,113 @@
1
+ module JSI
2
+ # including class MUST define
3
+ # - #node_document [Object] returning the document
4
+ # - #node_ptr [JSI::JSON::Pointer] returning a pointer for the node path in the document
5
+ # - #document_root_node [JSI::PathedNode] returning a PathedNode pointing at the document root
6
+ # - #parent_node [JSI::PathedNode] returning the parent node of this PathedNode
7
+ # - #deref [JSI::PathedNode] following a $ref
8
+ #
9
+ # given these, this module represents the node in the document at the path.
10
+ #
11
+ # the node content (#node_content) is the result of evaluating the node document at the path.
12
+ module PathedNode
13
+ def node_content
14
+ content = node_ptr.evaluate(node_document)
15
+ content
16
+ end
17
+
18
+ def node_ptr_deref(&block)
19
+ node_ptr.deref(node_document, &block)
20
+ end
21
+ end
22
+
23
+ # module extending a {JSI::PathedNode} object when its node_content is Hash-like (responds to #to_hash)
24
+ module PathedHashNode
25
+ # yields each hash key and value of this node.
26
+ #
27
+ # each yielded key is the same as a key of the node content hash,
28
+ # and each yielded value is the result of self[key] (see #[]).
29
+ #
30
+ # returns an Enumerator if no block is given.
31
+ #
32
+ # @yield [Object, Object] each key and value of this hash node
33
+ # @return [self, Enumerator]
34
+ def each(&block)
35
+ return to_enum(__method__) { node_content_hash_pubsend(:size) } unless block_given?
36
+ if block.arity > 1
37
+ node_content_hash_pubsend(:each_key) { |k| yield k, self[k] }
38
+ else
39
+ node_content_hash_pubsend(:each_key) { |k| yield [k, self[k]] }
40
+ end
41
+ self
42
+ end
43
+
44
+ # @return [Hash] a hash in which each key is a key of the node_content hash and
45
+ # each value is the result of self[key] (see #[]).
46
+ def to_hash
47
+ {}.tap { |h| each_key { |k| h[k] = self[k] } }
48
+ end
49
+
50
+ include Hashlike
51
+
52
+ # @param method_name [String, Symbol]
53
+ # @param *a, &b are passed to the invocation of method_name
54
+ # @return [Object] the result of calling method method_name on the node_content or its #to_hash
55
+ def node_content_hash_pubsend(method_name, *a, &b)
56
+ if node_content.respond_to?(method_name)
57
+ node_content.public_send(method_name, *a, &b)
58
+ else
59
+ node_content.to_hash.public_send(method_name, *a, &b)
60
+ end
61
+ end
62
+
63
+ # methods that don't look at the value; can skip the overhead of #[] (invoked by #to_hash)
64
+ SAFE_KEY_ONLY_METHODS.each do |method_name|
65
+ define_method(method_name) do |*a, &b|
66
+ node_content_hash_pubsend(method_name, *a, &b)
67
+ end
68
+ end
69
+ end
70
+
71
+ module PathedArrayNode
72
+ # yields each array element of this node.
73
+ #
74
+ # each yielded element is the result of self[index] for each index of our array (see #[]).
75
+ #
76
+ # returns an Enumerator if no block is given.
77
+ #
78
+ # @yield [Object] each element of this array node
79
+ # @return [self, Enumerator]
80
+ def each
81
+ return to_enum(__method__) { node_content_ary_pubsend(:size) } unless block_given?
82
+ node_content_ary_pubsend(:each_index) { |i| yield(self[i]) }
83
+ self
84
+ end
85
+
86
+ # @return [Array] an array, the same size as the node_content, in which the
87
+ # element at each index is the result of self[index] (see #[])
88
+ def to_ary
89
+ to_a
90
+ end
91
+
92
+ include Arraylike
93
+
94
+ # @param method_name [String, Symbol]
95
+ # @param *a, &b are passed to the invocation of method_name
96
+ # @return [Object] the result of calling method method_name on the node_content or its #to_ary
97
+ def node_content_ary_pubsend(method_name, *a, &b)
98
+ if node_content.respond_to?(method_name)
99
+ node_content.public_send(method_name, *a, &b)
100
+ else
101
+ node_content.to_ary.public_send(method_name, *a, &b)
102
+ end
103
+ end
104
+
105
+ # methods that don't look at the value; can skip the overhead of #[] (invoked by #to_a).
106
+ # we override these methods from Arraylike
107
+ SAFE_INDEX_ONLY_METHODS.each do |method_name|
108
+ define_method(method_name) do |*a, &b|
109
+ node_content_ary_pubsend(method_name, *a, &b)
110
+ end
111
+ end
112
+ end
113
+ end
@@ -8,6 +8,9 @@ module JSI
8
8
  include Memoize
9
9
 
10
10
  class << self
11
+ # @param schema_object [#to_hash, Boolean, JSI::Schema] an object to be instantiated as a schema.
12
+ # if it's already a schema, it is returned as-is.
13
+ # @return [JSI::Schema]
11
14
  def from_object(schema_object)
12
15
  if schema_object.is_a?(Schema)
13
16
  schema_object
@@ -17,36 +20,30 @@ module JSI
17
20
  end
18
21
  end
19
22
 
20
- # initializes a schema from a given JSI::Base, JSI::JSON::Node, or hash.
21
- # @param schema_object [JSI::Base, #to_hash] the schema
23
+ # initializes a schema from a given JSI::Base, JSI::JSON::Node, or hash. Boolean schemas are
24
+ # instantiated as their equivalent hash ({} for true and {"not" => {}} for false).
25
+ #
26
+ # @param schema_object [JSI::Base, #to_hash, Boolean] the schema
22
27
  def initialize(schema_object)
23
28
  if schema_object.is_a?(JSI::Schema)
24
29
  raise(TypeError, "will not instantiate Schema from another Schema: #{schema_object.pretty_inspect.chomp}")
25
- elsif schema_object.is_a?(JSI::Base)
26
- @schema_jsi = JSI.deep_stringify_symbol_keys(schema_object.deref)
27
- @schema_node = @schema_jsi.instance
28
- elsif schema_object.is_a?(JSI::JSON::HashNode)
29
- @schema_jsi = nil
30
+ elsif schema_object.is_a?(JSI::PathedNode)
30
31
  @schema_node = JSI.deep_stringify_symbol_keys(schema_object.deref)
31
32
  elsif schema_object.respond_to?(:to_hash)
32
- @schema_jsi = nil
33
33
  @schema_node = JSI::JSON::Node.new_doc(JSI.deep_stringify_symbol_keys(schema_object))
34
+ elsif schema_object == true
35
+ @schema_node = JSI::JSON::Node.new_doc({})
36
+ elsif schema_object == false
37
+ @schema_node = JSI::JSON::Node.new_doc({"not" => {}})
34
38
  else
35
39
  raise(TypeError, "cannot instantiate Schema from: #{schema_object.pretty_inspect.chomp}")
36
40
  end
37
41
  end
38
42
 
39
- # @return [JSI::JSON::Node] a JSI::JSON::Node for the schema
43
+ # @return [JSI::PathedNode] a JSI::PathedNode (JSI::JSON::Node or JSI::Base) for the schema
40
44
  attr_reader :schema_node
41
45
 
42
- # @return [JSI::Base, nil] a JSI for this schema, if a metaschema is known; otherwise nil
43
- attr_reader :schema_jsi
44
-
45
- # @return [JSI::Base, JSI::JSON::Node] either a JSI::Base subclass or a
46
- # JSI::JSON::Node for the schema
47
- def schema_object
48
- @schema_jsi || @schema_node
49
- end
46
+ alias_method :schema_object, :schema_node
50
47
 
51
48
  # @return [JSI::Base, JSI::JSON::Node, Object] property value from the schema_object
52
49
  # @param property_name [String, Object] property name to access from the schema_object
@@ -69,7 +66,7 @@ module JSI
69
66
  # look at 'id' if node_for_id is a schema, or the document root.
70
67
  # decide whether to look at '$id' for all parent nodes or also just schemas.
71
68
  if node_for_id.respond_to?(:to_hash)
72
- if node_for_id.path.empty? || node_for_id.object_id == schema_node.object_id
69
+ if node_for_id.node_ptr.root? || node_for_id.object_id == schema_node.object_id
73
70
  # I'm only looking at 'id' for the document root and the schema node
74
71
  # until I track what parents are schemas.
75
72
  parent_id = node_for_id['$id'] || node_for_id['id']
@@ -80,30 +77,30 @@ module JSI
80
77
  end
81
78
  end
82
79
 
83
- if parent_id || node_for_id.path.empty?
80
+ if parent_id || node_for_id.node_ptr.root?
84
81
  done = true
85
82
  else
86
- path_from_id_node.unshift(node_for_id.path.last)
83
+ path_from_id_node.unshift(node_for_id.node_ptr.reference_tokens.last)
87
84
  node_for_id = node_for_id.parent_node
88
85
  end
89
86
  end
90
87
  if parent_id
91
88
  parent_auri = Addressable::URI.parse(parent_id)
92
89
  else
93
- node_for_id = schema_node.document_node
94
- validator = ::JSON::Validator.new(node_for_id.content, nil)
90
+ node_for_id = schema_node.document_root_node
91
+ validator = ::JSON::Validator.new(Typelike.as_json(node_for_id), nil)
95
92
  # TODO not good instance_exec'ing into another library's ivars
96
93
  parent_auri = validator.instance_exec { @base_schema }.uri
97
94
  end
98
95
  if parent_auri.fragment
99
96
  # add onto the fragment
100
- parent_id_path = JSI::JSON::Pointer.new(:fragment, '#' + parent_auri.fragment).reference_tokens
97
+ parent_id_path = JSI::JSON::Pointer.from_fragment('#' + parent_auri.fragment).reference_tokens
101
98
  path_from_id_node = parent_id_path + path_from_id_node
102
99
  parent_auri.fragment = nil
103
100
  #else: no fragment so parent_id good as is
104
101
  end
105
102
 
106
- fragment = JSI::JSON::Pointer.new(:reference_tokens, path_from_id_node).fragment
103
+ fragment = JSI::JSON::Pointer.new(path_from_id_node).fragment
107
104
  schema_id = parent_auri.to_s + fragment
108
105
 
109
106
  schema_id
@@ -111,26 +108,35 @@ module JSI
111
108
  end
112
109
 
113
110
  # @return [Class subclassing JSI::Base] shortcut for JSI.class_for_schema(schema)
114
- def schema_class
111
+ def jsi_schema_class
115
112
  JSI.class_for_schema(self)
116
113
  end
117
114
 
115
+ alias_method :schema_class, :jsi_schema_class
116
+
117
+ # calls #new on the class for this schema with the given arguments. for parameters,
118
+ # see JSI::Base#initialize documentation.
119
+ #
120
+ # @return [JSI::Base] a JSI whose schema is this schema and whose instance is the given instance
121
+ def new_jsi(other_instance, *a, &b)
122
+ jsi_schema_class.new(other_instance, *a, &b)
123
+ end
124
+
118
125
  # if this schema is a oneOf, allOf, anyOf schema, #match_to_instance finds
119
126
  # one of the subschemas that matches the given instance and returns it. if
120
127
  # there are no matching *Of schemas, this schema is returned.
121
128
  #
122
- # @param instance [Object] the instance to which to attempt to match *Of subschemas
129
+ # @param other_instance [Object] the instance to which to attempt to match *Of subschemas
123
130
  # @return [JSI::Schema] a matched subschema, or this schema (self)
124
- def match_to_instance(instance)
131
+ def match_to_instance(other_instance)
125
132
  # matching oneOf is good here. one schema for one instance.
126
133
  # matching anyOf is okay. there could be more than one schema matched. it's often just one. if more
127
134
  # than one is a match, you just get the first one.
128
- instance = instance.deref if instance.is_a?(JSI::JSON::Node)
129
135
  %w(oneOf anyOf).select { |k| schema_node[k].respond_to?(:to_ary) }.each do |someof_key|
130
136
  schema_node[someof_key].map(&:deref).map do |someof_node|
131
137
  someof_schema = self.class.new(someof_node)
132
- if someof_schema.validate(instance)
133
- return someof_schema.match_to_instance(instance)
138
+ if someof_schema.validate_instance(other_instance)
139
+ return someof_schema.match_to_instance(other_instance)
134
140
  end
135
141
  end
136
142
  end
@@ -227,33 +233,33 @@ module JSI
227
233
 
228
234
  # @return [Array<String>] array of schema validation error messages for
229
235
  # the given instance against this schema
230
- def fully_validate(instance)
231
- ::JSON::Validator.fully_validate(JSI::Typelike.as_json(schema_node.document), JSI::Typelike.as_json(instance), fragment: schema_node.fragment)
236
+ def fully_validate_instance(other_instance)
237
+ ::JSON::Validator.fully_validate(JSI::Typelike.as_json(schema_node.node_document), JSI::Typelike.as_json(other_instance), fragment: schema_node.node_ptr.fragment)
232
238
  end
233
239
 
234
240
  # @return [true, false] whether the given instance validates against this schema
235
- def validate(instance)
236
- ::JSON::Validator.validate(JSI::Typelike.as_json(schema_node.document), JSI::Typelike.as_json(instance), fragment: schema_node.fragment)
241
+ def validate_instance(other_instance)
242
+ ::JSON::Validator.validate(JSI::Typelike.as_json(schema_node.node_document), JSI::Typelike.as_json(other_instance), fragment: schema_node.node_ptr.fragment)
237
243
  end
238
244
 
239
245
  # @return [true] if this method does not raise, it returns true to
240
246
  # indicate the instance is valid against this schema
241
247
  # @raise [::JSON::Schema::ValidationError] raises if the instance has
242
248
  # validation errors against this schema
243
- def validate!(instance)
244
- ::JSON::Validator.validate!(JSI::Typelike.as_json(schema_node.document), JSI::Typelike.as_json(instance), fragment: schema_node.fragment)
249
+ def validate_instance!(other_instance)
250
+ ::JSON::Validator.validate!(JSI::Typelike.as_json(schema_node.node_document), JSI::Typelike.as_json(other_instance), fragment: schema_node.node_ptr.fragment)
245
251
  end
246
252
 
247
253
  # @return [Array<String>] array of schema validation error messages for
248
254
  # this schema, validated against its metaschema. a default metaschema
249
255
  # is assumed if the schema does not specify a $schema.
250
256
  def fully_validate_schema
251
- ::JSON::Validator.fully_validate(JSI::Typelike.as_json(schema_node.document), [], fragment: schema_node.fragment, validate_schema: true, list: true)
257
+ ::JSON::Validator.fully_validate(JSI::Typelike.as_json(schema_node.node_document), [], fragment: schema_node.node_ptr.fragment, validate_schema: true, list: true)
252
258
  end
253
259
 
254
260
  # @return [true, false] whether this schema validates against its metaschema
255
261
  def validate_schema
256
- ::JSON::Validator.validate(JSI::Typelike.as_json(schema_node.document), [], fragment: schema_node.fragment, validate_schema: true, list: true)
262
+ ::JSON::Validator.validate(JSI::Typelike.as_json(schema_node.node_document), [], fragment: schema_node.node_ptr.fragment, validate_schema: true, list: true)
257
263
  end
258
264
 
259
265
  # @return [true] if this method does not raise, it returns true to
@@ -261,7 +267,7 @@ module JSI
261
267
  # @raise [::JSON::Schema::ValidationError] raises if this schema has
262
268
  # validation errors against its metaschema
263
269
  def validate_schema!
264
- ::JSON::Validator.validate!(JSI::Typelike.as_json(schema_node.document), [], fragment: schema_node.fragment, validate_schema: true, list: true)
270
+ ::JSON::Validator.validate!(JSI::Typelike.as_json(schema_node.node_document), [], fragment: schema_node.node_ptr.fragment, validate_schema: true, list: true)
265
271
  end
266
272
 
267
273
  # @return [String] a string for #instance and #pretty_print including the schema_id
@@ -298,7 +304,7 @@ module JSI
298
304
 
299
305
  # @return [Object] an opaque fingerprint of this Schema for FingerprintHash
300
306
  def fingerprint
301
- {class: self.class, schema_node: schema_node}
307
+ {class: self.class, schema_ptr: schema_node.node_ptr, schema_document: JSI::Typelike.as_json(schema_node.node_document)}
302
308
  end
303
309
  include FingerprintHash
304
310
  end
@@ -0,0 +1,86 @@
1
+ module JSI
2
+ # this module is just a namespace for schema classes.
3
+ module SchemaClasses
4
+ # JSI::SchemaClasses[schema_id] returns a class for the schema with the
5
+ # given id, the same class as returned from JSI.class_for_schema.
6
+ #
7
+ # @param schema_id [String] absolute schema id as returned by {JSI::Schema#schema_id}
8
+ # @return [Class subclassing JSI::Base] the class for that schema
9
+ def self.[](schema_id)
10
+ @classes_by_id[schema_id]
11
+ end
12
+ @classes_by_id = {}
13
+
14
+ class << self
15
+ include Memoize
16
+
17
+ # see {JSI.class_for_schema}
18
+ def class_for_schema(schema_object)
19
+ memoize(:class_for_schema, JSI::Schema.from_object(schema_object)) do |schema_|
20
+ Class.new(Base).instance_exec(schema_) do |schema|
21
+ define_singleton_method(:schema) { schema }
22
+ define_method(:schema) { schema }
23
+ include(JSI::SchemaClasses.module_for_schema(schema, conflicting_modules: [Base, BaseArray, BaseHash]))
24
+
25
+ jsi_class = self
26
+ define_method(:jsi_class) { jsi_class }
27
+
28
+ SchemaClasses.instance_exec(self) { |klass| @classes_by_id[klass.schema_id] = klass }
29
+
30
+ self
31
+ end
32
+ end
33
+ end
34
+
35
+ # a module for the given schema, with accessor methods for any object
36
+ # property names the schema identifies. also has a singleton method
37
+ # called #schema to access the {JSI::Schema} this module represents.
38
+ #
39
+ # accessor methods are defined on these modules so that methods can be
40
+ # defined on {JSI.class_for_schema} classes without method redefinition
41
+ # warnings. additionally, these overriding instance methods can call
42
+ # `super` to invoke the normal accessor behavior.
43
+ #
44
+ # no property names that are the same as existing method names on the JSI
45
+ # class will be defined. users should use #[] and #[]= to access properties
46
+ # whose names conflict with existing methods.
47
+ def SchemaClasses.module_for_schema(schema_object, conflicting_modules: [])
48
+ schema__ = JSI::Schema.from_object(schema_object)
49
+ memoize(:module_for_schema, schema__, conflicting_modules) do |schema_, conflicting_modules_|
50
+ Module.new.tap do |m|
51
+ m.instance_exec(schema_) do |schema|
52
+ define_singleton_method(:schema) { schema }
53
+ define_singleton_method(:schema_id) do
54
+ schema.schema_id
55
+ end
56
+ define_singleton_method(:inspect) do
57
+ %Q(#<Module for Schema: #{schema_id}>)
58
+ end
59
+
60
+ conflicting_instance_methods = (conflicting_modules_ + [m]).map do |mod|
61
+ mod.instance_methods + mod.private_instance_methods
62
+ end.inject(Set.new, &:|)
63
+ accessors_to_define = schema.described_object_property_names.map(&:to_s) - conflicting_instance_methods.map(&:to_s)
64
+ accessors_to_define.each do |property_name|
65
+ define_method(property_name) do
66
+ if respond_to?(:[])
67
+ self[property_name]
68
+ else
69
+ raise(NoMethodError, "schema instance of class #{self.class} does not respond to []; cannot call reader '#{property_name}'. instance is #{instance.pretty_inspect.chomp}")
70
+ end
71
+ end
72
+ define_method("#{property_name}=") do |value|
73
+ if respond_to?(:[]=)
74
+ self[property_name] = value
75
+ else
76
+ raise(NoMethodError, "schema instance of class #{self.class} does not respond to []=; cannot call writer '#{property_name}='. instance is #{instance.pretty_inspect.chomp}")
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,7 @@
1
+ module JSI
2
+ SimpleWrap = JSI.class_for_schema({"additionalProperties": {"$ref": "#"}, "items": {"$ref": "#"}})
3
+
4
+ # SimpleWrap is a JSI class which recursively wraps nested structures
5
+ class SimpleWrap
6
+ end
7
+ end
@@ -36,12 +36,8 @@ module JSI
36
36
  # @raise [TypeError] when the object (or an object nested with a hash or
37
37
  # array of object) cannot be expressed as json
38
38
  def self.as_json(object, *opt)
39
- if object.is_a?(JSI::Schema)
40
- as_json(object.schema_object, *opt)
41
- elsif object.is_a?(JSI::Base)
42
- as_json(object.instance, *opt)
43
- elsif object.is_a?(JSI::JSON::Node)
44
- as_json(object.content, *opt)
39
+ if object.is_a?(JSI::PathedNode)
40
+ as_json(object.node_content, *opt)
45
41
  elsif object.respond_to?(:to_hash)
46
42
  (object.respond_to?(:map) ? object : object.to_hash).map do |k, v|
47
43
  unless k.is_a?(Symbol) || k.respond_to?(:to_str)
@@ -78,7 +74,7 @@ module JSI
78
74
  SAFE_KEY_VALUE_METHODS = %w(< <= > >= any? assoc compact dig each_pair each_value fetch fetch_values has_value? invert key merge rassoc reject select to_h to_proc transform_values value? values values_at)
79
75
  DESTRUCTIVE_METHODS = %w(clear delete delete_if keep_if reject! replace select! shift)
80
76
  # these return a modified copy
81
- safe_modified_copy_methods = %w(compact merge)
77
+ safe_modified_copy_methods = %w(compact)
82
78
  # select and reject will return a modified copy but need the yielded block variable value from #[]
83
79
  safe_kv_block_modified_copy_methods = %w(select reject)
84
80
  SAFE_METHODS = SAFE_KEY_ONLY_METHODS | SAFE_KEY_VALUE_METHODS
@@ -88,7 +84,7 @@ module JSI
88
84
  end
89
85
  safe_modified_copy_methods.each do |method_name|
90
86
  define_method(method_name) do |*a, &b|
91
- JSI::Typelike.modified_copy(self) do |object_to_modify|
87
+ modified_copy do |object_to_modify|
92
88
  responsive_object = object_to_modify.respond_to?(method_name) ? object_to_modify : object_to_modify.to_hash
93
89
  responsive_object.public_send(method_name, *a, &b)
94
90
  end
@@ -96,7 +92,7 @@ module JSI
96
92
  end
97
93
  safe_kv_block_modified_copy_methods.each do |method_name|
98
94
  define_method(method_name) do |*a, &b|
99
- JSI::Typelike.modified_copy(self) do |object_to_modify|
95
+ modified_copy do |object_to_modify|
100
96
  responsive_object = object_to_modify.respond_to?(method_name) ? object_to_modify : object_to_modify.to_hash
101
97
  responsive_object.public_send(method_name, *a) do |k, _v|
102
98
  b.call(k, self[k])
@@ -105,6 +101,38 @@ module JSI
105
101
  end
106
102
  end
107
103
 
104
+ # the same as Hash#update
105
+ # @param other [#to_hash] the other hash to update this hash from
106
+ # @yield [key, oldval, newval] for entries with duplicate keys, the value of each duplicate key
107
+ # is determined by calling the block with the key, its value in hsh and its value in other_hash.
108
+ # @return self, updated with other
109
+ # @raise [TypeError] when `other` does not respond to #to_hash
110
+ def update(other, &block)
111
+ unless other.respond_to?(:to_hash)
112
+ raise(TypeError, "cannot update with argument that does not respond to #to_hash: #{other.pretty_inspect.chomp}")
113
+ end
114
+ self_respondingto_key = self.respond_to?(:key?) ? self : to_hash
115
+ other.to_hash.each_pair do |key, value|
116
+ if block_given? && self_respondingto_key.key?(key)
117
+ value = yield(key, self[key], value)
118
+ end
119
+ self[key] = value
120
+ end
121
+ self
122
+ end
123
+
124
+ alias_method :merge!, :update
125
+
126
+ # the same as Hash#merge
127
+ # @param other [#to_hash] the other hash to merge into this
128
+ # @yield [key, oldval, newval] for entries with duplicate keys, the value of each duplicate key
129
+ # is determined by calling the block with the key, its value in hsh and its value in other_hash.
130
+ # @return duplicate of this hash with the other hash merged in
131
+ # @raise [TypeError] when `other` does not respond to #to_hash
132
+ def merge(other, &block)
133
+ dup.update(other, &block)
134
+ end
135
+
108
136
  # @return [String] basically the same #inspect as Hash, but has the
109
137
  # class name and, if responsive, self's #object_group_text
110
138
  def inspect
@@ -168,7 +196,7 @@ module JSI
168
196
  end
169
197
  safe_modified_copy_methods.each do |method_name|
170
198
  define_method(method_name) do |*a, &b|
171
- JSI::Typelike.modified_copy(self) do |object_to_modify|
199
+ modified_copy do |object_to_modify|
172
200
  responsive_object = object_to_modify.respond_to?(method_name) ? object_to_modify : object_to_modify.to_ary
173
201
  responsive_object.public_send(method_name, *a, &b)
174
202
  end
@@ -176,7 +204,7 @@ module JSI
176
204
  end
177
205
  safe_el_block_methods.each do |method_name|
178
206
  define_method(method_name) do |*a, &b|
179
- JSI::Typelike.modified_copy(self) do |object_to_modify|
207
+ modified_copy do |object_to_modify|
180
208
  i = 0
181
209
  responsive_object = object_to_modify.respond_to?(method_name) ? object_to_modify : object_to_modify.to_ary
182
210
  responsive_object.public_send(method_name, *a) do |_e|