web_function 0.5.0 → 0.8.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/README.md +435 -14
- data/exe/wfn +12 -5
- data/lib/web_function/argument.rb +81 -65
- data/lib/web_function/attribute.rb +78 -65
- data/lib/web_function/client.rb +119 -37
- data/lib/web_function/documented_error.rb +47 -19
- data/lib/web_function/endpoint.rb +181 -171
- data/lib/web_function/flaggable.rb +40 -0
- data/lib/web_function/object_schema.rb +135 -0
- data/lib/web_function/package.rb +169 -40
- data/lib/web_function/pipeline.rb +35 -6
- data/lib/web_function/promise.rb +68 -0
- data/lib/web_function/request.rb +172 -0
- data/lib/web_function/type/any.rb +48 -0
- data/lib/web_function/type/array_of.rb +58 -0
- data/lib/web_function/type/base.rb +89 -0
- data/lib/web_function/type/union.rb +54 -0
- data/lib/web_function/type.rb +140 -0
- data/lib/web_function/utils.rb +67 -0
- data/lib/web_function/version.rb +1 -1
- data/lib/web_function.rb +23 -11
- metadata +38 -1
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module WebFunction
|
|
4
|
-
# # Endpoint
|
|
5
|
-
#
|
|
6
4
|
# Represents an endpoint as described in a Web Function package.
|
|
7
5
|
#
|
|
8
|
-
# An endpoint defines an operation that can be performed via a Web Function API.
|
|
9
|
-
#
|
|
10
|
-
#
|
|
6
|
+
# An endpoint defines an operation that can be performed via a Web Function API. Endpoints declare their name,
|
|
7
|
+
# documentation, arguments (inputs), attributes (outputs), and the possible errors that may occur when invoking them.
|
|
8
|
+
#
|
|
9
|
+
# Endpoints are described as objects in each package under the `"endpoints"` key. For more information, see:
|
|
11
10
|
#
|
|
12
|
-
# Endpoints are described as objects in each package under the `"endpoints"` key.
|
|
13
|
-
# For more information, see:
|
|
14
11
|
# - [Web Function package docs](https://webfunction.org/package)
|
|
15
12
|
# - [Web Function endpoint docs](https://webfunction.org/endpoint)
|
|
16
13
|
#
|
|
17
|
-
# This class provides methods for accessing endpoint metadata (name, docs, arguments, attributes, errors)
|
|
18
|
-
#
|
|
14
|
+
# This class provides methods for accessing endpoint metadata (name, docs, arguments, attributes, errors) and
|
|
15
|
+
# supports invocation via HTTP.
|
|
19
16
|
#
|
|
20
17
|
# Typical tasks include:
|
|
18
|
+
#
|
|
21
19
|
# - Querying endpoint name or documentation
|
|
22
20
|
# - Enumerating the arguments or attributes definitions
|
|
23
21
|
# - Invoking the endpoint through HTTP using required inputs
|
|
@@ -25,209 +23,221 @@ module WebFunction
|
|
|
25
23
|
# See: https://webfunction.org/endpoint for more details on endpoint structure and contract.
|
|
26
24
|
#
|
|
27
25
|
class Endpoint
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
include Flaggable
|
|
27
|
+
|
|
28
|
+
def initialize(name:, returns:, flags: [], group: nil, docs: nil, arguments: [], attributes: [], errors: [])
|
|
29
|
+
@name = name
|
|
30
|
+
@returns = Type.parse(returns)
|
|
31
|
+
@flags = flags
|
|
32
|
+
@group = group
|
|
33
|
+
@docs = docs
|
|
34
|
+
@arguments = arguments.to_h { |a| [a.name, a] }
|
|
35
|
+
@attributes = attributes.to_h { |a| [a.name, a] }
|
|
36
|
+
@errors = errors.to_h { |e| [e.code, e] }
|
|
30
37
|
end
|
|
31
38
|
|
|
32
39
|
class << self
|
|
33
|
-
#
|
|
40
|
+
# Invokes an endpoint through HTTP using the given URL, bearer authentication, version, and arguments.
|
|
34
41
|
#
|
|
35
|
-
#
|
|
42
|
+
# @param url [String] The URL of the endpoint to invoke
|
|
43
|
+
# @param bearer_auth [String] The bearer authentication token
|
|
44
|
+
# @param version [String] The API version to use
|
|
45
|
+
# @param args [Hash] The arguments to send to the endpoint
|
|
36
46
|
#
|
|
37
|
-
# @return [
|
|
47
|
+
# @return [Object] The response returned by the endpoint
|
|
38
48
|
#
|
|
39
|
-
def
|
|
40
|
-
|
|
41
|
-
response = Excon.post(url,
|
|
42
|
-
headers: headers,
|
|
43
|
-
body: body,
|
|
44
|
-
)
|
|
45
|
-
[response.status, response.body]
|
|
46
|
-
end
|
|
49
|
+
def invoke(url, bearer_auth: nil, version: nil, args: {})
|
|
50
|
+
Request.execute(url, bearer_auth: bearer_auth, version: version, args: args)
|
|
47
51
|
end
|
|
48
52
|
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# Sets the HTTP client used to invoke the endpoint.
|
|
52
|
-
#
|
|
53
|
-
# To provide a custom HTTP client instead of the default (which uses Excon),
|
|
54
|
-
# set this to any object responding to #call or a Proc/lambda.
|
|
55
|
-
#
|
|
56
|
-
# The contract is:
|
|
57
|
-
# client.call(url, headers, body)
|
|
53
|
+
# Creates a new Endpoint from a hash.
|
|
58
54
|
#
|
|
59
|
-
#
|
|
60
|
-
# - headers:[Hash<String,String>] HTTP headers, e.g. { "Content-Type" => "application/json" }
|
|
61
|
-
# - body: [String] The JSON body to post.
|
|
55
|
+
# @param endpoint [Hash] The endpoint hash
|
|
62
56
|
#
|
|
63
|
-
#
|
|
64
|
-
# - status: [Integer] HTTP status code (e.g. 200, 400, 500)
|
|
65
|
-
# - body: [String] Raw response body as a string
|
|
57
|
+
# @return [Endpoint] A new Endpoint instance
|
|
66
58
|
#
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
# [http_response.status, http_response.body]
|
|
71
|
-
# }
|
|
72
|
-
#
|
|
73
|
-
# @param http_client [Proc,#call] The new HTTP client to use.
|
|
74
|
-
#
|
|
75
|
-
attr_writer :http_client
|
|
76
|
-
|
|
77
|
-
def step(url, bearer_auth: nil, args: {})
|
|
78
|
-
headers = {
|
|
79
|
-
"Content-Type": "application/json",
|
|
80
|
-
"Accept": "application/json",
|
|
81
|
-
"User-Agent": "webfunction/#{WebFunction::VERSION}",
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if args.nil?
|
|
85
|
-
args = {}
|
|
59
|
+
def from_hash(endpoint)
|
|
60
|
+
unless endpoint.is_a?(Hash)
|
|
61
|
+
return
|
|
86
62
|
end
|
|
87
63
|
|
|
88
|
-
|
|
89
|
-
|
|
64
|
+
unless endpoint["name"]
|
|
65
|
+
return
|
|
90
66
|
end
|
|
91
67
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
headers: headers,
|
|
95
|
-
body: args,
|
|
96
|
-
}
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def invoke(url, bearer_auth: nil, args: {})
|
|
100
|
-
headers = {
|
|
101
|
-
"Content-Type": "application/json",
|
|
102
|
-
"Accept": "application/json",
|
|
103
|
-
"User-Agent": "webfunction/#{WebFunction::VERSION}",
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if args.nil?
|
|
107
|
-
args = {}
|
|
68
|
+
unless endpoint["returns"]
|
|
69
|
+
return
|
|
108
70
|
end
|
|
109
71
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
},
|
|
122
|
-
)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
begin
|
|
126
|
-
result = JSON.parse(body)
|
|
127
|
-
rescue JSON::ParserError => e
|
|
128
|
-
raise WebFunction::JsonParseError.new(e.message,
|
|
129
|
-
details: {
|
|
130
|
-
status_code: status,
|
|
131
|
-
raw_body: body,
|
|
132
|
-
original_exception: e,
|
|
133
|
-
},
|
|
134
|
-
)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
if status == 400
|
|
138
|
-
code = "BAD_REQUEST"
|
|
139
|
-
message = "Bad request"
|
|
140
|
-
details = { body: result }
|
|
141
|
-
|
|
142
|
-
if result.is_a?(Array) && result.length == 3 && result[0].is_a?(String) && result[1].is_a?(String)
|
|
143
|
-
code = result[0]
|
|
144
|
-
message = result[1]
|
|
145
|
-
details = result[2]
|
|
146
|
-
end
|
|
72
|
+
new(
|
|
73
|
+
name: endpoint["name"],
|
|
74
|
+
returns: endpoint["returns"],
|
|
75
|
+
flags: Utils.normalize_array_of_strings(endpoint["flags"]),
|
|
76
|
+
group: endpoint["group"],
|
|
77
|
+
docs: endpoint["docs"].to_s,
|
|
78
|
+
arguments: Argument.from_array(endpoint["arguments"]),
|
|
79
|
+
attributes: Attribute.from_array(endpoint["attributes"]),
|
|
80
|
+
errors: DocumentedError.from_array(endpoint["errors"]),
|
|
81
|
+
)
|
|
82
|
+
end
|
|
147
83
|
|
|
148
|
-
|
|
84
|
+
# Creates a new Endpoint from an array of hashes. Uses {Endpoint#from_hash} under the hood.
|
|
85
|
+
#
|
|
86
|
+
# @param endpoints [Array<Hash>] The endpoint array of hashes
|
|
87
|
+
#
|
|
88
|
+
# @return [Array<Endpoint>] A new array of Endpoint instances
|
|
89
|
+
#
|
|
90
|
+
def from_array(endpoints)
|
|
91
|
+
Utils.normalize_array endpoints do |endpoint|
|
|
92
|
+
from_hash(endpoint)
|
|
149
93
|
end
|
|
150
|
-
|
|
151
|
-
result
|
|
152
94
|
end
|
|
153
95
|
end
|
|
154
96
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
97
|
+
# The {Client} used to invoke this endpoint. It is assigned when the endpoint is loaded from a package and is
|
|
98
|
+
# required by {#call}.
|
|
99
|
+
#
|
|
100
|
+
# @return [Client, nil]
|
|
101
|
+
#
|
|
102
|
+
attr_accessor :client
|
|
103
|
+
|
|
104
|
+
# The suffix for the endpoint URL, appended to the package's base URL to form the full endpoint URL. Endpoint names
|
|
105
|
+
# are unique within a package; overloading (two endpoints sharing the same name) is not permitted.
|
|
106
|
+
#
|
|
107
|
+
# @return [String]
|
|
108
|
+
#
|
|
109
|
+
attr_reader :name
|
|
110
|
+
|
|
111
|
+
# The JSON type(s) returned by the endpoint. A non-empty array whose entries are each one of:
|
|
112
|
+
#
|
|
113
|
+
# - object
|
|
114
|
+
# - array
|
|
115
|
+
# - string
|
|
116
|
+
# - number
|
|
117
|
+
# - boolean
|
|
118
|
+
# - null
|
|
119
|
+
#
|
|
120
|
+
# @return [Array<String>]
|
|
121
|
+
#
|
|
122
|
+
attr_reader :returns
|
|
123
|
+
|
|
124
|
+
# A name used to categorize or group similar endpoints together. This should be used by documentation tools to
|
|
125
|
+
# organize related endpoints.
|
|
126
|
+
#
|
|
127
|
+
# @return [String, nil]
|
|
128
|
+
#
|
|
129
|
+
attr_reader :group
|
|
130
|
+
|
|
131
|
+
# Documentation for the endpoint. It must be formatted as markdown.
|
|
132
|
+
#
|
|
133
|
+
# @return [String]
|
|
134
|
+
#
|
|
135
|
+
attr_reader :docs
|
|
136
|
+
|
|
137
|
+
# Invokes the endpoint through its assigned {#client}, passing the given arguments.
|
|
138
|
+
#
|
|
139
|
+
# @param args [Hash] The arguments to send to the endpoint.
|
|
140
|
+
#
|
|
141
|
+
# @raise [RuntimeError] If no client has been assigned to the endpoint.
|
|
142
|
+
#
|
|
143
|
+
# @return [Object] The decoded response returned by the endpoint.
|
|
144
|
+
#
|
|
145
|
+
def call(args = {})
|
|
146
|
+
unless client
|
|
147
|
+
raise "Client must be set to invoke an endpoint"
|
|
148
|
+
end
|
|
158
149
|
|
|
159
|
-
|
|
160
|
-
[*@endpoint["returns"]].map { |type| type.to_s }
|
|
150
|
+
client.call(name, args)
|
|
161
151
|
end
|
|
162
152
|
|
|
163
|
-
|
|
164
|
-
|
|
153
|
+
# The list of errors specific to this endpoint. Clients SHOULD only refer to this list if the endpoint uses the
|
|
154
|
+
# `error_triple` flag. See the error specification for more information.
|
|
155
|
+
#
|
|
156
|
+
# @return [Array<DocumentedError>]
|
|
157
|
+
#
|
|
158
|
+
def errors
|
|
159
|
+
@errors.values
|
|
165
160
|
end
|
|
166
161
|
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
# Looks up a single endpoint error by its machine-readable code.
|
|
163
|
+
#
|
|
164
|
+
# @param code [String, Symbol] The error code to look up.
|
|
165
|
+
#
|
|
166
|
+
# @return [DocumentedError, nil] The matching error, or `nil` if none is found.
|
|
167
|
+
#
|
|
168
|
+
def error(code)
|
|
169
|
+
@errors[code.to_s]
|
|
169
170
|
end
|
|
170
171
|
|
|
171
|
-
|
|
172
|
-
|
|
172
|
+
# The attributes of the object returned by the endpoint. Relevant when the endpoint returns an `object`.
|
|
173
|
+
#
|
|
174
|
+
# @return [Array<Attribute>]
|
|
175
|
+
#
|
|
176
|
+
def attributes
|
|
177
|
+
@attributes.values
|
|
173
178
|
end
|
|
174
179
|
|
|
175
|
-
|
|
176
|
-
|
|
180
|
+
# Looks up a single returned attribute by name.
|
|
181
|
+
#
|
|
182
|
+
# @param name [String, Symbol] The name of the attribute to look up.
|
|
183
|
+
#
|
|
184
|
+
# @return [Attribute, nil] The matching attribute, or `nil` if none is found.
|
|
185
|
+
#
|
|
186
|
+
def attribute(name)
|
|
187
|
+
@attributes[name.to_s]
|
|
177
188
|
end
|
|
178
189
|
|
|
190
|
+
# The arguments required by the endpoint. The array is empty when the endpoint requires no arguments.
|
|
191
|
+
#
|
|
192
|
+
# @return [Array<Argument>]
|
|
193
|
+
#
|
|
179
194
|
def arguments
|
|
180
|
-
|
|
181
|
-
return []
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
@endpoint["arguments"].map do |argument|
|
|
185
|
-
unless argument.is_a?(Hash)
|
|
186
|
-
next
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
unless argument["name"]
|
|
190
|
-
next
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
Argument.new(argument)
|
|
194
|
-
end
|
|
195
|
+
@arguments.values
|
|
195
196
|
end
|
|
196
197
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
unless attribute["name"]
|
|
208
|
-
next
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
Attribute.new(attribute)
|
|
212
|
-
end
|
|
198
|
+
# Looks up a single argument by name.
|
|
199
|
+
#
|
|
200
|
+
# @param name [String, Symbol] The name of the argument to look up.
|
|
201
|
+
#
|
|
202
|
+
# @return [Argument, nil] The matching argument, or `nil` if none is found.
|
|
203
|
+
#
|
|
204
|
+
def argument(name)
|
|
205
|
+
@arguments[name.to_s]
|
|
213
206
|
end
|
|
214
207
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
208
|
+
# Whether the endpoint requires authentication via a bearer token, i.e. whether it declares the `bearer_auth` flag.
|
|
209
|
+
#
|
|
210
|
+
# @return [Boolean]
|
|
211
|
+
#
|
|
212
|
+
def bearer_auth?
|
|
213
|
+
flag?("bearer_auth")
|
|
214
|
+
end
|
|
219
215
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
216
|
+
# Whether the endpoint returns a bearer token in its response, i.e. whether it declares the `capture_bearer` flag.
|
|
217
|
+
# See the authentication specification for more information.
|
|
218
|
+
#
|
|
219
|
+
# @return [Boolean]
|
|
220
|
+
#
|
|
221
|
+
def capture_bearer?
|
|
222
|
+
flag?("capture_bearer")
|
|
223
|
+
end
|
|
224
224
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
225
|
+
# Whether the endpoint supports pagination, i.e. whether it declares the `paginated` flag.
|
|
226
|
+
#
|
|
227
|
+
# @return [Boolean]
|
|
228
|
+
#
|
|
229
|
+
def paginated?
|
|
230
|
+
flag?("paginated")
|
|
231
|
+
end
|
|
228
232
|
|
|
229
|
-
|
|
230
|
-
|
|
233
|
+
# Whether the endpoint is intended for internal use and is not part of the public API, i.e. whether it declares the
|
|
234
|
+
# `private` flag. Documentation tooling SHOULD omit endpoints with this flag from generated or
|
|
235
|
+
# published documentation.
|
|
236
|
+
#
|
|
237
|
+
# @return [Boolean]
|
|
238
|
+
#
|
|
239
|
+
def private?
|
|
240
|
+
flag?("private")
|
|
231
241
|
end
|
|
232
242
|
end
|
|
233
243
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebFunction
|
|
4
|
+
# A module that provides a flaggable interface. Flags are used to define the behavior of an object.
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# class Endpoint
|
|
8
|
+
# include Flaggable
|
|
9
|
+
#
|
|
10
|
+
# def initialize(name:, flags: [])
|
|
11
|
+
# @name = name
|
|
12
|
+
# @flags = flags
|
|
13
|
+
# end
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# endpoint = Endpoint.new(name: "get_user", flags: ["private"])
|
|
17
|
+
# endpoint.flag?("private") # => true
|
|
18
|
+
# endpoint.flag?("public") # => false
|
|
19
|
+
#
|
|
20
|
+
module Flaggable
|
|
21
|
+
# List of flags. See the [available flags section][2] on the Web Function
|
|
22
|
+
# website for a complete list of flags available.
|
|
23
|
+
#
|
|
24
|
+
# @return [Array<String>]
|
|
25
|
+
#
|
|
26
|
+
# [2]: https://webfunction.org/package#available-flags
|
|
27
|
+
#
|
|
28
|
+
attr_reader :flags
|
|
29
|
+
|
|
30
|
+
# Whether the endpoint declares the given flag.
|
|
31
|
+
#
|
|
32
|
+
# @param flag [String] The flag to check for.
|
|
33
|
+
#
|
|
34
|
+
# @return [Boolean]
|
|
35
|
+
#
|
|
36
|
+
def flag?(flag)
|
|
37
|
+
@flags.include?(flag)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebFunction
|
|
4
|
+
# Represents a named object definition as described in a Web Function package.
|
|
5
|
+
#
|
|
6
|
+
# Objects are declared in a package under the `"objects"` key and can be referenced as a refined object type
|
|
7
|
+
# (`object.<name>`) anywhere a type is expected. An `object.` reference appears in one of two contexts, which
|
|
8
|
+
# determines which set of properties applies:
|
|
9
|
+
#
|
|
10
|
+
# - Argument context — the object is referenced as an argument's `type`. Its {#arguments} describe its properties.
|
|
11
|
+
# - Attribute context — the object is referenced as an endpoint's `returns` or as an attribute's `type`. Its
|
|
12
|
+
# {#attributes} describe its properties.
|
|
13
|
+
#
|
|
14
|
+
# Because an object MAY be referenced in both contexts within the same package, it MAY define both `arguments` and
|
|
15
|
+
# `attributes`; each set is used only in its matching context.
|
|
16
|
+
#
|
|
17
|
+
# It is named `ObjectSchema` rather than `Object` to avoid clashing with Ruby's built-in `::Object`.
|
|
18
|
+
#
|
|
19
|
+
# See the [object definition documentation][0] on the Web Function website for more details.
|
|
20
|
+
#
|
|
21
|
+
# [0]: https://webfunction.org/package#object-definition
|
|
22
|
+
#
|
|
23
|
+
class ObjectSchema
|
|
24
|
+
# The contexts in which an object may be referenced. Each maps to the member set that applies in that context.
|
|
25
|
+
#
|
|
26
|
+
# @return [Array<Symbol>]
|
|
27
|
+
#
|
|
28
|
+
CONTEXTS = %i[arguments attributes].freeze
|
|
29
|
+
|
|
30
|
+
def initialize(name:, arguments: [], attributes: [])
|
|
31
|
+
@name = name
|
|
32
|
+
@arguments = arguments.to_h { |a| [a.name, a] }
|
|
33
|
+
@attributes = attributes.to_h { |a| [a.name, a] }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class << self
|
|
37
|
+
# Creates a new ObjectSchema from a hash. Typically coming from a {Package}.
|
|
38
|
+
#
|
|
39
|
+
# @param object [Hash] The object hash
|
|
40
|
+
#
|
|
41
|
+
# @return [ObjectSchema, nil] A new ObjectSchema instance, or `nil` if the hash is invalid.
|
|
42
|
+
#
|
|
43
|
+
def from_hash(object)
|
|
44
|
+
unless object.is_a?(Hash)
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
unless object["name"]
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
new(
|
|
53
|
+
name: object["name"],
|
|
54
|
+
arguments: Argument.from_array(object["arguments"]),
|
|
55
|
+
attributes: Attribute.from_array(object["attributes"]),
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Creates a new ObjectSchema from an array of hashes. Typically coming from a {Package}. Uses
|
|
60
|
+
# {ObjectSchema#from_hash} under the hood.
|
|
61
|
+
#
|
|
62
|
+
# @param objects [Array<Hash>] The object array of hashes
|
|
63
|
+
#
|
|
64
|
+
# @return [Array<ObjectSchema>] A new array of ObjectSchema instances
|
|
65
|
+
#
|
|
66
|
+
def from_array(objects)
|
|
67
|
+
Utils.normalize_array objects do |object|
|
|
68
|
+
from_hash(object)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# The name of the object. It is referenced as a refined object type (`object.<name>`) and is unique within a
|
|
74
|
+
# package.
|
|
75
|
+
#
|
|
76
|
+
# @return [String]
|
|
77
|
+
#
|
|
78
|
+
attr_reader :name
|
|
79
|
+
|
|
80
|
+
# The object's properties when it is referenced in an argument context.
|
|
81
|
+
#
|
|
82
|
+
# @return [Array<Argument>]
|
|
83
|
+
#
|
|
84
|
+
def arguments
|
|
85
|
+
@arguments.values
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Looks up a single argument member by name.
|
|
89
|
+
#
|
|
90
|
+
# @param name [String, Symbol] The name of the argument to look up.
|
|
91
|
+
#
|
|
92
|
+
# @return [Argument, nil] The matching argument, or `nil` if none is found.
|
|
93
|
+
#
|
|
94
|
+
def argument(name)
|
|
95
|
+
@arguments[name.to_s]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# The object's properties when it is referenced in an attribute context.
|
|
99
|
+
#
|
|
100
|
+
# @return [Array<Attribute>]
|
|
101
|
+
#
|
|
102
|
+
def attributes
|
|
103
|
+
@attributes.values
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Looks up a single attribute member by name.
|
|
107
|
+
#
|
|
108
|
+
# @param name [String, Symbol] The name of the attribute to look up.
|
|
109
|
+
#
|
|
110
|
+
# @return [Attribute, nil] The matching attribute, or `nil` if none is found.
|
|
111
|
+
#
|
|
112
|
+
def attribute(name)
|
|
113
|
+
@attributes[name.to_s]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# The object's properties for the given context.
|
|
117
|
+
#
|
|
118
|
+
# @param context [Symbol] The context to resolve properties for. One of {CONTEXTS}.
|
|
119
|
+
#
|
|
120
|
+
# @raise [ArgumentError] If the context is not one of {CONTEXTS}.
|
|
121
|
+
#
|
|
122
|
+
# @return [Array<Argument>, Array<Attribute>] The properties that apply in the given context.
|
|
123
|
+
#
|
|
124
|
+
def properties(context)
|
|
125
|
+
case context
|
|
126
|
+
when :arguments
|
|
127
|
+
arguments
|
|
128
|
+
when :attributes
|
|
129
|
+
attributes
|
|
130
|
+
else
|
|
131
|
+
raise ArgumentError, "context must be one of #{CONTEXTS.inspect}, got #{context.inspect}"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|