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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +4 -2
- data/lib/scorpio.rb +9 -22
- data/lib/scorpio/google_api_document.rb +13 -16
- data/lib/scorpio/openapi.rb +141 -143
- data/lib/scorpio/openapi/document.rb +167 -0
- data/lib/scorpio/openapi/operation.rb +208 -0
- data/lib/scorpio/openapi/operations_scope.rb +29 -0
- data/lib/scorpio/openapi/v3/server.rb +32 -0
- data/lib/scorpio/request.rb +227 -0
- data/lib/scorpio/resource_base.rb +148 -182
- data/lib/scorpio/response.rb +34 -0
- data/lib/scorpio/ur.rb +33 -0
- data/lib/scorpio/version.rb +1 -1
- data/scorpio.gemspec +3 -4
- metadata +32 -36
- data/lib/scorpio/json-schema-fragments.rb +0 -191
- data/lib/scorpio/json.rb +0 -5
- data/lib/scorpio/json/node.rb +0 -256
- data/lib/scorpio/schema.rb +0 -249
- data/lib/scorpio/schema_instance_base.rb +0 -325
- data/lib/scorpio/schema_instance_base/to_rb.rb +0 -127
- data/lib/scorpio/schema_instance_json_coder.rb +0 -83
- data/lib/scorpio/struct_json_coder.rb +0 -30
- data/lib/scorpio/typelike_modules.rb +0 -164
- data/lib/scorpio/util.rb +0 -89
- data/lib/scorpio/util/faraday/response_media_type.rb +0 -15
data/lib/scorpio/schema.rb
DELETED
@@ -1,249 +0,0 @@
|
|
1
|
-
require 'scorpio/json/node'
|
2
|
-
|
3
|
-
module Scorpio
|
4
|
-
class Schema
|
5
|
-
include Memoize
|
6
|
-
|
7
|
-
def initialize(schema_object)
|
8
|
-
if schema_object.is_a?(Scorpio::Schema)
|
9
|
-
raise(TypeError, "will not instantiate Schema from another Schema: #{schema_object.pretty_inspect.chomp}")
|
10
|
-
elsif schema_object.is_a?(Scorpio::SchemaInstanceBase)
|
11
|
-
@schema_object = Scorpio.deep_stringify_symbol_keys(schema_object.deref)
|
12
|
-
@schema_node = @schema_object.instance
|
13
|
-
elsif schema_object.is_a?(Scorpio::JSON::HashNode)
|
14
|
-
@schema_object = nil
|
15
|
-
@schema_node = Scorpio.deep_stringify_symbol_keys(schema_object.deref)
|
16
|
-
elsif schema_object.respond_to?(:to_hash)
|
17
|
-
@schema_object = nil
|
18
|
-
@schema_node = Scorpio::JSON::Node.new_by_type(Scorpio.deep_stringify_symbol_keys(schema_object), [])
|
19
|
-
else
|
20
|
-
raise(TypeError, "cannot instantiate Schema from: #{schema_object.pretty_inspect.chomp}")
|
21
|
-
end
|
22
|
-
if @schema_object
|
23
|
-
define_singleton_method(:instance) { schema_node } # aka schema_object.instance
|
24
|
-
define_singleton_method(:schema) { schema_object.schema }
|
25
|
-
extend SchemaInstanceBaseHash
|
26
|
-
else
|
27
|
-
define_singleton_method(:[]) { |*a, &b| schema_node.public_send(:[], *a, &b) }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
attr_reader :schema_node
|
31
|
-
def schema_object
|
32
|
-
@schema_object || @schema_node
|
33
|
-
end
|
34
|
-
|
35
|
-
def schema_id
|
36
|
-
@schema_id ||= begin
|
37
|
-
# start from schema_node and ascend parents looking for an 'id' property.
|
38
|
-
# append a fragment to that id (appending to an existing fragment if there
|
39
|
-
# is one) consisting of the path from that parent to our schema_node.
|
40
|
-
node_for_id = schema_node
|
41
|
-
path_from_id_node = []
|
42
|
-
done = false
|
43
|
-
|
44
|
-
while !done
|
45
|
-
# TODO: track what parents are schemas. somehow.
|
46
|
-
# look at 'id' if node_for_id is a schema, or the document root.
|
47
|
-
# decide whether to look at '$id' for all parent nodes or also just schemas.
|
48
|
-
if node_for_id.respond_to?(:to_hash)
|
49
|
-
if node_for_id.path.empty? || node_for_id.object_id == schema_node.object_id
|
50
|
-
# I'm only looking at 'id' for the document root and the schema node
|
51
|
-
# until I track what parents are schemas.
|
52
|
-
parent_id = node_for_id['$id'] || node_for_id['id']
|
53
|
-
else
|
54
|
-
# will look at '$id' everywhere since it is less likely to show up outside schemas than
|
55
|
-
# 'id', but it will be better to only look at parents that are schemas for this too.
|
56
|
-
parent_id = node_for_id['$id']
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
if parent_id || node_for_id.path.empty?
|
61
|
-
done = true
|
62
|
-
else
|
63
|
-
path_from_id_node.unshift(node_for_id.path.last)
|
64
|
-
node_for_id = node_for_id.parent_node
|
65
|
-
end
|
66
|
-
end
|
67
|
-
if parent_id
|
68
|
-
parent_auri = Addressable::URI.parse(parent_id)
|
69
|
-
else
|
70
|
-
node_for_id = schema_node.document_node
|
71
|
-
validator = ::JSON::Validator.new(node_for_id.content, nil)
|
72
|
-
# TODO not good instance_exec'ing into another library's ivars
|
73
|
-
parent_auri = validator.instance_exec { @base_schema }.uri
|
74
|
-
end
|
75
|
-
if parent_auri.fragment
|
76
|
-
# add onto the fragment
|
77
|
-
parent_id_path = ::JSON::Schema::Pointer.new(:fragment, '#' + parent_auri.fragment).reference_tokens
|
78
|
-
path_from_id_node = parent_id_path + path_from_id_node
|
79
|
-
parent_auri.fragment = nil
|
80
|
-
#else: no fragment so parent_id good as is
|
81
|
-
end
|
82
|
-
|
83
|
-
fragment = ::JSON::Schema::Pointer.new(:reference_tokens, path_from_id_node).fragment
|
84
|
-
schema_id = parent_auri.to_s + fragment
|
85
|
-
|
86
|
-
schema_id
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def schema_class
|
91
|
-
Scorpio.class_for_schema(self)
|
92
|
-
end
|
93
|
-
|
94
|
-
def match_to_instance(instance)
|
95
|
-
# matching oneOf is good here. one schema for one instance.
|
96
|
-
# matching anyOf is okay. there could be more than one schema matched. it's often just one. if more
|
97
|
-
# than one is a match, the problems of allOf occur.
|
98
|
-
# matching allOf is questionable. all of the schemas must be matched but we just return the first match.
|
99
|
-
# there isn't really a better answer with the current implementation. merging the schemas together
|
100
|
-
# is a thought but is not practical.
|
101
|
-
%w(oneOf allOf anyOf).select { |k| schema_node[k].respond_to?(:to_ary) }.each do |someof_key|
|
102
|
-
schema_node[someof_key].map(&:deref).map do |someof_node|
|
103
|
-
someof_schema = self.class.new(someof_node)
|
104
|
-
if someof_schema.validate(instance)
|
105
|
-
return someof_schema.match_to_instance(instance)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
return self
|
110
|
-
end
|
111
|
-
|
112
|
-
def subschema_for_property(property_name_)
|
113
|
-
memoize(:subschema_for_property, property_name_) do |property_name|
|
114
|
-
if schema_object['properties'].respond_to?(:to_hash) && schema_object['properties'][property_name].respond_to?(:to_hash)
|
115
|
-
self.class.new(schema_object['properties'][property_name])
|
116
|
-
else
|
117
|
-
if schema_object['patternProperties'].respond_to?(:to_hash)
|
118
|
-
_, pattern_schema_object = schema_object['patternProperties'].detect do |pattern, _|
|
119
|
-
property_name.to_s =~ Regexp.new(pattern) # TODO map pattern to ruby syntax
|
120
|
-
end
|
121
|
-
end
|
122
|
-
if pattern_schema_object
|
123
|
-
self.class.new(pattern_schema_object)
|
124
|
-
else
|
125
|
-
if schema_object['additionalProperties'].respond_to?(:to_hash)
|
126
|
-
self.class.new(schema_object['additionalProperties'])
|
127
|
-
else
|
128
|
-
nil
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def subschema_for_index(index_)
|
136
|
-
memoize(:subschema_for_index, index_) do |index|
|
137
|
-
if schema_object['items'].respond_to?(:to_ary)
|
138
|
-
if index < schema_object['items'].size
|
139
|
-
self.class.new(schema_object['items'][index])
|
140
|
-
elsif schema_object['additionalItems'].respond_to?(:to_hash)
|
141
|
-
self.class.new(schema_object['additionalItems'])
|
142
|
-
end
|
143
|
-
elsif schema_object['items'].respond_to?(:to_hash)
|
144
|
-
self.class.new(schema_object['items'])
|
145
|
-
else
|
146
|
-
nil
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
def describes_array?
|
152
|
-
memoize(:describes_array?) do
|
153
|
-
schema_node['type'] == 'array' ||
|
154
|
-
schema_node['items'] ||
|
155
|
-
schema_node['additionalItems'] ||
|
156
|
-
schema_node['default'].respond_to?(:to_ary) || # TODO make sure this is right
|
157
|
-
(schema_node['enum'].respond_to?(:to_ary) && schema_node['enum'].all? { |enum| enum.respond_to?(:to_ary) }) ||
|
158
|
-
schema_node['maxItems'] ||
|
159
|
-
schema_node['minItems'] ||
|
160
|
-
schema_node.key?('uniqueItems') ||
|
161
|
-
schema_node['oneOf'].respond_to?(:to_ary) &&
|
162
|
-
schema_node['oneOf'].all? { |someof_node| self.class.new(someof_node).describes_array? } ||
|
163
|
-
schema_node['allOf'].respond_to?(:to_ary) &&
|
164
|
-
schema_node['allOf'].all? { |someof_node| self.class.new(someof_node).describes_array? } ||
|
165
|
-
schema_node['anyOf'].respond_to?(:to_ary) &&
|
166
|
-
schema_node['anyOf'].all? { |someof_node| self.class.new(someof_node).describes_array? }
|
167
|
-
end
|
168
|
-
end
|
169
|
-
def describes_hash?
|
170
|
-
memoize(:describes_hash?) do
|
171
|
-
schema_node['type'] == 'object' ||
|
172
|
-
schema_node['required'].respond_to?(:to_ary) ||
|
173
|
-
schema_node['properties'].respond_to?(:to_hash) ||
|
174
|
-
schema_node['additionalProperties'] ||
|
175
|
-
schema_node['patternProperties'] ||
|
176
|
-
schema_node['default'].respond_to?(:to_hash) ||
|
177
|
-
(schema_node['enum'].respond_to?(:to_ary) && schema_node['enum'].all? { |enum| enum.respond_to?(:to_hash) }) ||
|
178
|
-
schema_node['oneOf'].respond_to?(:to_ary) &&
|
179
|
-
schema_node['oneOf'].all? { |someof_node| self.class.new(someof_node).describes_hash? } ||
|
180
|
-
schema_node['allOf'].respond_to?(:to_ary) &&
|
181
|
-
schema_node['allOf'].all? { |someof_node| self.class.new(someof_node).describes_hash? } ||
|
182
|
-
schema_node['anyOf'].respond_to?(:to_ary) &&
|
183
|
-
schema_node['anyOf'].all? { |someof_node| self.class.new(someof_node).describes_hash? }
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
def described_hash_property_names
|
188
|
-
memoize(:described_hash_property_names) do
|
189
|
-
Set.new.tap do |property_names|
|
190
|
-
if schema_node['properties'].respond_to?(:to_hash)
|
191
|
-
property_names.merge(schema_node['properties'].keys)
|
192
|
-
end
|
193
|
-
if schema_node['required'].respond_to?(:to_ary)
|
194
|
-
property_names.merge(schema_node['required'].to_ary)
|
195
|
-
end
|
196
|
-
# we _could_ look at the properties of 'default' and each 'enum' but ... nah.
|
197
|
-
# we should look at dependencies (TODO).
|
198
|
-
%w(oneOf allOf anyOf).select { |k| schema_node[k].respond_to?(:to_ary) }.each do |schemas_key|
|
199
|
-
schema_node[schemas_key].map(&:deref).map do |someof_node|
|
200
|
-
property_names.merge(self.class.new(someof_node).described_hash_property_names)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
def fully_validate(instance)
|
208
|
-
::JSON::Validator.fully_validate(schema_node.document, object_to_content(instance), fragment: schema_node.fragment)
|
209
|
-
end
|
210
|
-
def validate(instance)
|
211
|
-
::JSON::Validator.validate(schema_node.document, object_to_content(instance), fragment: schema_node.fragment)
|
212
|
-
end
|
213
|
-
def validate!(instance)
|
214
|
-
::JSON::Validator.validate!(schema_node.document, object_to_content(instance), fragment: schema_node.fragment)
|
215
|
-
end
|
216
|
-
|
217
|
-
def object_group_text
|
218
|
-
"schema_id=#{schema_id}"
|
219
|
-
end
|
220
|
-
def inspect
|
221
|
-
"\#<#{self.class.inspect} #{object_group_text} #{schema_object.inspect}>"
|
222
|
-
end
|
223
|
-
alias_method :to_s, :inspect
|
224
|
-
def pretty_print(q)
|
225
|
-
q.instance_exec(self) do |obj|
|
226
|
-
text "\#<#{obj.class.inspect} #{obj.object_group_text}"
|
227
|
-
group_sub {
|
228
|
-
nest(2) {
|
229
|
-
breakable ' '
|
230
|
-
pp obj.schema_object
|
231
|
-
}
|
232
|
-
}
|
233
|
-
breakable ''
|
234
|
-
text '>'
|
235
|
-
end
|
236
|
-
end
|
237
|
-
def fingerprint
|
238
|
-
{class: self.class, schema_node: schema_node}
|
239
|
-
end
|
240
|
-
include FingerprintHash
|
241
|
-
|
242
|
-
private
|
243
|
-
def object_to_content(object)
|
244
|
-
object = object.instance if object.is_a?(Scorpio::SchemaInstanceBase)
|
245
|
-
object = object.content if object.is_a?(Scorpio::JSON::Node)
|
246
|
-
object
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
@@ -1,325 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'scorpio/typelike_modules'
|
3
|
-
|
4
|
-
module Scorpio
|
5
|
-
# base class for representing an instance of an instance described by a schema
|
6
|
-
class SchemaInstanceBase
|
7
|
-
include Memoize
|
8
|
-
include Enumerable
|
9
|
-
|
10
|
-
class << self
|
11
|
-
def schema_id
|
12
|
-
schema.schema_id
|
13
|
-
end
|
14
|
-
|
15
|
-
def inspect
|
16
|
-
if !respond_to?(:schema)
|
17
|
-
super
|
18
|
-
elsif !name || name =~ /\AScorpio::SchemaClasses::/
|
19
|
-
%Q(#{SchemaClasses.inspect}[#{schema_id.inspect}])
|
20
|
-
else
|
21
|
-
%Q(#{name} (#{schema_id}))
|
22
|
-
end
|
23
|
-
end
|
24
|
-
def to_s
|
25
|
-
if !respond_to?(:schema)
|
26
|
-
super
|
27
|
-
elsif !name || name =~ /\AScorpio::SchemaClasses::/
|
28
|
-
%Q(#{SchemaClasses.inspect}[#{schema_id.inspect}])
|
29
|
-
else
|
30
|
-
name
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def schema_classes_const_name
|
35
|
-
name = schema.schema_id.gsub(/[^\w]/, '_')
|
36
|
-
name = 'X' + name unless name[/\A[a-zA-Z_]/]
|
37
|
-
name = name[0].upcase + name[1..-1]
|
38
|
-
name
|
39
|
-
end
|
40
|
-
|
41
|
-
def name
|
42
|
-
unless super
|
43
|
-
SchemaClasses.const_set(schema_classes_const_name, self)
|
44
|
-
end
|
45
|
-
super
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def initialize(instance, origin: nil)
|
50
|
-
unless respond_to?(:schema)
|
51
|
-
raise(TypeError, "cannot instantiate #{self.class.inspect} which has no method #schema. please use Scorpio.class_for_schema")
|
52
|
-
end
|
53
|
-
|
54
|
-
@origin = origin || self
|
55
|
-
self.instance = instance
|
56
|
-
|
57
|
-
if @instance.is_a?(Scorpio::JSON::HashNode)
|
58
|
-
extend SchemaInstanceBaseHash
|
59
|
-
elsif @instance.is_a?(Scorpio::JSON::ArrayNode)
|
60
|
-
extend SchemaInstanceBaseArray
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
attr_reader :instance
|
65
|
-
|
66
|
-
# each is overridden by SchemaInstanceBaseHash or SchemaInstanceBaseArray when appropriate. the base
|
67
|
-
# #each is not actually implemented, along with all the methods of Enumerable.
|
68
|
-
def each
|
69
|
-
raise NoMethodError, "Enumerable methods and #each not implemented for instance that is not like a hash or array: #{instance.pretty_inspect.chomp}"
|
70
|
-
end
|
71
|
-
|
72
|
-
def parents
|
73
|
-
parent = @origin
|
74
|
-
(@origin.instance.path.size...self.instance.path.size).map do |i|
|
75
|
-
parent.tap do
|
76
|
-
parent = parent[self.instance.path[i]]
|
77
|
-
end
|
78
|
-
end.reverse
|
79
|
-
end
|
80
|
-
def parent
|
81
|
-
parents.first
|
82
|
-
end
|
83
|
-
|
84
|
-
def deref
|
85
|
-
derefed = instance.deref
|
86
|
-
if derefed.object_id == instance.object_id
|
87
|
-
self
|
88
|
-
else
|
89
|
-
self.class.new(derefed, origin: @origin)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def modified_copy(&block)
|
94
|
-
modified_instance = instance.modified_copy(&block)
|
95
|
-
self.class.new(modified_instance, origin: @origin)
|
96
|
-
end
|
97
|
-
|
98
|
-
def fragment
|
99
|
-
instance.fragment
|
100
|
-
end
|
101
|
-
|
102
|
-
def fully_validate
|
103
|
-
schema.fully_validate(instance)
|
104
|
-
end
|
105
|
-
def validate
|
106
|
-
schema.validate(instance)
|
107
|
-
end
|
108
|
-
def validate!
|
109
|
-
schema.validate!(instance)
|
110
|
-
end
|
111
|
-
def inspect
|
112
|
-
"\#<#{self.class.to_s} #{instance.inspect}>"
|
113
|
-
end
|
114
|
-
def pretty_print(q)
|
115
|
-
q.instance_exec(self) do |obj|
|
116
|
-
text "\#<#{obj.class.to_s}"
|
117
|
-
group_sub {
|
118
|
-
nest(2) {
|
119
|
-
breakable ' '
|
120
|
-
pp obj.instance
|
121
|
-
}
|
122
|
-
}
|
123
|
-
breakable ''
|
124
|
-
text '>'
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def object_group_text
|
129
|
-
instance.object_group_text
|
130
|
-
end
|
131
|
-
|
132
|
-
def as_json(*opt)
|
133
|
-
Typelike.as_json(instance, *opt)
|
134
|
-
end
|
135
|
-
|
136
|
-
def fingerprint
|
137
|
-
{class: self.class, instance: instance}
|
138
|
-
end
|
139
|
-
include FingerprintHash
|
140
|
-
|
141
|
-
private
|
142
|
-
def instance=(thing)
|
143
|
-
if instance_variable_defined?(:@instance)
|
144
|
-
raise(Scorpio::Bug, "overwriting instance is not supported")
|
145
|
-
end
|
146
|
-
if thing.is_a?(SchemaInstanceBase)
|
147
|
-
warn "assigning instance to a SchemaInstanceBase instance is incorrect. received: #{thing.pretty_inspect.chomp}"
|
148
|
-
@instance = Scorpio.deep_stringify_symbol_keys(thing.instance)
|
149
|
-
elsif thing.is_a?(Scorpio::JSON::Node)
|
150
|
-
@instance = Scorpio.deep_stringify_symbol_keys(thing)
|
151
|
-
else
|
152
|
-
@instance = Scorpio::JSON::Node.new_by_type(Scorpio.deep_stringify_symbol_keys(thing), [])
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def subscript_assign(subscript, value)
|
157
|
-
clear_memo(:[], subscript)
|
158
|
-
if value.is_a?(SchemaInstanceBase)
|
159
|
-
instance[subscript] = value.instance
|
160
|
-
else
|
161
|
-
instance[subscript] = value
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
# this module is just a namespace for schema classes.
|
167
|
-
module SchemaClasses
|
168
|
-
extend Memoize
|
169
|
-
def self.[](schema_id)
|
170
|
-
@classes_by_id[schema_id]
|
171
|
-
end
|
172
|
-
@classes_by_id = {}
|
173
|
-
end
|
174
|
-
|
175
|
-
def SchemaClasses.class_for_schema(schema_object)
|
176
|
-
if schema_object.is_a?(Scorpio::Schema)
|
177
|
-
schema__ = schema_object
|
178
|
-
else
|
179
|
-
schema__ = Scorpio::Schema.new(schema_object)
|
180
|
-
end
|
181
|
-
|
182
|
-
memoize(:class_for_schema, schema__) do |schema_|
|
183
|
-
begin
|
184
|
-
begin
|
185
|
-
Class.new(SchemaInstanceBase).instance_exec(schema_) do |schema|
|
186
|
-
begin
|
187
|
-
include(Scorpio.module_for_schema(schema))
|
188
|
-
|
189
|
-
SchemaClasses.instance_exec(self) { |klass| @classes_by_id[klass.schema_id] = klass }
|
190
|
-
|
191
|
-
self
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
def self.module_for_schema(schema_object)
|
200
|
-
if schema_object.is_a?(Scorpio::Schema)
|
201
|
-
schema__ = schema_object
|
202
|
-
else
|
203
|
-
schema__ = Scorpio::Schema.new(schema_object)
|
204
|
-
end
|
205
|
-
|
206
|
-
memoize(:module_for_schema, schema__) do |schema_|
|
207
|
-
Module.new.tap do |m|
|
208
|
-
m.instance_exec(schema_) do |schema|
|
209
|
-
define_method(:schema) { schema }
|
210
|
-
define_singleton_method(:schema) { schema }
|
211
|
-
define_singleton_method(:included) do |includer|
|
212
|
-
includer.send(:define_singleton_method, :schema) { schema }
|
213
|
-
end
|
214
|
-
|
215
|
-
define_singleton_method(:schema_id) do
|
216
|
-
schema.schema_id
|
217
|
-
end
|
218
|
-
define_singleton_method(:inspect) do
|
219
|
-
%Q(#<Module for Schema: #{schema_id}>)
|
220
|
-
end
|
221
|
-
|
222
|
-
if schema.describes_hash?
|
223
|
-
instance_method_modules = [m, SchemaInstanceBase, SchemaInstanceBaseArray, SchemaInstanceBaseHash]
|
224
|
-
instance_methods = instance_method_modules.map do |mod|
|
225
|
-
mod.instance_methods + mod.private_instance_methods
|
226
|
-
end.inject(Set.new, &:|)
|
227
|
-
accessors_to_define = schema.described_hash_property_names.map(&:to_s) - instance_methods.map(&:to_s)
|
228
|
-
accessors_to_define.each do |property_name|
|
229
|
-
define_method(property_name) do
|
230
|
-
if respond_to?(:[])
|
231
|
-
self[property_name]
|
232
|
-
else
|
233
|
-
raise(NoMethodError, "instance does not respond to []; cannot call reader `#{property_name}' for: #{pretty_inspect.chomp}")
|
234
|
-
end
|
235
|
-
end
|
236
|
-
define_method("#{property_name}=") do |value|
|
237
|
-
if respond_to?(:[]=)
|
238
|
-
self[property_name] = value
|
239
|
-
else
|
240
|
-
raise(NoMethodError, "instance does not respond to []=; cannot call writer `#{property_name}=' for: #{pretty_inspect.chomp}")
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
module SchemaInstanceBaseHash
|
251
|
-
# Hash methods
|
252
|
-
def each
|
253
|
-
return to_enum(__method__) { instance.size } unless block_given?
|
254
|
-
instance.each_key { |k| yield(k, self[k]) }
|
255
|
-
self
|
256
|
-
end
|
257
|
-
|
258
|
-
def to_hash
|
259
|
-
inject({}) { |h, (k, v)| h[k] = v; h }
|
260
|
-
end
|
261
|
-
|
262
|
-
include Hashlike
|
263
|
-
|
264
|
-
# methods that don't look at the value; can skip the overhead of #[] (invoked by #to_hash)
|
265
|
-
SAFE_KEY_ONLY_METHODS.each do |method_name|
|
266
|
-
define_method(method_name) { |*a, &b| instance.public_send(method_name, *a, &b) }
|
267
|
-
end
|
268
|
-
|
269
|
-
def [](property_name_)
|
270
|
-
memoize(:[], property_name_) do |property_name|
|
271
|
-
begin
|
272
|
-
property_schema = schema.subschema_for_property(property_name)
|
273
|
-
property_schema = property_schema && property_schema.match_to_instance(instance[property_name])
|
274
|
-
|
275
|
-
if property_schema && instance[property_name].is_a?(JSON::Node)
|
276
|
-
Scorpio.class_for_schema(property_schema).new(instance[property_name], origin: @origin)
|
277
|
-
else
|
278
|
-
instance[property_name]
|
279
|
-
end
|
280
|
-
end
|
281
|
-
end
|
282
|
-
end
|
283
|
-
def []=(property_name, value)
|
284
|
-
subscript_assign(property_name, value)
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
module SchemaInstanceBaseArray
|
289
|
-
def each
|
290
|
-
return to_enum(__method__) { instance.size } unless block_given?
|
291
|
-
instance.each_index { |i| yield(self[i]) }
|
292
|
-
self
|
293
|
-
end
|
294
|
-
|
295
|
-
def to_ary
|
296
|
-
to_a
|
297
|
-
end
|
298
|
-
|
299
|
-
include Arraylike
|
300
|
-
|
301
|
-
# methods that don't look at the value; can skip the overhead of #[] (invoked by #to_a).
|
302
|
-
# we override these methods from Arraylike
|
303
|
-
SAFE_INDEX_ONLY_METHODS.each do |method_name|
|
304
|
-
define_method(method_name) { |*a, &b| instance.public_send(method_name, *a, &b) }
|
305
|
-
end
|
306
|
-
|
307
|
-
def [](i_)
|
308
|
-
memoize(:[], i_) do |i|
|
309
|
-
begin
|
310
|
-
index_schema = schema.subschema_for_index(i)
|
311
|
-
index_schema = index_schema && index_schema.match_to_instance(instance[i])
|
312
|
-
|
313
|
-
if index_schema && instance[i].is_a?(JSON::Node)
|
314
|
-
Scorpio.class_for_schema(index_schema).new(instance[i], origin: @origin)
|
315
|
-
else
|
316
|
-
instance[i]
|
317
|
-
end
|
318
|
-
end
|
319
|
-
end
|
320
|
-
end
|
321
|
-
def []=(i, value)
|
322
|
-
subscript_assign(i, value)
|
323
|
-
end
|
324
|
-
end
|
325
|
-
end
|