scorpio 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -0
- data/README.md +108 -25
- data/Rakefile +2 -2
- data/documents/openapis.org/v3/schema.json +1239 -0
- data/documents/openapis.org/v3/schema.yml +794 -0
- data/lib/scorpio.rb +68 -68
- data/lib/scorpio/google_api_document.rb +18 -24
- data/lib/scorpio/json-schema-fragments.rb +1 -1
- data/lib/scorpio/json/node.rb +106 -74
- data/lib/scorpio/openapi.rb +146 -68
- data/lib/scorpio/pickle_adapter.rb +3 -3
- data/lib/scorpio/{model.rb → resource_base.rb} +187 -145
- data/lib/scorpio/schema.rb +188 -76
- data/lib/scorpio/schema_instance_base.rb +309 -0
- data/lib/scorpio/schema_instance_base/to_rb.rb +127 -0
- data/lib/scorpio/typelike_modules.rb +120 -4
- data/lib/scorpio/util.rb +83 -0
- data/lib/scorpio/util/faraday/response_media_type.rb +15 -0
- data/lib/scorpio/version.rb +1 -1
- data/scorpio.gemspec +0 -1
- metadata +10 -19
- data/lib/scorpio/schema_object_base.rb +0 -227
@@ -1,227 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'scorpio/typelike_modules'
|
3
|
-
|
4
|
-
module Scorpio
|
5
|
-
# base class for representing an instance of an object described by a schema
|
6
|
-
class SchemaObjectBase
|
7
|
-
def initialize(object)
|
8
|
-
if object.is_a?(Scorpio::JSON::Node)
|
9
|
-
@object = object
|
10
|
-
else
|
11
|
-
@object = Scorpio::JSON::Node.new_by_type(object, [])
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
attr_reader :object
|
16
|
-
|
17
|
-
def fragment
|
18
|
-
object.fragment
|
19
|
-
end
|
20
|
-
|
21
|
-
def fully_validate
|
22
|
-
module_schema.fully_validate(object)
|
23
|
-
end
|
24
|
-
def validate
|
25
|
-
module_schema.validate(object)
|
26
|
-
end
|
27
|
-
def validate!
|
28
|
-
module_schema.validate!(object)
|
29
|
-
end
|
30
|
-
def inspect
|
31
|
-
"\#<#{self.class.name} #{object.inspect}>"
|
32
|
-
end
|
33
|
-
def pretty_print(q)
|
34
|
-
q.instance_exec(self) do |obj|
|
35
|
-
text "\#<#{obj.class.name}"
|
36
|
-
group_sub {
|
37
|
-
nest(2) {
|
38
|
-
breakable ' '
|
39
|
-
pp obj.object
|
40
|
-
}
|
41
|
-
}
|
42
|
-
breakable ''
|
43
|
-
text '>'
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def fingerprint
|
48
|
-
{class: self.class, object: object}
|
49
|
-
end
|
50
|
-
include FingerprintHash
|
51
|
-
end
|
52
|
-
|
53
|
-
CLASS_FOR_SCHEMA = Hash.new do |h, schema_node_|
|
54
|
-
h[schema_node_] = Class.new(SchemaObjectBase).instance_exec(schema_node_) do |schema_node|
|
55
|
-
prepend(Scorpio.module_for_schema(schema_node))
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.class_for_schema(schema_node)
|
60
|
-
schema_node = schema_node.object if schema_node.is_a?(Scorpio::SchemaObjectBase)
|
61
|
-
CLASS_FOR_SCHEMA[schema_node.deref]
|
62
|
-
end
|
63
|
-
|
64
|
-
# this invokes methods of type-like modules (Arraylike, Hashlike) but only if the #object
|
65
|
-
# is of the expected class. since the object may be anything - it will just not be a valid
|
66
|
-
# instance of its schema - we can't assume that the methods on the Xlike modules will work
|
67
|
-
# (e.g. trying to call #each_index on an #object that's not array-like)
|
68
|
-
module SchemaObjectMightBeLike
|
69
|
-
def inspect(*a, &b)
|
70
|
-
if object.is_a?(expected_object_class)
|
71
|
-
super
|
72
|
-
else
|
73
|
-
SchemaObjectBase.instance_method(:inspect).bind(self).call(*a, &b)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
def pretty_print(*a, &b)
|
77
|
-
if object.is_a?(expected_object_class)
|
78
|
-
super
|
79
|
-
else
|
80
|
-
SchemaObjectBase.instance_method(:pretty_print).bind(self).call(*a, &b)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
module SchemaObjectBaseHash
|
85
|
-
def expected_object_class
|
86
|
-
Scorpio::JSON::HashNode
|
87
|
-
end
|
88
|
-
|
89
|
-
# Hash methods
|
90
|
-
def each
|
91
|
-
return to_enum(__method__) { object.size } unless block_given?
|
92
|
-
object.each_key { |k| yield(k, self[k]) }
|
93
|
-
self
|
94
|
-
end
|
95
|
-
include Enumerable
|
96
|
-
|
97
|
-
def to_hash
|
98
|
-
inject({}) { |h, (k, v)| h[k] = v; h }
|
99
|
-
end
|
100
|
-
|
101
|
-
include Hashlike
|
102
|
-
include SchemaObjectMightBeLike
|
103
|
-
|
104
|
-
# hash methods - define only those which do not modify the hash.
|
105
|
-
|
106
|
-
# methods that don't look at the value; can skip the overhead of #[]
|
107
|
-
key_methods = %w(each_key empty? include? has_key? key key? keys length member? size)
|
108
|
-
key_methods.each do |method_name|
|
109
|
-
define_method(method_name) { |*a, &b| object.public_send(method_name, *a, &b) }
|
110
|
-
end
|
111
|
-
|
112
|
-
# methods which use key and value
|
113
|
-
hash_methods = %w(compact each_pair each_value fetch fetch_values has_value? invert
|
114
|
-
rassoc reject select to_h transform_values value? values values_at)
|
115
|
-
hash_methods.each do |method_name|
|
116
|
-
define_method(method_name) { |*a, &b| to_hash.public_send(method_name, *a, &b) }
|
117
|
-
end
|
118
|
-
|
119
|
-
def [](property_name_)
|
120
|
-
@object_mapped ||= Hash.new do |hash, property_name|
|
121
|
-
hash[property_name] = begin
|
122
|
-
property_schema = module_schema.subschema_for_property(property_name)
|
123
|
-
property_schema = property_schema && property_schema.match_to_object(object[property_name])
|
124
|
-
|
125
|
-
if property_schema && object[property_name].is_a?(JSON::Node)
|
126
|
-
Scorpio.class_for_schema(property_schema.schema_node).new(object[property_name])
|
127
|
-
else
|
128
|
-
object[property_name]
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
@object_mapped[property_name_]
|
133
|
-
end
|
134
|
-
|
135
|
-
def merge(other)
|
136
|
-
# we want to strip the containers from this before we merge
|
137
|
-
# this is kind of annoying. wish I had a better way.
|
138
|
-
other_stripped = ycomb do |striprec|
|
139
|
-
proc do |stripobject|
|
140
|
-
stripobject = stripobject.object if stripobject.is_a?(Scorpio::SchemaObjectBase)
|
141
|
-
stripobject = stripobject.content if stripobject.is_a?(Scorpio::JSON::Node)
|
142
|
-
if stripobject.is_a?(Hash)
|
143
|
-
stripobject.map { |k, v| {striprec.call(k) => striprec.call(v)} }.inject({}, &:update)
|
144
|
-
elsif stripobject.is_a?(Array)
|
145
|
-
stripobject.map(&striprec)
|
146
|
-
elsif stripobject.is_a?(Symbol)
|
147
|
-
stripobject.to_s
|
148
|
-
elsif [String, TrueClass, FalseClass, NilClass, Numeric].any? { |c| stripobject.is_a?(c) }
|
149
|
-
stripobject
|
150
|
-
else
|
151
|
-
raise(TypeError, "bad (not jsonifiable) object: #{stripobject.pretty_inspect}")
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end.call(other)
|
155
|
-
|
156
|
-
self.class.new(object.merge(other_stripped))
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
module SchemaObjectBaseArray
|
161
|
-
def expected_object_class
|
162
|
-
Scorpio::JSON::ArrayNode
|
163
|
-
end
|
164
|
-
|
165
|
-
def each
|
166
|
-
return to_enum(__method__) { object.size } unless block_given?
|
167
|
-
object.each_index { |i| yield(self[i]) }
|
168
|
-
self
|
169
|
-
end
|
170
|
-
include Enumerable
|
171
|
-
|
172
|
-
def to_ary
|
173
|
-
to_a
|
174
|
-
end
|
175
|
-
|
176
|
-
include Arraylike
|
177
|
-
include SchemaObjectMightBeLike
|
178
|
-
|
179
|
-
def [](i_)
|
180
|
-
# it would make more sense for this to be an array here, but but Array doesn't have a nice memoizing
|
181
|
-
# constructor, so it's a hash with integer keys
|
182
|
-
@object_mapped ||= Hash.new do |hash, i|
|
183
|
-
hash[i] = begin
|
184
|
-
index_schema = module_schema.subschema_for_index(i)
|
185
|
-
index_schema = index_schema && index_schema.match_to_object(object[i])
|
186
|
-
|
187
|
-
if index_schema && object[i].is_a?(JSON::Node)
|
188
|
-
Scorpio.class_for_schema(index_schema.schema_node).new(object[i])
|
189
|
-
else
|
190
|
-
object[i]
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
@object_mapped[i_]
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
def self.module_for_schema(schema_node_)
|
199
|
-
Module.new.tap do |m|
|
200
|
-
m.instance_exec(schema_node_) do |module_schema_node|
|
201
|
-
unless module_schema_node.is_a?(Scorpio::JSON::Node)
|
202
|
-
raise(ArgumentError, "expected instance of Scorpio::JSON::Node; got: #{module_schema_node.pretty_inspect.chomp}")
|
203
|
-
end
|
204
|
-
|
205
|
-
module_schema = Scorpio::Schema.new(module_schema_node)
|
206
|
-
|
207
|
-
define_method(:module_schema) { module_schema }
|
208
|
-
define_singleton_method(:module_schema) { module_schema }
|
209
|
-
define_singleton_method(:included) do |includer|
|
210
|
-
includer.send(:define_singleton_method, :module_schema) { module_schema }
|
211
|
-
end
|
212
|
-
|
213
|
-
if module_schema.describes_hash?
|
214
|
-
include SchemaObjectBaseHash
|
215
|
-
|
216
|
-
module_schema.described_hash_property_names.each do |property_name|
|
217
|
-
define_method(property_name) do
|
218
|
-
self[property_name]
|
219
|
-
end
|
220
|
-
end
|
221
|
-
elsif module_schema.describes_array?
|
222
|
-
include SchemaObjectBaseArray
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|