keiyaku 0.1.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.
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Keiyaku
4
+ VERSION = "0.1.0"
5
+ end
data/lib/keiyaku.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Loads the runtime, which is all an application needs: generated clients
4
+ # require "keiyaku/runtime" directly. The generator is a separate file that
5
+ # only the `keiyaku` executable pulls in, so nothing that merely calls an API
6
+ # ever loads it.
7
+ require_relative "keiyaku/runtime"
data/sig/keiyaku.rbs ADDED
@@ -0,0 +1,216 @@
1
+ # Signatures for the runtime. Generated clients declare `class Client <
2
+ # Keiyaku::Client` and `class Pet < Keiyaku::Model`, so without these their own
3
+ # RBS would not resolve — which would defeat the point of emitting it.
4
+
5
+ module Keiyaku
6
+ VERSION: String
7
+
8
+ # A parameter that was not passed, distinct from one passed as nil.
9
+ UNSET: untyped
10
+
11
+ # The words Ruby will not read as a name, which the generated method body
12
+ # needs too: a parameter may be called one of these.
13
+ KEYWORDS: Array[String]
14
+
15
+ class Error < StandardError
16
+ end
17
+
18
+ class CastError < Error
19
+ end
20
+
21
+ class Unsupported < Error
22
+ end
23
+
24
+ class HTTPError < Error
25
+ attr_reader status: Integer
26
+ attr_reader headers: Hash[String, String]
27
+ attr_reader body: String?
28
+
29
+ # The decoded body: a model if the operation documents a schema for this
30
+ # status, otherwise whatever JSON.parse returned.
31
+ attr_reader parsed: untyped
32
+
33
+ def initialize: (status: Integer, headers: Hash[String, String], body: String?, ?parsed: untyped) -> void
34
+ end
35
+
36
+ class ClientError < HTTPError
37
+ end
38
+
39
+ class ServerError < HTTPError
40
+ end
41
+
42
+ # The request did not happen. Every adapter raises this rather than its own
43
+ # library's class, so moving a client onto another HTTP stack does not
44
+ # change what the code around it has to rescue.
45
+ class ConnectionError < Error
46
+ end
47
+
48
+ # What a transport failure looks like from the stdlib.
49
+ TRANSPORT_ERRORS: Array[Class]
50
+
51
+ # One number for both phases, or `{ open:, read: }` for two.
52
+ type timeout = Integer | Float | Hash[Symbol, Integer | Float]
53
+
54
+ def self.timeouts: (timeout) -> [Integer | Float, Integer | Float]
55
+
56
+ def self.camelize: (String | Symbol) -> String
57
+ def self.snake: (String | Symbol) -> String
58
+
59
+ # Types are values, not a type language: Integer, [Pet], { String => Pet },
60
+ # :bool, :any. There is nothing more precise to say about them here.
61
+ def self.coerce: (untyped type, untyped value, String path) -> untyped
62
+ def self.dump: (untyped) -> untyped
63
+
64
+ # Keyed by an exact code, by a range like "4XX", or by :default, narrowest
65
+ # first. The table is the operation's, so its values are whatever it holds.
66
+ def self.for_status: (Hash[untyped, untyped] table, Integer status) -> untyped
67
+
68
+ # Returns a Keiyaku::Model subclass built at runtime; the generator emits a
69
+ # proper class declaration for each one alongside the code. The fields are a
70
+ # positional Hash so that a property named `from` cannot displace the option.
71
+ def self.model: (
72
+ Hash[Symbol, untyped] fields, ?required: Array[Symbol], ?from: Hash[Symbol, String], ?open: untyped
73
+ ) -> untyped
74
+
75
+ # The value type a schema becomes. Each generated model declares its own
76
+ # fields, `new` and `with`; what is here is what they all share.
77
+ class Model
78
+ def self.members: () -> Array[Symbol]
79
+ def self.types: () -> Hash[Symbol, untyped]
80
+ def self.json_names: () -> Hash[Symbol, String]
81
+ def self.required: () -> Array[Symbol]
82
+
83
+ # What `additionalProperties` said: false, true, or the type declared for
84
+ # the values of the properties the schema did not name.
85
+ def self.additional: () -> untyped
86
+ def self.open?: () -> bool
87
+
88
+ def self.cast: (untyped, ?String) -> untyped
89
+ def self.__define: (Hash[Symbol, untyped] fields, required: Array[Symbol], from: Hash[Symbol, String], open: untyped) -> void
90
+
91
+ def initialize: (**untyped) -> void
92
+
93
+ # A field by name, whether or not it is one Ruby will take through a dot,
94
+ # and on an open model the properties the document did not name.
95
+ def []: (String | Symbol) -> untyped
96
+
97
+ def with: (**untyped) -> self
98
+ def to_h: () -> Hash[Symbol, untyped]
99
+ def deconstruct: () -> Array[untyped]
100
+ def deconstruct_keys: (Array[Symbol]?) -> Hash[Symbol, untyped]
101
+ def to_json_hash: () -> Hash[String, untyped]
102
+ def to_json: (*untyped) -> String
103
+ end
104
+
105
+ class OneOf
106
+ def self.[]: (*untyped variants, on: String, ?map: Hash[untyped, untyped]) -> OneOf
107
+ def initialize: (Array[untyped], String, Hash[untyped, untyped]) -> void
108
+ def cast: (untyped, ?String) -> untyped
109
+ end
110
+
111
+ # Keyed by the code itself or by the range the document wrote in place of
112
+ # one, which is a String because `2XX` is not a number.
113
+ class ByStatus
114
+ def self.[]: (Hash[Integer | String, untyped] types) -> ByStatus
115
+ def initialize: (Hash[Integer | String, untyped]) -> void
116
+ def []: (Integer status) -> untyped
117
+ def types: () -> Hash[Integer | String, untyped]
118
+
119
+ private
120
+
121
+ def normalise: (untyped status) -> untyped
122
+ end
123
+
124
+ class Upload
125
+ attr_reader io: untyped
126
+ attr_reader filename: String
127
+ attr_reader content_type: String
128
+
129
+ def initialize: (untyped io, ?filename: String?, ?content_type: String?) -> void
130
+ def read: () -> String
131
+ end
132
+
133
+ module Serialize
134
+ def self.query: (Hash[String, untyped], ?deep: Array[String]) -> Array[[String, String]]
135
+ def self.deep_object: (String name, untyped value) -> Array[[String, String]]
136
+ def self.path: (String name, untyped value, ?explode: bool) -> String
137
+ def self.simple: (String name, untyped value, ?explode: bool, ?escape: bool) -> String
138
+ def self.simple_part: (String name, untyped value, ?escape: bool) -> String
139
+ def self.stringify: (untyped) -> String
140
+ def self.multipart: (Hash[String, untyped], String boundary) -> String
141
+ def self.part: (String name, untyped value, String boundary) -> String
142
+ end
143
+
144
+ # Anything that can make a request. Pass one as `adapter:` to put the client
145
+ # on an HTTP stack the application already has. Response header names may be
146
+ # in any case; the client lower-cases them before reading any.
147
+ interface _Adapter
148
+ def call: (Symbol verb, untyped uri, Hash[String, String] headers, String? body) -> [Integer, Hash[String, untyped], String?]
149
+ end
150
+
151
+ # Autoloaded from `keiyaku/adapters/net_http` by the client that was given no
152
+ # adapter, so nothing has to require it to get the default.
153
+ class NetHTTPAdapter
154
+ include _Adapter
155
+
156
+ def initialize: (?timeout: timeout) -> void
157
+ end
158
+
159
+ # Loaded only by `require "keiyaku/adapters/faraday"`. Faraday's own types
160
+ # are deliberately not named here: the signature has to resolve whether or
161
+ # not the gem is installed.
162
+ class FaradayAdapter
163
+ include _Adapter
164
+
165
+ def initialize: (?untyped connection, ?timeout: timeout?, **untyped) -> void
166
+ end
167
+
168
+ # Loaded only by `require "keiyaku/adapters/http"`. Wraps the http.rb gem.
169
+ class HTTPAdapter
170
+ include _Adapter
171
+
172
+ def initialize: (?untyped client, ?timeout: timeout) -> void
173
+ end
174
+
175
+ class Client
176
+ def self.operations: () -> Hash[Symbol, Hash[Symbol, untyped]]
177
+ def self.server: (?String?) -> String?
178
+
179
+ # The schemes the document declares, by its own name for each, and the
180
+ # requirement that holds where an operation states none of its own.
181
+ def self.security: (?Hash[Symbol | String, untyped] schemes, ?default: untyped) -> untyped
182
+ def self.default_security: () -> Array[Array[Symbol]]
183
+
184
+ # A requirement is a list of alternatives, any one of which is enough,
185
+ # each naming the schemes that all have to be satisfied.
186
+ def self.requirement: (untyped) -> Array[Array[Symbol]]
187
+
188
+ def self.get: (Symbol name, String template, **untyped) -> void
189
+ def self.post: (Symbol name, String template, **untyped) -> void
190
+ def self.put: (Symbol name, String template, **untyped) -> void
191
+ def self.patch: (Symbol name, String template, **untyped) -> void
192
+ def self.delete: (Symbol name, String template, **untyped) -> void
193
+ def self.head: (Symbol name, String template, **untyped) -> void
194
+ def self.options: (Symbol name, String template, **untyped) -> void
195
+
196
+ def self.operation: (
197
+ Symbol verb, Symbol name, String template,
198
+ ?query: Array[Symbol], ?deep_object: Array[String], ?header: Hash[String, Symbol],
199
+ ?explode: Array[String], ?required: Array[Symbol | String],
200
+ ?body: untyped, ?form: untyped, ?multipart: untyped, ?content_type: String?, ?body_required: bool,
201
+ ?into: untyped, ?errors: Hash[untyped, untyped], ?security: untyped
202
+ ) -> void
203
+
204
+ def self.unsupported: (Symbol name, String reason) -> void
205
+
206
+ attr_reader base_url: String
207
+
208
+ # `auth:` is credentials by scheme name — a bare value only where the
209
+ # document declares one scheme, since with two there is nothing to say
210
+ # which it is.
211
+ def initialize: (
212
+ ?base_url: String?, ?auth: Hash[Symbol | String, untyped] | String | Array[String] | nil,
213
+ ?adapter: _Adapter?, ?timeout: timeout, ?retries: Integer, ?logger: untyped
214
+ ) -> void
215
+ end
216
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: keiyaku
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - merely
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: |
13
+ Generates Ruby clients from OpenAPI documents that carry only what is
14
+ specific to one API — an operation table and the schema fields. Transport,
15
+ parameter serialization, casting and error mapping live in a shared
16
+ runtime, so a nineteen-operation client is about seventy lines. A schema
17
+ becomes a frozen value type with RBS emitted beside it, so terse Ruby
18
+ costs nothing in tooling. Constructs it cannot translate faithfully are
19
+ refused at generation time rather than emitted as plausible guesses.
20
+ email:
21
+ - git@merely.ca
22
+ executables:
23
+ - keiyaku
24
+ extensions: []
25
+ extra_rdoc_files: []
26
+ files:
27
+ - CHANGELOG.md
28
+ - DESIGN.md
29
+ - LICENSE.txt
30
+ - README.md
31
+ - exe/keiyaku
32
+ - lib/keiyaku.rb
33
+ - lib/keiyaku/adapters/faraday.rb
34
+ - lib/keiyaku/adapters/http.rb
35
+ - lib/keiyaku/adapters/net_http.rb
36
+ - lib/keiyaku/emitter.rb
37
+ - lib/keiyaku/emitter/rbs.rb
38
+ - lib/keiyaku/emitter/security.rb
39
+ - lib/keiyaku/names.rb
40
+ - lib/keiyaku/runtime.rb
41
+ - lib/keiyaku/version.rb
42
+ - sig/keiyaku.rbs
43
+ homepage: https://github.com/onyxblade/keiyaku
44
+ licenses:
45
+ - MIT
46
+ metadata:
47
+ source_code_uri: https://github.com/onyxblade/keiyaku
48
+ changelog_uri: https://github.com/onyxblade/keiyaku/blob/main/CHANGELOG.md
49
+ rubygems_mfa_required: 'true'
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '3.2'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubygems_version: 4.0.3
65
+ specification_version: 4
66
+ summary: OpenAPI clients as a table of operations, not a generated codebase.
67
+ test_files: []