scorpio 0.2.3 → 0.3.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.
@@ -1,6 +1,5 @@
1
1
  require 'addressable/template'
2
2
  require 'faraday'
3
- require 'scorpio/util/faraday/response_media_type'
4
3
 
5
4
  module Scorpio
6
5
  # see also Faraday::Env::MethodsWithBodies
@@ -10,6 +9,9 @@ module Scorpio
10
9
 
11
10
  class ResourceBase
12
11
  class << self
12
+ # a hash of accessor names (Symbol) to default getter methods (UnboundMethod), used to determine
13
+ # what accessors have been overridden from their defaults.
14
+ (-> (x) { define_method(:inheritable_accessor_defaults) { x } }).({})
13
15
  def define_inheritable_accessor(accessor, options = {})
14
16
  if options[:default_getter]
15
17
  # the value before the field is set (overwritten) is the result of the default_getter proc
@@ -19,6 +21,7 @@ module Scorpio
19
21
  default_value = options[:default_value]
20
22
  define_singleton_method(accessor) { default_value }
21
23
  end
24
+ inheritable_accessor_defaults[accessor] = self.singleton_class.instance_method(accessor)
22
25
  # field setter method. redefines the getter, replacing the method with one that returns the
23
26
  # setter's argument (that being inherited to the scope of the define_method(accessor) block
24
27
  define_singleton_method(:"#{accessor}=") do |value|
@@ -40,80 +43,76 @@ module Scorpio
40
43
  end
41
44
  end
42
45
  end
43
- # the class on which the openapi document is defined. subclasses use the openapi document set on this class
44
- # (except in the unlikely event it is overwritten by a subclass)
45
- define_inheritable_accessor(:openapi_document_class)
46
- # the openapi document
47
- define_inheritable_accessor(:tag_name, on_set: -> { update_dynamic_methods })
48
46
  define_inheritable_accessor(:represented_schemas, default_value: [], on_set: proc do
49
47
  unless represented_schemas.respond_to?(:to_ary)
50
48
  raise(TypeError, "represented_schemas must be an array. received: #{represented_schemas.pretty_inspect.chomp}")
51
49
  end
52
- if represented_schemas.all? { |s| s.is_a?(Scorpio::Schema) }
50
+ if represented_schemas.all? { |s| s.is_a?(JSI::Schema) }
53
51
  represented_schemas.each do |schema|
54
52
  openapi_document_class.models_by_schema = openapi_document_class.models_by_schema.merge(schema => self)
55
53
  end
56
54
  update_dynamic_methods
57
55
  else
58
56
  self.represented_schemas = self.represented_schemas.map do |schema|
59
- unless schema.is_a?(Scorpio::Schema)
60
- schema = Scorpio::Schema.new(schema)
61
- end
62
- unless schema['type'].nil? || schema.describes_hash?
63
- raise(TypeError, "given schema for #{self.inspect} not of type object - type must be object for Scorpio ResourceBase to represent this schema. schema is: #{schema.pretty_inspect.chomp}")
57
+ unless schema.is_a?(JSI::Schema)
58
+ schema = JSI::Schema.new(schema)
64
59
  end
65
60
  schema
66
61
  end
67
62
  end
68
63
  end)
69
64
  define_inheritable_accessor(:models_by_schema, default_value: {})
70
- # the base url to which paths are appended.
71
- # by default this looks at the openapi document's schemes, picking https or http first.
72
- # it looks at the openapi_document's host and basePath.
73
65
  # a model overriding this MUST include the openapi document's basePath if defined, e.g.
74
66
  # class MyModel
75
67
  # self.base_url = File.join('https://example.com/', openapi_document.basePath)
76
68
  # end
77
69
  define_inheritable_accessor(:base_url, default_getter: -> {
78
- if openapi_document.schemes.nil?
79
- scheme = 'https'
80
- elsif openapi_document.schemes.respond_to?(:to_ary)
81
- # prefer https, then http, then anything else since we probably don't support.
82
- scheme = openapi_document.schemes.sort_by { |s| ['https', 'http'].index(s) || (1.0 / 0) }.first
83
- end
84
- if openapi_document.host && scheme
85
- Addressable::URI.new(
86
- scheme: scheme,
87
- host: openapi_document.host,
88
- path: openapi_document.basePath,
89
- ).to_s
70
+ openapi_document.base_url(server: server, server_variables: server_variables)
71
+ })
72
+
73
+ define_inheritable_accessor(:server_variables, default_value: {}, on_set: -> {
74
+ if openapi_document && openapi_document.v2?
75
+ raise(ArgumentError, "server variables are not supported for OpenAPI V2")
90
76
  end
91
77
  })
