jsi 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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|