lingara-apps 0.1.0.pre.alpha.3
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +123 -0
- data/lib/lingara/apps/app.rb +160 -0
- data/lib/lingara/apps/card.rb +140 -0
- data/lib/lingara/apps/generated/app_action_request.rb +469 -0
- data/lib/lingara/apps/generated/app_card_reply.rb +247 -0
- data/lib/lingara/apps/generated/app_render_request.rb +417 -0
- data/lib/lingara/apps/generated/app_slot_name.rb +41 -0
- data/lib/lingara/apps/generated/button_style.rb +41 -0
- data/lib/lingara/apps/generated/card.rb +239 -0
- data/lib/lingara/apps/limits.rb +227 -0
- data/lib/lingara/apps/manifest.rb +181 -0
- data/lib/lingara/apps/operations.rb +23 -0
- data/lib/lingara/apps/rack_app.rb +31 -0
- data/lib/lingara/apps/unions.rb +284 -0
- data/lib/lingara/apps/version.rb +14 -0
- data/lib/lingara/apps.rb +24 -0
- data/sig/lingara_apps.rbs +346 -0
- metadata +84 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# Generated by ruby/codegen/generate.rb from the app view. DO NOT EDIT.
|
|
2
|
+
|
|
3
|
+
module Lingara
|
|
4
|
+
module Apps
|
|
5
|
+
# The helpers every arm below shares.
|
|
6
|
+
module Unions
|
|
7
|
+
# An arm's wire form: its tag, then every member that is set (an
|
|
8
|
+
# unset optional member is omitted, never null), nested arms in
|
|
9
|
+
# their own wire form.
|
|
10
|
+
def self.wire(tag, value, members)
|
|
11
|
+
members.compact.each_with_object({tag => value}) do |(name, member), out|
|
|
12
|
+
out[name.to_s] = member.is_a?(Array) ? member.map { |m| m.respond_to?(:to_wire) ? m.to_wire : m } : member
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# The keyword arguments for an arm, read from a decoded JSON
|
|
17
|
+
# object: its own members only (an unknown key is ignored), null
|
|
18
|
+
# treated as absent. A missing required member is ArgumentError.
|
|
19
|
+
def self.members(arm, fields)
|
|
20
|
+
arm.members.to_h { |m| [m, fields[m.to_s]] }.compact
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# A ContextSlice, tagged on `kind`: every arm includes this module, so
|
|
25
|
+
# `case x in Lingara::Apps::ContextSlice` matches any of them.
|
|
26
|
+
module ContextSlice
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# A CardElement, tagged on `type`: every arm includes this module, so
|
|
30
|
+
# `case x in Lingara::Apps::CardElement` matches any of them.
|
|
31
|
+
module CardElement
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# A ListItem, tagged on `type`: every arm includes this module, so
|
|
35
|
+
# `case x in Lingara::Apps::ListItem` matches any of them.
|
|
36
|
+
module ListItem
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# The ContextSlice arm `languages`.
|
|
40
|
+
ContextSliceLanguages = Data.define(:source_lang, :target_lang, :level) do
|
|
41
|
+
include ContextSlice
|
|
42
|
+
|
|
43
|
+
def initialize(source_lang:, target_lang:, level: nil)
|
|
44
|
+
super
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def kind = "languages"
|
|
48
|
+
|
|
49
|
+
def to_wire = Unions.wire("kind", "languages", to_h)
|
|
50
|
+
|
|
51
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# The ContextSlice arm `plan_summary`.
|
|
55
|
+
ContextSlicePlanSummary = Data.define(:plan_id, :target_lang, :set_count, :sets_completed, :title) do
|
|
56
|
+
include ContextSlice
|
|
57
|
+
|
|
58
|
+
def initialize(plan_id:, target_lang:, set_count:, sets_completed:, title: nil)
|
|
59
|
+
super
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def kind = "plan_summary"
|
|
63
|
+
|
|
64
|
+
def to_wire = Unions.wire("kind", "plan_summary", to_h)
|
|
65
|
+
|
|
66
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# The ContextSlice arm `review_due`.
|
|
70
|
+
ContextSliceReviewDue = Data.define(:due, :learned) do
|
|
71
|
+
include ContextSlice
|
|
72
|
+
|
|
73
|
+
def kind = "review_due"
|
|
74
|
+
|
|
75
|
+
def to_wire = Unions.wire("kind", "review_due", to_h)
|
|
76
|
+
|
|
77
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# The ContextSlice arm `tutor_topic`.
|
|
81
|
+
ContextSliceTutorTopic = Data.define(:topic) do
|
|
82
|
+
include ContextSlice
|
|
83
|
+
|
|
84
|
+
def kind = "tutor_topic"
|
|
85
|
+
|
|
86
|
+
def to_wire = Unions.wire("kind", "tutor_topic", to_h)
|
|
87
|
+
|
|
88
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# The CardElement arm `heading`.
|
|
92
|
+
CardElementHeading = Data.define(:text, :level) do
|
|
93
|
+
include CardElement
|
|
94
|
+
|
|
95
|
+
def type = "heading"
|
|
96
|
+
|
|
97
|
+
def to_wire = Unions.wire("type", "heading", to_h)
|
|
98
|
+
|
|
99
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# The CardElement arm `text`.
|
|
103
|
+
CardElementText = Data.define(:text, :lang) do
|
|
104
|
+
include CardElement
|
|
105
|
+
|
|
106
|
+
def initialize(text:, lang: nil)
|
|
107
|
+
super
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def type = "text"
|
|
111
|
+
|
|
112
|
+
def to_wire = Unions.wire("type", "text", to_h)
|
|
113
|
+
|
|
114
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# The CardElement arm `term`.
|
|
118
|
+
CardElementTerm = Data.define(:word, :reading, :gloss, :lang) do
|
|
119
|
+
include CardElement
|
|
120
|
+
|
|
121
|
+
def initialize(word:, reading: nil, gloss: nil, lang: nil)
|
|
122
|
+
super
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def type = "term"
|
|
126
|
+
|
|
127
|
+
def to_wire = Unions.wire("type", "term", to_h)
|
|
128
|
+
|
|
129
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# The CardElement arm `list`.
|
|
133
|
+
CardElementList = Data.define(:items) do
|
|
134
|
+
include CardElement
|
|
135
|
+
|
|
136
|
+
def type = "list"
|
|
137
|
+
|
|
138
|
+
def to_wire = Unions.wire("type", "list", to_h)
|
|
139
|
+
|
|
140
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# The CardElement arm `progress`.
|
|
144
|
+
CardElementProgress = Data.define(:value, :label) do
|
|
145
|
+
include CardElement
|
|
146
|
+
|
|
147
|
+
def type = "progress"
|
|
148
|
+
|
|
149
|
+
def to_wire = Unions.wire("type", "progress", to_h)
|
|
150
|
+
|
|
151
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# The CardElement arm `divider`.
|
|
155
|
+
CardElementDivider = Data.define() do
|
|
156
|
+
include CardElement
|
|
157
|
+
|
|
158
|
+
def type = "divider"
|
|
159
|
+
|
|
160
|
+
def to_wire = Unions.wire("type", "divider", to_h)
|
|
161
|
+
|
|
162
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# The CardElement arm `button`.
|
|
166
|
+
CardElementButton = Data.define(:label, :action, :style) do
|
|
167
|
+
include CardElement
|
|
168
|
+
|
|
169
|
+
def initialize(label:, action:, style: nil)
|
|
170
|
+
super
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def type = "button"
|
|
174
|
+
|
|
175
|
+
def to_wire = Unions.wire("type", "button", to_h)
|
|
176
|
+
|
|
177
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# The CardElement arm `link`.
|
|
181
|
+
CardElementLink = Data.define(:label, :url) do
|
|
182
|
+
include CardElement
|
|
183
|
+
|
|
184
|
+
def type = "link"
|
|
185
|
+
|
|
186
|
+
def to_wire = Unions.wire("type", "link", to_h)
|
|
187
|
+
|
|
188
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# The ListItem arm `text`.
|
|
192
|
+
ListItemText = Data.define(:text, :lang) do
|
|
193
|
+
include ListItem
|
|
194
|
+
|
|
195
|
+
def initialize(text:, lang: nil)
|
|
196
|
+
super
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def type = "text"
|
|
200
|
+
|
|
201
|
+
def to_wire = Unions.wire("type", "text", to_h)
|
|
202
|
+
|
|
203
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# The ListItem arm `term`.
|
|
207
|
+
ListItemTerm = Data.define(:word, :reading, :gloss, :lang) do
|
|
208
|
+
include ListItem
|
|
209
|
+
|
|
210
|
+
def initialize(word:, reading: nil, gloss: nil, lang: nil)
|
|
211
|
+
super
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def type = "term"
|
|
215
|
+
|
|
216
|
+
def to_wire = Unions.wire("type", "term", to_h)
|
|
217
|
+
|
|
218
|
+
def self.from_wire(fields) = new(**Unions.members(self, fields))
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
module ContextSlice
|
|
222
|
+
TAG = "kind"
|
|
223
|
+
|
|
224
|
+
# Each tag value's arm.
|
|
225
|
+
ARMS = {
|
|
226
|
+
"languages" => ContextSliceLanguages,
|
|
227
|
+
"plan_summary" => ContextSlicePlanSummary,
|
|
228
|
+
"review_due" => ContextSliceReviewDue,
|
|
229
|
+
"tutor_topic" => ContextSliceTutorTopic
|
|
230
|
+
}.freeze
|
|
231
|
+
|
|
232
|
+
# The arm a decoded JSON object names, or nil for a tag this kit does
|
|
233
|
+
# not know. A known arm missing a required member is ArgumentError.
|
|
234
|
+
def self.decode(fields)
|
|
235
|
+
arm = ARMS[fields[TAG]]
|
|
236
|
+
arm&.from_wire(fields)
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
module CardElement
|
|
241
|
+
TAG = "type"
|
|
242
|
+
|
|
243
|
+
# Each tag value's arm.
|
|
244
|
+
ARMS = {
|
|
245
|
+
"heading" => CardElementHeading,
|
|
246
|
+
"text" => CardElementText,
|
|
247
|
+
"term" => CardElementTerm,
|
|
248
|
+
"list" => CardElementList,
|
|
249
|
+
"progress" => CardElementProgress,
|
|
250
|
+
"divider" => CardElementDivider,
|
|
251
|
+
"button" => CardElementButton,
|
|
252
|
+
"link" => CardElementLink
|
|
253
|
+
}.freeze
|
|
254
|
+
|
|
255
|
+
# The arm a decoded JSON object names, or nil for a tag this kit does
|
|
256
|
+
# not know. A known arm missing a required member is ArgumentError.
|
|
257
|
+
def self.decode(fields)
|
|
258
|
+
arm = ARMS[fields[TAG]]
|
|
259
|
+
arm&.from_wire(fields)
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
module ListItem
|
|
264
|
+
TAG = "type"
|
|
265
|
+
|
|
266
|
+
# Each tag value's arm.
|
|
267
|
+
ARMS = {
|
|
268
|
+
"text" => ListItemText,
|
|
269
|
+
"term" => ListItemTerm
|
|
270
|
+
}.freeze
|
|
271
|
+
|
|
272
|
+
# The arm a decoded JSON object names, or nil for a tag this kit does
|
|
273
|
+
# not know. A known arm missing a required member is ArgumentError.
|
|
274
|
+
def self.decode(fields)
|
|
275
|
+
arm = ARMS[fields[TAG]]
|
|
276
|
+
arm&.from_wire(fields)
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# The ContextSlice tag values, in the view's order: what a manifest's
|
|
281
|
+
# `context` may name.
|
|
282
|
+
CONTEXT_SLICE_KINDS = ["languages", "plan_summary", "review_due", "tutor_topic"].freeze
|
|
283
|
+
end
|
|
284
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Generated by ruby/codegen/generate.rb from the app view. DO NOT EDIT.
|
|
2
|
+
|
|
3
|
+
module Lingara
|
|
4
|
+
module Apps
|
|
5
|
+
# This kit's released version, SemVer.
|
|
6
|
+
VERSION = "0.1.0-alpha.3"
|
|
7
|
+
|
|
8
|
+
# The same version in RubyGems' spelling, which the gemspec uses.
|
|
9
|
+
GEM_VERSION = "0.1.0.pre.alpha.3"
|
|
10
|
+
|
|
11
|
+
# The API version the app view was generated from.
|
|
12
|
+
GENERATED_FROM = "2026-10-affable-towhee"
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/lingara/apps.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The Lingara app kit for Ruby (ADR 30.9.26am): an app is a server that
|
|
4
|
+
# answers Lingara's two signed requests, app.render and app.action, with a
|
|
5
|
+
# card. Lingara::Apps::App holds the functions and the core,
|
|
6
|
+
# Lingara::Apps::RackApp mounts it, and the card and manifest builders
|
|
7
|
+
# refuse at build time what Lingara would otherwise clamp. The signature
|
|
8
|
+
# check is the `lingara` library's, the gem's only runtime dependency.
|
|
9
|
+
# ../conformance/CONTRACT.md is the behaviour every official kit keeps.
|
|
10
|
+
|
|
11
|
+
require "json"
|
|
12
|
+
require "lingara"
|
|
13
|
+
|
|
14
|
+
require_relative "apps/version"
|
|
15
|
+
|
|
16
|
+
Dir[File.join(__dir__, "apps/generated/*.rb")].sort.each { |file| require file }
|
|
17
|
+
|
|
18
|
+
require_relative "apps/unions"
|
|
19
|
+
require_relative "apps/operations"
|
|
20
|
+
require_relative "apps/limits"
|
|
21
|
+
require_relative "apps/card"
|
|
22
|
+
require_relative "apps/manifest"
|
|
23
|
+
require_relative "apps/app"
|
|
24
|
+
require_relative "apps/rack_app"
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# The public surface of the gem `lingara-apps` (ADR 30.9.26am). The
|
|
2
|
+
# library's own types (Lingara::Events::Webhook and its error) are the
|
|
3
|
+
# `lingara` gem's signatures, so they are untyped here.
|
|
4
|
+
module Lingara
|
|
5
|
+
module Apps
|
|
6
|
+
VERSION: String
|
|
7
|
+
GEM_VERSION: String
|
|
8
|
+
GENERATED_FROM: String
|
|
9
|
+
CONTEXT_SLICE_KINDS: Array[String]
|
|
10
|
+
|
|
11
|
+
type wire = Hash[String, untyped]
|
|
12
|
+
type reply = Card | Reply
|
|
13
|
+
|
|
14
|
+
interface _Logger
|
|
15
|
+
def warn: (String message) -> untyped
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# The generated models (openapi-generator, models only).
|
|
19
|
+
class AppRenderRequest
|
|
20
|
+
attr_accessor type: String
|
|
21
|
+
attr_accessor id: String
|
|
22
|
+
attr_accessor install_id: String
|
|
23
|
+
attr_accessor subject: String
|
|
24
|
+
attr_accessor slot: String
|
|
25
|
+
attr_accessor locale: String
|
|
26
|
+
attr_accessor context: Array[ContextSlice]
|
|
27
|
+
def self.build_from_hash: (Hash[untyped, untyped] attributes) -> AppRenderRequest?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class AppActionRequest
|
|
31
|
+
attr_accessor type: String
|
|
32
|
+
attr_accessor id: String
|
|
33
|
+
attr_accessor install_id: String
|
|
34
|
+
attr_accessor subject: String
|
|
35
|
+
attr_accessor slot: String
|
|
36
|
+
attr_accessor locale: String
|
|
37
|
+
attr_accessor context: Array[ContextSlice]
|
|
38
|
+
attr_accessor action_id: String
|
|
39
|
+
attr_accessor card_etag: String
|
|
40
|
+
def self.build_from_hash: (Hash[untyped, untyped] attributes) -> AppActionRequest?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class Card
|
|
44
|
+
attr_accessor elements: Array[CardElement]
|
|
45
|
+
def initialize: (?Hash[Symbol, untyped] attributes) -> void
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class AppSlotName
|
|
49
|
+
PLANS_EMPTY_DETAIL: String
|
|
50
|
+
HOME_SIDE: String
|
|
51
|
+
UNKNOWN_DEFAULT_OPEN_API: String
|
|
52
|
+
def self.all_vars: () -> Array[String]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class ButtonStyle
|
|
56
|
+
PRIMARY: String
|
|
57
|
+
SECONDARY: String
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The unions and their arms (ruby/codegen/generate.rb). Each arm is a
|
|
61
|
+
# Data class with its view members; `to_wire` writes its JSON object.
|
|
62
|
+
module Unions
|
|
63
|
+
def self.wire: (String tag, String value, Hash[Symbol, untyped] members) -> wire
|
|
64
|
+
def self.members: (untyped arm, Hash[String, untyped] fields) -> Hash[Symbol, untyped]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
interface _Arm
|
|
68
|
+
def to_wire: () -> wire
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
module CardElement : _Arm
|
|
72
|
+
TAG: String
|
|
73
|
+
ARMS: Hash[String, untyped]
|
|
74
|
+
def self.decode: (Hash[String, untyped] fields) -> CardElement?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
module ListItem : _Arm
|
|
78
|
+
TAG: String
|
|
79
|
+
ARMS: Hash[String, untyped]
|
|
80
|
+
def self.decode: (Hash[String, untyped] fields) -> ListItem?
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
module ContextSlice : _Arm
|
|
84
|
+
TAG: String
|
|
85
|
+
ARMS: Hash[String, untyped]
|
|
86
|
+
def self.decode: (Hash[String, untyped] fields) -> ContextSlice?
|
|
87
|
+
def kind: () -> String
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# The arms: Data classes, each including its union.
|
|
91
|
+
class ContextSliceLanguages < Data
|
|
92
|
+
include ContextSlice
|
|
93
|
+
attr_reader source_lang: String
|
|
94
|
+
attr_reader target_lang: String
|
|
95
|
+
attr_reader level: Integer?
|
|
96
|
+
def kind: () -> String
|
|
97
|
+
def to_wire: () -> wire
|
|
98
|
+
def self.from_wire: (Hash[String, untyped] fields) -> ContextSliceLanguages
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class ContextSlicePlanSummary < Data
|
|
102
|
+
include ContextSlice
|
|
103
|
+
attr_reader plan_id: String
|
|
104
|
+
attr_reader title: String?
|
|
105
|
+
attr_reader target_lang: String
|
|
106
|
+
attr_reader set_count: Integer
|
|
107
|
+
attr_reader sets_completed: Integer
|
|
108
|
+
def kind: () -> String
|
|
109
|
+
def to_wire: () -> wire
|
|
110
|
+
def self.from_wire: (Hash[String, untyped] fields) -> ContextSlicePlanSummary
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
class ContextSliceReviewDue < Data
|
|
114
|
+
include ContextSlice
|
|
115
|
+
attr_reader due: Integer
|
|
116
|
+
attr_reader learned: Integer
|
|
117
|
+
def kind: () -> String
|
|
118
|
+
def to_wire: () -> wire
|
|
119
|
+
def self.from_wire: (Hash[String, untyped] fields) -> ContextSliceReviewDue
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
class ContextSliceTutorTopic < Data
|
|
123
|
+
include ContextSlice
|
|
124
|
+
attr_reader topic: String
|
|
125
|
+
def kind: () -> String
|
|
126
|
+
def to_wire: () -> wire
|
|
127
|
+
def self.from_wire: (Hash[String, untyped] fields) -> ContextSliceTutorTopic
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
class CardElementHeading < Data
|
|
131
|
+
include CardElement
|
|
132
|
+
attr_reader text: String
|
|
133
|
+
attr_reader level: Integer
|
|
134
|
+
def type: () -> String
|
|
135
|
+
def to_wire: () -> wire
|
|
136
|
+
def self.from_wire: (Hash[String, untyped] fields) -> CardElementHeading
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
class CardElementText < Data
|
|
140
|
+
include CardElement
|
|
141
|
+
attr_reader text: String
|
|
142
|
+
attr_reader lang: String?
|
|
143
|
+
def type: () -> String
|
|
144
|
+
def to_wire: () -> wire
|
|
145
|
+
def self.from_wire: (Hash[String, untyped] fields) -> CardElementText
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
class CardElementTerm < Data
|
|
149
|
+
include CardElement
|
|
150
|
+
attr_reader word: String
|
|
151
|
+
attr_reader reading: String?
|
|
152
|
+
attr_reader gloss: String?
|
|
153
|
+
attr_reader lang: String?
|
|
154
|
+
def type: () -> String
|
|
155
|
+
def to_wire: () -> wire
|
|
156
|
+
def self.from_wire: (Hash[String, untyped] fields) -> CardElementTerm
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
class CardElementList < Data
|
|
160
|
+
include CardElement
|
|
161
|
+
attr_reader items: Array[ListItem]
|
|
162
|
+
def type: () -> String
|
|
163
|
+
def to_wire: () -> wire
|
|
164
|
+
def self.from_wire: (Hash[String, untyped] fields) -> CardElementList
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
class CardElementProgress < Data
|
|
168
|
+
include CardElement
|
|
169
|
+
attr_reader value: Float
|
|
170
|
+
attr_reader label: String
|
|
171
|
+
def type: () -> String
|
|
172
|
+
def to_wire: () -> wire
|
|
173
|
+
def self.from_wire: (Hash[String, untyped] fields) -> CardElementProgress
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
class CardElementDivider < Data
|
|
177
|
+
include CardElement
|
|
178
|
+
def type: () -> String
|
|
179
|
+
def to_wire: () -> wire
|
|
180
|
+
def self.from_wire: (Hash[String, untyped] fields) -> CardElementDivider
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
class CardElementButton < Data
|
|
184
|
+
include CardElement
|
|
185
|
+
attr_reader label: String
|
|
186
|
+
attr_reader action: String
|
|
187
|
+
attr_reader style: String?
|
|
188
|
+
def type: () -> String
|
|
189
|
+
def to_wire: () -> wire
|
|
190
|
+
def self.from_wire: (Hash[String, untyped] fields) -> CardElementButton
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
class CardElementLink < Data
|
|
194
|
+
include CardElement
|
|
195
|
+
attr_reader label: String
|
|
196
|
+
attr_reader url: String
|
|
197
|
+
def type: () -> String
|
|
198
|
+
def to_wire: () -> wire
|
|
199
|
+
def self.from_wire: (Hash[String, untyped] fields) -> CardElementLink
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
class ListItemText < Data
|
|
203
|
+
include ListItem
|
|
204
|
+
attr_reader text: String
|
|
205
|
+
attr_reader lang: String?
|
|
206
|
+
def type: () -> String
|
|
207
|
+
def to_wire: () -> wire
|
|
208
|
+
def self.from_wire: (Hash[String, untyped] fields) -> ListItemText
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
class ListItemTerm < Data
|
|
212
|
+
include ListItem
|
|
213
|
+
attr_reader word: String
|
|
214
|
+
attr_reader reading: String?
|
|
215
|
+
attr_reader gloss: String?
|
|
216
|
+
attr_reader lang: String?
|
|
217
|
+
def type: () -> String
|
|
218
|
+
def to_wire: () -> wire
|
|
219
|
+
def self.from_wire: (Hash[String, untyped] fields) -> ListItemTerm
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
module Operations
|
|
223
|
+
RENDER: String
|
|
224
|
+
ACTION: String
|
|
225
|
+
REQUESTS: Hash[String, String]
|
|
226
|
+
REPLY: String
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
class CardLimitError < StandardError
|
|
230
|
+
attr_reader reason: Symbol
|
|
231
|
+
def initialize: (Symbol reason) -> void
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
module Limits
|
|
235
|
+
REPLY_MAX_BYTES: Integer
|
|
236
|
+
REQUEST_MAX_BYTES: Integer
|
|
237
|
+
MAX_ELEMENTS: Integer
|
|
238
|
+
MAX_BUTTONS: Integer
|
|
239
|
+
MAX_LIST_ITEMS: Integer
|
|
240
|
+
TUTOR_NOTE_MAX_CHARS: Integer
|
|
241
|
+
MAX_URL_BYTES: Integer
|
|
242
|
+
HEADING_MAX_CHARS: Integer
|
|
243
|
+
TEXT_MAX_CHARS: Integer
|
|
244
|
+
TERM_WORD_MAX_CHARS: Integer
|
|
245
|
+
TERM_READING_MAX_CHARS: Integer
|
|
246
|
+
TERM_GLOSS_MAX_CHARS: Integer
|
|
247
|
+
PROGRESS_LABEL_MAX_CHARS: Integer
|
|
248
|
+
BUTTON_LABEL_MAX_CHARS: Integer
|
|
249
|
+
LINK_LABEL_MAX_CHARS: Integer
|
|
250
|
+
LANG_PATTERN: Regexp
|
|
251
|
+
ACTION_PATTERN: Regexp
|
|
252
|
+
REASONS: Array[Symbol]
|
|
253
|
+
|
|
254
|
+
def self.trim: (String text) -> String
|
|
255
|
+
def self.control?: (String text, bool newline) -> bool
|
|
256
|
+
def self.truncate: (String text, Integer limit) -> String
|
|
257
|
+
def self.safe_link?: (String raw) -> bool
|
|
258
|
+
def self.validate_reply: (untyped reply) -> String
|
|
259
|
+
def self.check_card: (untyped card) -> void
|
|
260
|
+
def self.check_tutor_note: (String note) -> void
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
module Item
|
|
264
|
+
def self.text: (String text, ?lang: String?) -> ListItem
|
|
265
|
+
def self.term: (word: String, ?reading: String?, ?gloss: String?, ?lang: String?) -> ListItem
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
class CardBuilder
|
|
269
|
+
def heading: (String text, ?Integer level) -> self
|
|
270
|
+
def text: (String text, ?lang: String?) -> self
|
|
271
|
+
def term: (word: String, ?reading: String?, ?gloss: String?, ?lang: String?) -> self
|
|
272
|
+
def list: (Array[ListItem] items) -> self
|
|
273
|
+
def progress: (Float | Integer value, String label) -> self
|
|
274
|
+
def divider: () -> self
|
|
275
|
+
def button: (String label, String action, ?style: String?) -> self
|
|
276
|
+
def link: (String label, String url) -> self
|
|
277
|
+
def build: () -> Card
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
class Reply
|
|
281
|
+
attr_reader card: Card
|
|
282
|
+
def initialize: (Card card) -> void
|
|
283
|
+
def tutor_note: (String text) -> self
|
|
284
|
+
| () -> String?
|
|
285
|
+
def to_wire: () -> wire
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
class ManifestError < StandardError
|
|
289
|
+
attr_reader rule: Symbol
|
|
290
|
+
def initialize: (Symbol rule) -> void
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
module ManifestRules
|
|
294
|
+
NAME_MAX_CHARS: Integer
|
|
295
|
+
DESCRIPTION_MAX_CHARS: Integer
|
|
296
|
+
STORED_MAX_BYTES: Integer
|
|
297
|
+
RULES: Array[Symbol]
|
|
298
|
+
SLOT_NAMES: Array[String]
|
|
299
|
+
def self.first_broken: (untyped manifest) -> Symbol?
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
class ManifestBuilder
|
|
303
|
+
type localized = String | Hash[String, String]
|
|
304
|
+
|
|
305
|
+
def default_locale: (String locale) -> self
|
|
306
|
+
def name: (localized name) -> self
|
|
307
|
+
def description: (localized description) -> self
|
|
308
|
+
def render_url: (String url) -> self
|
|
309
|
+
def slots: (*String slots) -> self
|
|
310
|
+
def context: (*String kinds) -> self
|
|
311
|
+
def scopes: (*String scopes) -> self
|
|
312
|
+
def tutor_note: (?bool enabled) -> self
|
|
313
|
+
def listed: (?bool listed) -> self
|
|
314
|
+
def build: () -> wire
|
|
315
|
+
def to_json: (*untyped) -> String
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
class App
|
|
319
|
+
DISPATCH: Hash[String, Symbol]
|
|
320
|
+
attr_reader webhook: untyped
|
|
321
|
+
def initialize: (secret: String | Array[String], ?logger: _Logger) -> void
|
|
322
|
+
def render: () { (AppRenderRequest request) -> reply } -> self
|
|
323
|
+
def action: (String | Symbol id) { (AppActionRequest request) -> reply } -> self
|
|
324
|
+
def handle: (String? method, Hash[String, untyped] headers, ^(Integer) -> String) -> [Integer, Hash[String, String], String]
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
class Decoder
|
|
328
|
+
def initialize: (_Logger logger) -> void
|
|
329
|
+
def decode: (String body) -> (AppRenderRequest | AppActionRequest)?
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
class RackApp
|
|
333
|
+
def initialize: (App app) -> void
|
|
334
|
+
def call: (Hash[String, untyped] env) -> [Integer, Hash[String, String], Array[String]]
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def self.card: () -> CardBuilder
|
|
338
|
+
def self.item: () -> singleton(Item)
|
|
339
|
+
def self.reply: (Card card) -> Reply
|
|
340
|
+
def self.card_wire: (Card card) -> wire
|
|
341
|
+
def self.truncate: (String text, Integer limit) -> String
|
|
342
|
+
def self.validate_reply: (untyped reply) -> String
|
|
343
|
+
def self.manifest: () -> ManifestBuilder
|
|
344
|
+
def self.validate_manifest: (untyped manifest) -> void
|
|
345
|
+
end
|
|
346
|
+
end
|