92
78
 
93
- define_inheritable_accessor(:user_agent, default_getter: -> {
94
- "Scorpio/#{Scorpio::VERSION} (https://github.com/notEthan/scorpio) Faraday/#{Faraday::VERSION} Ruby/#{RUBY_VERSION}"
79
+ define_inheritable_accessor(:server, on_set: -> {
80
+ if openapi_document && openapi_document.v2?
81
+ raise(ArgumentError, "servers are not supported for OpenAPI V2")
82
+ end
83
+ unless server.is_a?(Scorpio::OpenAPI::V3::Server)
84
+ raise(TypeError, "server must be an #{Scorpio::OpenAPI::V3::Server.inspect}. received: #{server.pretty_inspect.chomp}")
85
+ end
95
86
  })
96
- define_inheritable_accessor(:faraday_request_middleware, default_value: [])
97
- define_inheritable_accessor(:faraday_adapter, default_getter: proc { Faraday.default_adapter })
98
- define_inheritable_accessor(:faraday_response_middleware, default_value: [])
87
+
88
+ define_inheritable_accessor(:user_agent, default_getter: -> { openapi_document.user_agent })
89
+
90
+ define_inheritable_accessor(:faraday_builder, default_getter: -> { openapi_document.faraday_builder })
91
+ define_inheritable_accessor(:faraday_adapter, default_getter: -> { openapi_document.faraday_adapter })
99
92
  class << self
93
+ # the openapi document
100
94
  def openapi_document
101
95
  nil
102
96
  end
97
+ def openapi_document_class
98
+ nil
99
+ end
103
100
 
104
101
  def openapi_document=(openapi_document)
105
- self.openapi_document_class = self
106
-
107
- if openapi_document.is_a?(Hash)
108
- openapi_document = OpenAPI::V2::Document.new(openapi_document)
109
- end
102
+ openapi_document = OpenAPI::Document.from_instance(openapi_document)
110
103
 
111
104
  begin
112
105
  singleton_class.instance_exec { remove_method(:openapi_document) }
113
106
  rescue NameError
114
107
  end
108
+ begin
109
+ singleton_class.instance_exec { remove_method(:openapi_document_class) }
110
+ rescue NameError
111
+ end
112
+ openapi_document_class = self
115
113
  define_singleton_method(:openapi_document) { openapi_document }
116
- define_singleton_method(:openapi_document=) do
114
+ define_singleton_method(:openapi_document_class) { openapi_document_class }
115
+ define_singleton_method(:openapi_document=) do |_|
117
116
  if self == openapi_document_class
118
117
  raise(ArgumentError, "openapi_document may only be set once on #{self.inspect}")
119
118
  else
@@ -124,15 +123,36 @@ module Scorpio
124
123
 
125
124
  openapi_document.paths.each do |path, path_item|
126
125
  path_item.each do |http_method, operation|
127
- next if http_method == 'parameters' # parameters is not an operation. TOOD maybe just select the keys that are http methods?
128
- unless operation.is_a?(Scorpio::OpenAPI::V2::Operation)
129
- raise("bad operation at #{operation.fragment}: #{operation.pretty_inspect}")
126
+ unless operation.is_a?(Scorpio::OpenAPI::Operation)
127
+ next
130
128
  end
131
129
  end
132
130
  end
133
131
 
134
- openapi_document.validate!
132
+ # TODO blame validate openapi_document
133
+
134
+ update_dynamic_methods
135
+ end
136
+
137
+ def tag_name
138
+ nil
139
+ end
135
140
 
141
+ def tag_name=(tag_name)
142
+ unless tag_name.respond_to?(:to_str)
143
+ raise(TypeError)
144
+ end
145
+ set_on_class = self
146
+ tag_name = tag_name.to_str
147
+
148
+ begin
149
+ singleton_class.instance_exec { remove_method(:tag_name) }
150
+ rescue NameError
151
+ end
152
+ define_singleton_method(:tag_name) { tag_name }
153
+ define_singleton_method(:tag_name=) do |_|
154
+ raise(ArgumentError, "tag_name may not be overridden. it is been set to #{tag_name.inspect}")
155
+ end
136
156
  update_dynamic_methods
137
157
  end
138
158
 
@@ -142,7 +162,7 @@ module Scorpio
142
162
  end
143
163
 
144
164
  def all_schema_properties
145
- represented_schemas.map(&:described_hash_property_names).inject(Set.new, &:|)
165
+ represented_schemas.map(&:described_object_property_names).inject(Set.new, &:|)
146
166
  end
147
167
 
148
168
  def update_instance_accessors
@@ -165,7 +185,7 @@ module Scorpio
165
185
 
166
186
  return true if operation.tags.respond_to?(:to_ary) && operation.tags.include?(tag_name)
167
187
 
168
- if operation.request_schema && represented_schemas.include?(operation.request_schema)
188
+ if (operation.request_schemas || []).any? { |s| represented_schemas.include?(s) }
169
189
  return true
170
190
  end
171
191
 
@@ -192,7 +212,7 @@ module Scorpio
192
212
  # should we define an instance method?
193
213
  #request_attributes |= method_desc['parameters'] ? method_desc['parameters'].keys : []
194
214
 
195
- schema_attributes = represented_schemas.map(&:described_hash_property_names).inject(Set.new, &:|)
215
+ schema_attributes = represented_schemas.map(&:described_object_property_names).inject(Set.new, &:|)
196
216
 
197
217
  return request_resource_is_self || (request_attributes & schema_attributes.to_a).any?
198
218
  end
@@ -200,7 +220,7 @@ module Scorpio
200
220
  def method_names_by_operation
201
221
  @method_names_by_operation ||= Hash.new do |h, operation|
202
222
  h[operation] = begin
203
- raise(ArgumentError, operation.pretty_inspect) unless operation.is_a?(Scorpio::OpenAPI::V2::Operation)
223
+ raise(ArgumentError, operation.pretty_inspect) unless operation.is_a?(Scorpio::OpenAPI::Operation)
204
224
 
205
225
  if operation.tags.respond_to?(:to_ary) && operation.tags.include?(tag_name) && operation.operationId =~ /\A#{Regexp.escape(tag_name)}\.(\w+)\z/
206
226
  method_name = $1
@@ -216,82 +236,95 @@ module Scorpio
216
236
  path_item.each do |http_method, operation|
217
237
  next if http_method == 'parameters' # parameters is not an operation. TOOD maybe just select the keys that are http methods?
218
238
  method_name = method_names_by_operation[operation]
219
- # class method
220
- if operation_for_resource_class?(operation) && !respond_to?(method_name)
221
- define_singleton_method(method_name) do |call_params = nil|
222
- call_operation(operation, call_params: call_params)
239
+ if method_name
240
+ # class method
241
+ if operation_for_resource_class?(operation) && !respond_to?(method_name)
242
+ define_singleton_method(method_name) do |call_params = nil|
243
+ call_operation(operation, call_params: call_params)
244
+ end
223
245
  end
224
- end
225
246
 
226
- # instance method
227
- if operation_for_resource_instance?(operation) && !method_defined?(method_name)
228
- define_method(method_name) do |call_params = nil|
229
- call_operation(operation, call_params: call_params)
247
+ # instance method
248
+ if operation_for_resource_instance?(operation) && !method_defined?(method_name)
249
+ define_method(method_name) do |call_params = nil|
250
+ call_operation(operation, call_params: call_params)
251
+ end
230
252
  end
231
253
  end
232
254
  end
233
255
  end
234
256
  end
235
257
 
236
- def connection
237
- Faraday.new(:headers => {'User-Agent' => user_agent}) do |c|
238
- faraday_request_middleware.each do |m|
239
- c.request(*m)
240
- end
241
- faraday_response_middleware.each do |m|
242
- c.response(*m)
243
- end
244
- c.adapter(*faraday_adapter)
245
- end
246
- end
247
-
248
258
  def call_operation(operation, call_params: nil, model_attributes: nil)
249
- call_params = Scorpio.stringify_symbol_keys(call_params) if call_params.is_a?(Hash)
250
- model_attributes = Scorpio.stringify_symbol_keys(model_attributes || {})
251
- http_method = operation.http_method.downcase.to_sym
252
- path_template = Addressable::Template.new(operation.path)
253
- template_params = model_attributes
254
- template_params = template_params.merge(call_params) if call_params.is_a?(Hash)
255
- missing_variables = path_template.variables - template_params.keys
256
- if missing_variables.any?
257
- raise(ArgumentError, "path #{operation.path} for operation #{operation.operationId} requires attributes " +
258
- "which were missing: #{missing_variables.inspect}")
259
- end
260
- empty_variables = path_template.variables.select { |v| template_params[v].to_s.empty? }
261
- if empty_variables.any?
262
- raise(ArgumentError, "path #{operation.path} for operation #{operation.operationId} requires attributes " +
263
- "which were empty: #{empty_variables.inspect}")
259
+ call_params = JSI.stringify_symbol_keys(call_params) if call_params.is_a?(Hash)
260
+ model_attributes = JSI.stringify_symbol_keys(model_attributes || {})
261
+
262
+ request = Scorpio::Request.new(operation)
263
+
264
+ accessor_overridden = -> (accessor) do
265
+ # an accessor is overridden if the default accessor getter (UnboundMethod) is the same
266
+ # as the UnboundMethod returned from instance_method on the owner of that instance method.
267
+ # gotta be the owner since different classes return different UnboundMethod instances for
268
+ # the same method. for example, referring to models of scorpio/test/blog_scorpio_models.rb
269
+ # with the server_variables instance method:
270
+ # Article.instance_method(:server_variables)
271
+ # => #<UnboundMethod: #<Class:Article>#server_variables>
272
+ # returns a different UnboundMethod than
273
+ # Scorpio::ResourceBase.instance_method(:server_variables)
274
+ # => #<UnboundMethod: #<Class:Scorpio::ResourceBase>#server_variables>
275
+ # even though they are really the same method (the #owner for both is Scorpio::ResourceBase)
276
+ inheritable_accessor_defaults[accessor] != self.singleton_class.instance_method(accessor).owner.instance_method(accessor)
264
277
  end
265
- path = path_template.expand(template_params)
266
- # we do not use Addressable::URI#join as the paths should just be concatenated, not resolved.
267
- # we use File.join just to deal with consecutive slashes.
268
- url = File.join(base_url, path)
269
- url = Addressable::URI.parse(url)
278
+
279
+ # pretty ugly... may find a better way to do this.
280
+ request.base_url = self.base_url if accessor_overridden.(:base_url)
281
+ request.server_variables = self.server_variables if accessor_overridden.(:server_variables)
282
+ request.server = self.server if accessor_overridden.(:server)
283
+ request.user_agent = self.user_agent if accessor_overridden.(:user_agent)
284
+ request.faraday_builder = self.faraday_builder if accessor_overridden.(:faraday_builder)
285
+ request.faraday_adapter = self.faraday_adapter if accessor_overridden.(:faraday_adapter)
286
+
287
+ request.path_params = request.path_template.variables.map do |var|
288
+ if call_params.respond_to?(:to_hash) && call_params.key?(var)
289
+ {var => call_params[var]}
290
+ elsif model_attributes.respond_to?(:to_hash) && model_attributes.key?(var)
291
+ {var => model_attributes[var]}
292
+ else
293
+ {}
294
+ end
295
+ end.inject({}, &:update)
296
+
270
297
  # assume that call_params must be included somewhere. model_attributes are a source of required things
271
298
  # but not required to be here.
272
- other_params = call_params
273
- if other_params.is_a?(Hash)
274
- other_params.reject! { |k, _| path_template.variables.include?(k) }
299
+ if call_params.respond_to?(:to_hash)
300
+ unused_call_params = call_params.reject { |k, _| request.path_template.variables.include?(k) }
301
+ if !unused_call_params.empty?
302
+ other_params = unused_call_params
303
+ else
304
+ other_params = nil
305
+ end
306
+ else
307
+ other_params = call_params
275
308
  end
276
309
 
277
310
  if operation.request_schema
278
311
  # TODO deal with model_attributes / call_params better in nested whatever
279
312
  if call_params.nil?
280
- body = request_body_for_schema(model_attributes, operation.request_schema)
313
+ request.body_object = request_body_for_schema(model_attributes, operation.request_schema)
281
314
  elsif call_params.is_a?(Hash)
282
315
  body = request_body_for_schema(model_attributes.merge(call_params), operation.request_schema)
283
- body = body.merge(call_params) # TODO
316
+ request.body_object = body.merge(call_params) # TODO
284
317
  else
285
- body = call_params
318
+ request.body_object = call_params
286
319
  end
287
320
  else
288
321
  if other_params
289
- if METHODS_WITH_BODIES.any? { |m| m.to_s == http_method.downcase.to_s }
290
- body = other_params
322
+ if METHODS_WITH_BODIES.any? { |m| m.to_s == operation.http_method.downcase.to_s }
323
+ request.body_object = other_params
291
324
  else
292
325
  if other_params.is_a?(Hash)
293
326
  # TODO pay more attention to 'parameters' api method attribute
294
- url.query_values = other_params
327
+ request.query_params = other_params
295
328
  else
296
329
  raise
297
330
  end
@@ -299,91 +332,25 @@ module Scorpio
299
332
  end
300
333
  end
301
334
 
302
- request_headers = {}
303
-
304
- if METHODS_WITH_BODIES.any? { |m| m.to_s == http_method.downcase.to_s } && body != nil
305
- consumes = operation.consumes || openapi_document.consumes || []
306
- if consumes.include?("application/json") || (!body.respond_to?(:to_str) && consumes.empty?)
307
- # if we have a body that's not a string and no indication of how to serialize it, we guess json.
308
- request_headers['Content-Type'] = "application/json"
309
- unless body.respond_to?(:to_str)
310
- body = ::JSON.pretty_generate(Typelike.as_json(body))
311
- end
312
- elsif consumes.include?("application/x-www-form-urlencoded")
313
- request_headers['Content-Type'] = "application/x-www-form-urlencoded"
314
- unless body.respond_to?(:to_str)
315
- body = URI.encode_www_form(body)
316
- end
317
- elsif body.is_a?(String)
318
- if consumes.size == 1
319
- request_headers['Content-Type'] = consumes.first
320
- end
321
- else
322
- raise("do not know how to serialize for #{consumes.inspect}: #{body.pretty_inspect.chomp}")
323
- end
324
- end
335
+ ur = request.run_ur
325
336
 
326
- response = connection.run_request(http_method, url, body, request_headers)
327
-
328
- if response.media_type == 'application/json'
329
- if response.body.empty?
330
- response_object = nil
331
- else
332
- begin
333
- response_object = ::JSON.parse(response.body)
334
- rescue ::JSON::ParserError
335
- # TODO warn
336
- response_object = response.body
337
- end
338
- end
339
- else
340
- response_object = response.body
341
- end
342
-
343
- if operation.responses
344
- _, operation_response = operation.responses.detect { |k, v| k.to_s == response.status.to_s }
345
- operation_response ||= operation.responses['default']
346
- response_schema = operation_response['schema'] if operation_response
347
- end
348
- if response_schema
349
- # not too sure about this, but I don't think it makes sense to instantiate things that are
350
- # not hash or array as a SchemaInstanceBase
351
- if response_object.respond_to?(:to_hash) || response_object.respond_to?(:to_ary)
352
- response_object = Scorpio.class_for_schema(response_schema).new(response_object)
353
- end
354
- end
355
-
356
- error_class = Scorpio.error_classes_by_status[response.status]
357
- error_class ||= if (400..499).include?(response.status)
358
- ClientError
359
- elsif (500..599).include?(response.status)
360
- ServerError
361
- elsif !response.success?
362
- HTTPError
363
- end
364
- if error_class
365
- message = "Error calling operation #{operation.operationId} on #{self}:\n" + (response.env[:raw_body] || response.env.body)
366
- raise(error_class.new(message).tap do |e|
367
- e.faraday_response = response
368
- e.response_object = response_object
369
- end)
370
- end
337
+ ur.raise_on_http_error
371
338
 
372
339
  initialize_options = {
373
340
  'persisted' => true,
374
- 'source' => {'operationId' => operation.operationId, 'call_params' => call_params, 'url' => url.to_s},
375
- 'response' => response,
341
+ 'source' => {'operationId' => operation.operationId, 'call_params' => call_params, 'url' => ur.request.uri.to_s},
342
+ 'ur' => ur,
376
343
  }
377
- response_object_to_instances(response_object, initialize_options)
344
+ response_object_to_instances(ur.response.body_object, initialize_options)
378
345
  end
379
346
 
380
347
  def request_body_for_schema(object, schema)
381
348
  if object.is_a?(Scorpio::ResourceBase)
382
349
  # TODO request_schema_fail unless schema is for given model type
383
350
  request_body_for_schema(object.attributes, schema)
384
- elsif object.is_a?(Scorpio::SchemaInstanceBase)
351
+ elsif object.is_a?(JSI::Base)
385
352
  request_body_for_schema(object.instance, schema)
386
- elsif object.is_a?(Scorpio::JSON::Node)
353
+ elsif object.is_a?(JSI::JSON::Node)
387
354
  request_body_for_schema(object.content, schema)
388
355
  else
389
356
  if object.is_a?(Hash)
@@ -436,7 +403,7 @@ module Scorpio
436
403
  if schema['type'] == 'array'
437
404
  # TODO index based subschema or whatever else works for array
438
405
  subschema = schema['items']
439
- else
406
+ elsif schema['type']
440
407
  request_schema_fail(object, schema)
441
408
  end
442
409
  end
@@ -451,16 +418,16 @@ module Scorpio
451
418
  end
452
419
 
453
420
  def request_schema_fail(object, schema)
454
- raise(RequestSchemaFailure, "object does not conform to schema.\nobject = #{object.pretty_inspect}\nschema = #{::JSON.pretty_generate(schema, quirks_mode: true)}")
421
+ # TODO blame
455
422
  end
456
423
 
457
424
  def response_object_to_instances(object, initialize_options = {})
458
- if object.is_a?(SchemaInstanceBase)
425
+ if object.is_a?(JSI::Base)
459
426
  model = models_by_schema[object.schema]
460
427
  end
461
428
 
462
429
  if object.respond_to?(:to_hash)
463
- out = Typelike.modified_copy(object) do
430
+ out = JSI::Typelike.modified_copy(object) do
464
431
  object.map do |key, value|
465
432
  {key => response_object_to_instances(value, initialize_options)}
466
433
  end.inject({}, &:update)
@@ -471,7 +438,7 @@ module Scorpio
471
438
  out
472
439
  end
473
440
  elsif object.respond_to?(:to_ary)
474
- Typelike.modified_copy(object) do
441
+ JSI::Typelike.modified_copy(object) do
475
442
  object.map do |element|
476
443
  response_object_to_instances(element, initialize_options)
477
444
  end
@@ -483,8 +450,8 @@ module Scorpio
483
450
  end
484
451
 
485
452
  def initialize(attributes = {}, options = {})
486
- @attributes = Scorpio.stringify_symbol_keys(attributes)
487
- @options = Scorpio.stringify_symbol_keys(options)
453
+ @attributes = JSI.stringify_symbol_keys(attributes)
454
+ @options = JSI.stringify_symbol_keys(options)
488
455
  @persisted = !!@options['persisted']
489
456
  end
490
457
 
@@ -514,10 +481,9 @@ module Scorpio
514
481
  # if we're making a POST or PUT and the request schema is this resource, we'll assume that
515
482
  # the request is persisting this resource
516
483
  request_resource_is_self = operation.request_schema && self.class.represented_schemas.include?(operation.request_schema)
517
- if @options['response'] && @options['response'].status && operation.responses
518
- _, response_schema_node = operation.responses.detect { |k, v| k.to_s == @options['response'].status.to_s }
484
+ if @options['ur'].is_a?(Scorpio::Ur)
485
+ response_schema = @options['ur'].response.response_schema
519
486
  end
520
- response_schema = Scorpio::Schema.new(response_schema_node) if response_schema_node
521
487
  response_resource_is_self = response_schema && self.class.represented_schemas.include?(response_schema)
522
488
  if request_resource_is_self && %w(put post).include?(operation.http_method.to_s.downcase)
523
489
  @persisted = true
@@ -531,7 +497,7 @@ module Scorpio
531
497
  end
532
498
 
533
499
  def as_json(*opt)
534
- Typelike.as_json(@attributes, *opt)
500
+ JSI::Typelike.as_json(@attributes, *opt)
535
501
  end
536
502
 
537
503
  def inspect
@@ -552,8 +518,8 @@ module Scorpio
552
518
  end
553
519
 
554
520
  def fingerprint
555
- {class: self.class, attributes: Typelike.as_json(@attributes)}
521
+ {class: self.class, attributes: JSI::Typelike.as_json(@attributes)}
556
522
  end
557
- include FingerprintHash
523
+ include JSI::FingerprintHash
558
524
  end
559
525
  end