terminal-shop 1.0.0 → 1.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/README.md +27 -19
- data/lib/terminal-shop/base_client.rb +2 -0
- data/lib/terminal-shop/base_model.rb +471 -440
- data/lib/terminal-shop/base_page.rb +20 -0
- data/lib/terminal-shop/models/cart.rb +35 -2
- data/lib/terminal-shop/models/cart_convert_params.rb +11 -1
- data/lib/terminal-shop/models/cart_redeem_gift_card_params.rb +24 -0
- data/lib/terminal-shop/models/cart_redeem_gift_card_response.rb +48 -0
- data/lib/terminal-shop/models/cart_remove_gift_card_params.rb +18 -0
- data/lib/terminal-shop/models/cart_remove_gift_card_response.rb +19 -0
- data/lib/terminal-shop/models/product.rb +11 -6
- data/lib/terminal-shop/pooled_net_requester.rb +23 -10
- data/lib/terminal-shop/resources/cart.rb +43 -1
- data/lib/terminal-shop/util.rb +146 -52
- data/lib/terminal-shop/version.rb +1 -1
- data/lib/terminal-shop.rb +4 -0
- data/rbi/lib/terminal-shop/base_client.rbi +23 -21
- data/rbi/lib/terminal-shop/base_model.rbi +235 -217
- data/rbi/lib/terminal-shop/client.rbi +2 -2
- data/rbi/lib/terminal-shop/errors.rbi +8 -8
- data/rbi/lib/terminal-shop/models/address.rbi +2 -2
- data/rbi/lib/terminal-shop/models/address_create_params.rbi +3 -13
- data/rbi/lib/terminal-shop/models/address_create_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/address_delete_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/address_delete_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/address_get_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/address_get_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/address_list_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/address_list_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/app.rbi +2 -2
- data/rbi/lib/terminal-shop/models/app_create_params.rbi +2 -2
- data/rbi/lib/terminal-shop/models/app_create_response.rbi +4 -4
- data/rbi/lib/terminal-shop/models/app_delete_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/app_delete_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/app_get_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/app_get_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/app_list_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/app_list_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/card.rbi +4 -4
- data/rbi/lib/terminal-shop/models/card_collect_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/card_collect_response.rbi +4 -4
- data/rbi/lib/terminal-shop/models/card_create_params.rbi +2 -2
- data/rbi/lib/terminal-shop/models/card_create_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/card_delete_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/card_delete_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/card_get_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/card_get_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/card_list_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/card_list_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/cart.rbi +45 -9
- data/rbi/lib/terminal-shop/models/cart_convert_params.rbi +17 -3
- data/rbi/lib/terminal-shop/models/cart_convert_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/cart_get_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/cart_get_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/cart_redeem_gift_card_params.rbi +32 -0
- data/rbi/lib/terminal-shop/models/cart_redeem_gift_card_response.rbi +66 -0
- data/rbi/lib/terminal-shop/models/cart_remove_gift_card_params.rbi +21 -0
- data/rbi/lib/terminal-shop/models/cart_remove_gift_card_response.rbi +23 -0
- data/rbi/lib/terminal-shop/models/cart_set_address_params.rbi +2 -2
- data/rbi/lib/terminal-shop/models/cart_set_address_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/cart_set_card_params.rbi +2 -2
- data/rbi/lib/terminal-shop/models/cart_set_card_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/cart_set_item_params.rbi +2 -2
- data/rbi/lib/terminal-shop/models/cart_set_item_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/email_create_params.rbi +2 -2
- data/rbi/lib/terminal-shop/models/email_create_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/order.rbi +10 -10
- data/rbi/lib/terminal-shop/models/order_create_params.rbi +2 -2
- data/rbi/lib/terminal-shop/models/order_create_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/order_get_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/order_get_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/order_list_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/order_list_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/product.rbi +29 -14
- data/rbi/lib/terminal-shop/models/product_get_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/product_get_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/product_list_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/product_list_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/product_variant.rbi +2 -2
- data/rbi/lib/terminal-shop/models/profile.rbi +4 -4
- data/rbi/lib/terminal-shop/models/profile_me_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/profile_me_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/profile_update_params.rbi +2 -2
- data/rbi/lib/terminal-shop/models/profile_update_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/subscription.rbi +15 -13
- data/rbi/lib/terminal-shop/models/subscription_create_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/subscription_create_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/subscription_delete_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/subscription_delete_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/subscription_get_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/subscription_get_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/subscription_list_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/subscription_list_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/token.rbi +2 -2
- data/rbi/lib/terminal-shop/models/token_create_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/token_create_response.rbi +4 -4
- data/rbi/lib/terminal-shop/models/token_delete_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/token_delete_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/token_get_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/token_get_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/token_list_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/token_list_response.rbi +2 -2
- data/rbi/lib/terminal-shop/models/view_init_params.rbi +5 -2
- data/rbi/lib/terminal-shop/models/view_init_response.rbi +5 -15
- data/rbi/lib/terminal-shop/pooled_net_requester.rbi +15 -10
- data/rbi/lib/terminal-shop/request_options.rbi +4 -0
- data/rbi/lib/terminal-shop/resources/address.rbi +2 -2
- data/rbi/lib/terminal-shop/resources/app.rbi +2 -2
- data/rbi/lib/terminal-shop/resources/card.rbi +2 -2
- data/rbi/lib/terminal-shop/resources/cart.rbi +24 -4
- data/rbi/lib/terminal-shop/resources/email.rbi +2 -2
- data/rbi/lib/terminal-shop/resources/order.rbi +2 -2
- data/rbi/lib/terminal-shop/resources/product.rbi +2 -2
- data/rbi/lib/terminal-shop/resources/profile.rbi +2 -2
- data/rbi/lib/terminal-shop/resources/subscription.rbi +2 -2
- data/rbi/lib/terminal-shop/resources/token.rbi +2 -2
- data/rbi/lib/terminal-shop/resources/view.rbi +2 -2
- data/rbi/lib/terminal-shop/util.rbi +181 -126
- data/rbi/lib/terminal-shop/version.rbi +1 -1
- data/sig/terminal-shop/models/cart.rbs +27 -2
- data/sig/terminal-shop/models/cart_convert_params.rbs +10 -2
- data/sig/terminal-shop/models/cart_redeem_gift_card_params.rbs +25 -0
- data/sig/terminal-shop/models/cart_redeem_gift_card_response.rbs +47 -0
- data/sig/terminal-shop/models/cart_remove_gift_card_params.rbs +19 -0
- data/sig/terminal-shop/models/cart_remove_gift_card_response.rbs +18 -0
- data/sig/terminal-shop/models/product.rbs +8 -2
- data/sig/terminal-shop/pooled_net_requester.rbs +4 -2
- data/sig/terminal-shop/request_options.rbs +4 -0
- data/sig/terminal-shop/resources/cart.rbs +20 -0
- data/sig/terminal-shop/util.rbs +27 -2
- data/sig/terminal-shop/version.rbs +1 -1
- metadata +14 -2
@@ -55,11 +55,11 @@ module TerminalShop
|
|
55
55
|
type_info(spec.slice(:const, :enum, :union).first&.last)
|
56
56
|
in Proc
|
57
57
|
spec
|
58
|
-
in TerminalShop::Converter | Class
|
58
|
+
in TerminalShop::Converter | Class | Symbol
|
59
59
|
-> { spec }
|
60
60
|
in true | false
|
61
61
|
-> { TerminalShop::BooleanModel }
|
62
|
-
in NilClass |
|
62
|
+
in NilClass | Integer | Float
|
63
63
|
-> { spec.class }
|
64
64
|
end
|
65
65
|
end
|
@@ -82,6 +82,13 @@ module TerminalShop
|
|
82
82
|
case target
|
83
83
|
in TerminalShop::Converter
|
84
84
|
target.coerce(value)
|
85
|
+
in Symbol
|
86
|
+
case value
|
87
|
+
in Symbol | String if (val = value.to_sym) == target
|
88
|
+
val
|
89
|
+
else
|
90
|
+
value
|
91
|
+
end
|
85
92
|
in Class
|
86
93
|
case target
|
87
94
|
in -> { _1 <= NilClass }
|
@@ -140,6 +147,13 @@ module TerminalShop
|
|
140
147
|
case target
|
141
148
|
in TerminalShop::Converter
|
142
149
|
target.try_strict_coerce(value)
|
150
|
+
in Symbol
|
151
|
+
case value
|
152
|
+
in Symbol | String if (val = value.to_sym) == target
|
153
|
+
[true, val, 1]
|
154
|
+
else
|
155
|
+
[false, false, 0]
|
156
|
+
end
|
143
157
|
in Class
|
144
158
|
case [target, value]
|
145
159
|
in [-> { _1 <= NilClass }, _]
|
@@ -155,7 +169,7 @@ module TerminalShop
|
|
155
169
|
in [-> { _1 <= Date || _1 <= Time }, String]
|
156
170
|
Kernel.then do
|
157
171
|
[true, target.parse(value), 1]
|
158
|
-
rescue ArgumentError
|
172
|
+
rescue ArgumentError
|
159
173
|
[false, false, 0]
|
160
174
|
end
|
161
175
|
in [_, ^target]
|
@@ -192,33 +206,35 @@ module TerminalShop
|
|
192
206
|
#
|
193
207
|
def self.==(other) = other.is_a?(Class) && other <= TerminalShop::Unknown
|
194
208
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
209
|
+
class << self
|
210
|
+
# @!parse
|
211
|
+
# # @private
|
212
|
+
# #
|
213
|
+
# # @param value [Object]
|
214
|
+
# #
|
215
|
+
# # @return [Object]
|
216
|
+
# #
|
217
|
+
# def coerce(value) = super
|
218
|
+
|
219
|
+
# @!parse
|
220
|
+
# # @private
|
221
|
+
# #
|
222
|
+
# # @param value [Object]
|
223
|
+
# #
|
224
|
+
# # @return [Object]
|
225
|
+
# #
|
226
|
+
# def dump(value) = super
|
212
227
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
228
|
+
# @private
|
229
|
+
#
|
230
|
+
# @param value [Object]
|
231
|
+
#
|
232
|
+
# @return [Array(true, Object, nil), Array(false, Boolean, Integer)]
|
233
|
+
#
|
234
|
+
def try_strict_coerce(value)
|
235
|
+
# prevent unknown variant from being chosen during the first coercion pass
|
236
|
+
[false, true, 0]
|
237
|
+
end
|
222
238
|
end
|
223
239
|
|
224
240
|
# rubocop:enable Lint/UnusedMethodArgument
|
@@ -246,36 +262,38 @@ module TerminalShop
|
|
246
262
|
#
|
247
263
|
def self.==(other) = other.is_a?(Class) && other <= TerminalShop::BooleanModel
|
248
264
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
265
|
+
class << self
|
266
|
+
# @!parse
|
267
|
+
# # @private
|
268
|
+
# #
|
269
|
+
# # @param value [Boolean, Object]
|
270
|
+
# #
|
271
|
+
# # @return [Boolean, Object]
|
272
|
+
# #
|
273
|
+
# def coerce(value) = super
|
274
|
+
|
275
|
+
# @!parse
|
276
|
+
# # @private
|
277
|
+
# #
|
278
|
+
# # @param value [Boolean, Object]
|
279
|
+
# #
|
280
|
+
# # @return [Boolean, Object]
|
281
|
+
# #
|
282
|
+
# def dump(value) = super
|
266
283
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
284
|
+
# @private
|
285
|
+
#
|
286
|
+
# @param value [Object]
|
287
|
+
#
|
288
|
+
# @return [Array(true, Object, nil), Array(false, Boolean, Integer)]
|
289
|
+
#
|
290
|
+
def try_strict_coerce(value)
|
291
|
+
case value
|
292
|
+
in true | false
|
293
|
+
[true, value, 1]
|
294
|
+
else
|
295
|
+
[false, false, 0]
|
296
|
+
end
|
279
297
|
end
|
280
298
|
end
|
281
299
|
end
|
@@ -297,17 +315,19 @@ module TerminalShop
|
|
297
315
|
class Enum
|
298
316
|
extend TerminalShop::Converter
|
299
317
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
318
|
+
class << self
|
319
|
+
# All of the valid Symbol values for this enum.
|
320
|
+
#
|
321
|
+
# @return [Array<NilClass, Boolean, Integer, Float, Symbol>]
|
322
|
+
#
|
323
|
+
def values = (@values ||= constants.map { const_get(_1) })
|
305
324
|
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
325
|
+
# @private
|
326
|
+
#
|
327
|
+
# Guard against thread safety issues by instantiating `@values`.
|
328
|
+
#
|
329
|
+
private def finalize! = values
|
330
|
+
end
|
311
331
|
|
312
332
|
private_class_method :new
|
313
333
|
|
@@ -325,41 +345,50 @@ module TerminalShop
|
|
325
345
|
other.is_a?(Class) && other <= TerminalShop::Enum && other.values.to_set == values.to_set
|
326
346
|
end
|
327
347
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
348
|
+
class << self
|
349
|
+
# @private
|
350
|
+
#
|
351
|
+
# @param value [String, Symbol, Object]
|
352
|
+
#
|
353
|
+
# @return [Symbol, Object]
|
354
|
+
#
|
355
|
+
def coerce(value)
|
356
|
+
case value
|
357
|
+
in Symbol | String if values.include?(val = value.to_sym)
|
358
|
+
val
|
359
|
+
else
|
360
|
+
value
|
361
|
+
end
|
362
|
+
end
|
335
363
|
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
364
|
+
# @!parse
|
365
|
+
# # @private
|
366
|
+
# #
|
367
|
+
# # @param value [Symbol, Object]
|
368
|
+
# #
|
369
|
+
# # @return [Symbol, Object]
|
370
|
+
# #
|
371
|
+
# def dump(value) = super
|
344
372
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
373
|
+
# @private
|
374
|
+
#
|
375
|
+
# @param value [Object]
|
376
|
+
#
|
377
|
+
# @return [Array(true, Object, nil), Array(false, Boolean, Integer)]
|
378
|
+
#
|
379
|
+
def try_strict_coerce(value)
|
380
|
+
return [true, value, 1] if values.include?(value)
|
353
381
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
else
|
358
|
-
case [value, values.first]
|
359
|
-
in [true | false, true | false] | [Integer, Integer] | [Symbol | String, Symbol]
|
360
|
-
[false, true, 0]
|
382
|
+
case value
|
383
|
+
in Symbol | String if values.include?(val = value.to_sym)
|
384
|
+
[true, val, 1]
|
361
385
|
else
|
362
|
-
[
|
386
|
+
case [value, values.first]
|
387
|
+
in [true | false, true | false] | [Integer, Integer] | [Symbol | String, Symbol]
|
388
|
+
[false, true, 0]
|
389
|
+
else
|
390
|
+
[false, false, 0]
|
391
|
+
end
|
363
392
|
end
|
364
393
|
end
|
365
394
|
end
|
@@ -372,15 +401,15 @@ module TerminalShop
|
|
372
401
|
class Union
|
373
402
|
extend TerminalShop::Converter
|
374
403
|
|
375
|
-
# @private
|
376
|
-
#
|
377
|
-
# All of the specified variant info for this union.
|
378
|
-
#
|
379
|
-
# @return [Array<Array(Symbol, Proc)>]
|
380
|
-
#
|
381
|
-
private_class_method def self.known_variants = (@known_variants ||= [])
|
382
|
-
|
383
404
|
class << self
|
405
|
+
# @private
|
406
|
+
#
|
407
|
+
# All of the specified variant info for this union.
|
408
|
+
#
|
409
|
+
# @return [Array<Array(Symbol, Proc)>]
|
410
|
+
#
|
411
|
+
private def known_variants = (@known_variants ||= [])
|
412
|
+
|
384
413
|
# @private
|
385
414
|
#
|
386
415
|
# All of the specified variants for this union.
|
@@ -390,68 +419,68 @@ module TerminalShop
|
|
390
419
|
protected def variants
|
391
420
|
@known_variants.map { |key, variant_fn| [key, variant_fn.call] }
|
392
421
|
end
|
393
|
-
end
|
394
422
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
in Symbol
|
402
|
-
@discriminator = property
|
403
|
-
end
|
404
|
-
end
|
405
|
-
|
406
|
-
# @private
|
407
|
-
#
|
408
|
-
# @param key [Symbol, Hash{Symbol=>Object}, Proc, TerminalShop::Converter, Class]
|
409
|
-
#
|
410
|
-
# @param spec [Hash{Symbol=>Object}, Proc, TerminalShop::Converter, Class] .
|
411
|
-
#
|
412
|
-
# @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
|
413
|
-
#
|
414
|
-
# @option spec [Proc] :enum
|
415
|
-
#
|
416
|
-
# @option spec [Proc] :union
|
417
|
-
#
|
418
|
-
# @option spec [Boolean] :"nil?"
|
419
|
-
#
|
420
|
-
private_class_method def self.variant(key, spec = nil)
|
421
|
-
variant_info =
|
422
|
-
case key
|
423
|
+
# @private
|
424
|
+
#
|
425
|
+
# @param property [Symbol]
|
426
|
+
#
|
427
|
+
private def discriminator(property)
|
428
|
+
case property
|
423
429
|
in Symbol
|
424
|
-
|
425
|
-
in Proc | TerminalShop::Converter | Class | Hash
|
426
|
-
[nil, TerminalShop::Converter.type_info(key)]
|
430
|
+
@discriminator = property
|
427
431
|
end
|
432
|
+
end
|
428
433
|
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
434
|
+
# @private
|
435
|
+
#
|
436
|
+
# @param key [Symbol, Hash{Symbol=>Object}, Proc, TerminalShop::Converter, Class]
|
437
|
+
#
|
438
|
+
# @param spec [Hash{Symbol=>Object}, Proc, TerminalShop::Converter, Class] .
|
439
|
+
#
|
440
|
+
# @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
|
441
|
+
#
|
442
|
+
# @option spec [Proc] :enum
|
443
|
+
#
|
444
|
+
# @option spec [Proc] :union
|
445
|
+
#
|
446
|
+
# @option spec [Boolean] :"nil?"
|
447
|
+
#
|
448
|
+
private def variant(key, spec = nil)
|
449
|
+
variant_info =
|
450
|
+
case key
|
451
|
+
in Symbol
|
452
|
+
[key, TerminalShop::Converter.type_info(spec)]
|
453
|
+
in Proc | TerminalShop::Converter | Class | Hash
|
454
|
+
[nil, TerminalShop::Converter.type_info(key)]
|
448
455
|
end
|
449
456
|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
457
|
+
known_variants << variant_info
|
458
|
+
end
|
459
|
+
|
460
|
+
# @private
|
461
|
+
#
|
462
|
+
# @param value [Object]
|
463
|
+
#
|
464
|
+
# @return [TerminalShop::Converter, Class, nil]
|
465
|
+
#
|
466
|
+
private def resolve_variant(value)
|
467
|
+
case [@discriminator, value]
|
468
|
+
in [_, TerminalShop::BaseModel]
|
469
|
+
value.class
|
470
|
+
in [Symbol, Hash]
|
471
|
+
key =
|
472
|
+
if value.key?(@discriminator)
|
473
|
+
value.fetch(@discriminator)
|
474
|
+
elsif value.key?((discriminator = @discriminator.to_s))
|
475
|
+
value.fetch(discriminator)
|
476
|
+
end
|
477
|
+
|
478
|
+
key = key.to_sym if key.is_a?(String)
|
479
|
+
_, resolved = known_variants.find { |k,| k == key }
|
480
|
+
resolved.nil? ? TerminalShop::Unknown : resolved.call
|
481
|
+
else
|
482
|
+
nil
|
483
|
+
end
|
455
484
|
end
|
456
485
|
end
|
457
486
|
|
@@ -478,87 +507,89 @@ module TerminalShop
|
|
478
507
|
other.is_a?(Class) && other <= TerminalShop::Union && other.variants == variants
|
479
508
|
end
|
480
509
|
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
510
|
+
class << self
|
511
|
+
# @private
|
512
|
+
#
|
513
|
+
# @param value [Object]
|
514
|
+
#
|
515
|
+
# @return [Object]
|
516
|
+
#
|
517
|
+
def coerce(value)
|
518
|
+
if (variant = resolve_variant(value))
|
519
|
+
return TerminalShop::Converter.coerce(variant, value)
|
520
|
+
end
|
491
521
|
|
492
|
-
|
522
|
+
matches = []
|
493
523
|
|
494
|
-
|
495
|
-
|
524
|
+
known_variants.each do |_, variant_fn|
|
525
|
+
variant = variant_fn.call
|
496
526
|
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
527
|
+
case TerminalShop::Converter.try_strict_coerce(variant, value)
|
528
|
+
in [true, coerced, _]
|
529
|
+
return coerced
|
530
|
+
in [false, true, score]
|
531
|
+
matches << [score, variant]
|
532
|
+
in [false, false, _]
|
533
|
+
nil
|
534
|
+
end
|
504
535
|
end
|
505
|
-
end
|
506
|
-
|
507
|
-
_, variant = matches.sort! { _2.first <=> _1.first }.find { |score,| !score.zero? }
|
508
|
-
variant.nil? ? value : TerminalShop::Converter.coerce(variant, value)
|
509
|
-
end
|
510
536
|
|
511
|
-
|
512
|
-
|
513
|
-
# @param value [Object]
|
514
|
-
#
|
515
|
-
# @return [Object]
|
516
|
-
#
|
517
|
-
def self.dump(value)
|
518
|
-
if (variant = resolve_variant(value))
|
519
|
-
return TerminalShop::Converter.dump(variant, value)
|
537
|
+
_, variant = matches.sort! { _2.first <=> _1.first }.find { |score,| !score.zero? }
|
538
|
+
variant.nil? ? value : TerminalShop::Converter.coerce(variant, value)
|
520
539
|
end
|
521
540
|
|
522
|
-
|
523
|
-
|
524
|
-
|
541
|
+
# @private
|
542
|
+
#
|
543
|
+
# @param value [Object]
|
544
|
+
#
|
545
|
+
# @return [Object]
|
546
|
+
#
|
547
|
+
def dump(value)
|
548
|
+
if (variant = resolve_variant(value))
|
525
549
|
return TerminalShop::Converter.dump(variant, value)
|
526
550
|
end
|
527
|
-
end
|
528
|
-
value
|
529
|
-
end
|
530
551
|
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
# TODO(ruby) this will result in super linear decoding behaviour for nested unions
|
539
|
-
# follow up with a decoding context that captures current strictness levels
|
540
|
-
if (variant = resolve_variant(value))
|
541
|
-
return Converter.try_strict_coerce(variant, value)
|
552
|
+
known_variants.each do |_, variant_fn|
|
553
|
+
variant = variant_fn.call
|
554
|
+
if variant === value
|
555
|
+
return TerminalShop::Converter.dump(variant, value)
|
556
|
+
end
|
557
|
+
end
|
558
|
+
value
|
542
559
|
end
|
543
560
|
|
544
|
-
|
545
|
-
|
561
|
+
# @private
|
562
|
+
#
|
563
|
+
# @param value [Object]
|
564
|
+
#
|
565
|
+
# @return [Array(true, Object, nil), Array(false, Boolean, Integer)]
|
566
|
+
#
|
567
|
+
def try_strict_coerce(value)
|
568
|
+
# TODO(ruby) this will result in super linear decoding behaviour for nested unions
|
569
|
+
# follow up with a decoding context that captures current strictness levels
|
570
|
+
if (variant = resolve_variant(value))
|
571
|
+
return Converter.try_strict_coerce(variant, value)
|
572
|
+
end
|
546
573
|
|
547
|
-
|
548
|
-
|
574
|
+
coercible = false
|
575
|
+
max_score = 0
|
549
576
|
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
577
|
+
known_variants.each do |_, variant_fn|
|
578
|
+
variant = variant_fn.call
|
579
|
+
|
580
|
+
case TerminalShop::Converter.try_strict_coerce(variant, value)
|
581
|
+
in [true, coerced, score]
|
582
|
+
return [true, coerced, score]
|
583
|
+
in [false, true, score]
|
584
|
+
coercible = true
|
585
|
+
max_score = [max_score, score].max
|
586
|
+
in [false, false, _]
|
587
|
+
nil
|
588
|
+
end
|
558
589
|
end
|
559
|
-
end
|
560
590
|
|
561
|
-
|
591
|
+
[false, coercible, max_score]
|
592
|
+
end
|
562
593
|
end
|
563
594
|
|
564
595
|
# rubocop:enable Style/CaseEquality
|
@@ -851,20 +882,18 @@ module TerminalShop
|
|
851
882
|
class BaseModel
|
852
883
|
extend TerminalShop::Converter
|
853
884
|
|
854
|
-
# @private
|
855
|
-
#
|
856
|
-
# Assumes superclass fields are totally defined before fields are accessed /
|
857
|
-
# defined on subclasses.
|
858
|
-
#
|
859
|
-
# @return [Hash{Symbol=>Hash{Symbol=>Object}}]
|
860
|
-
#
|
861
|
-
def self.known_fields
|
862
|
-
@known_fields ||= (self < TerminalShop::BaseModel ? superclass.known_fields.dup : {})
|
863
|
-
end
|
864
|
-
|
865
885
|
class << self
|
866
886
|
# @private
|
867
887
|
#
|
888
|
+
# Assumes superclass fields are totally defined before fields are accessed /
|
889
|
+
# defined on subclasses.
|
890
|
+
#
|
891
|
+
# @return [Hash{Symbol=>Hash{Symbol=>Object}}]
|
892
|
+
#
|
893
|
+
def known_fields
|
894
|
+
@known_fields ||= (self < TerminalShop::BaseModel ? superclass.known_fields.dup : {})
|
895
|
+
end
|
896
|
+
|
868
897
|
# @return [Hash{Symbol=>Hash{Symbol=>Object}}]
|
869
898
|
#
|
870
899
|
def fields
|
@@ -872,135 +901,135 @@ module TerminalShop
|
|
872
901
|
{**field.except(:type_fn), type: field.fetch(:type_fn).call}
|
873
902
|
end
|
874
903
|
end
|
875
|
-
end
|
876
904
|
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
905
|
+
# @private
|
906
|
+
#
|
907
|
+
# @return [Hash{Symbol=>Proc}]
|
908
|
+
#
|
909
|
+
def defaults = (@defaults ||= {})
|
882
910
|
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
911
|
+
# @private
|
912
|
+
#
|
913
|
+
# @param name_sym [Symbol]
|
914
|
+
#
|
915
|
+
# @param required [Boolean]
|
916
|
+
#
|
917
|
+
# @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Converter, Class]
|
918
|
+
#
|
919
|
+
# @param spec [Hash{Symbol=>Object}] .
|
920
|
+
#
|
921
|
+
# @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
|
922
|
+
#
|
923
|
+
# @option spec [Proc] :enum
|
924
|
+
#
|
925
|
+
# @option spec [Proc] :union
|
926
|
+
#
|
927
|
+
# @option spec [Boolean] :"nil?"
|
928
|
+
#
|
929
|
+
private def add_field(name_sym, required:, type_info:, spec:)
|
930
|
+
type_fn, info =
|
931
|
+
case type_info
|
932
|
+
in Proc | Class | TerminalShop::Converter
|
933
|
+
[TerminalShop::Converter.type_info({**spec, union: type_info}), spec]
|
934
|
+
in Hash
|
935
|
+
[TerminalShop::Converter.type_info(type_info), type_info]
|
936
|
+
end
|
909
937
|
|
910
|
-
|
911
|
-
|
938
|
+
fallback = info[:const]
|
939
|
+
defaults[name_sym] = fallback if required && !info[:nil?] && info.key?(:const)
|
912
940
|
|
913
|
-
|
914
|
-
|
941
|
+
key = info.fetch(:api_name, name_sym)
|
942
|
+
setter = "#{name_sym}="
|
915
943
|
|
916
|
-
|
917
|
-
|
918
|
-
|
944
|
+
if known_fields.key?(name_sym)
|
945
|
+
[name_sym, setter].each { undef_method(_1) }
|
946
|
+
end
|
919
947
|
|
920
|
-
|
948
|
+
known_fields[name_sym] = {mode: @mode, key: key, required: required, type_fn: type_fn}
|
921
949
|
|
922
|
-
|
923
|
-
|
924
|
-
|
950
|
+
define_method(setter) do |val|
|
951
|
+
@data[key] = val
|
952
|
+
end
|
925
953
|
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
954
|
+
define_method(name_sym) do
|
955
|
+
field_type = type_fn.call
|
956
|
+
value = @data.fetch(key) { self.class.defaults[key] }
|
957
|
+
TerminalShop::Converter.coerce(field_type, value)
|
958
|
+
rescue StandardError
|
959
|
+
name = self.class.name.split("::").last
|
960
|
+
raise TerminalShop::ConversionError.new(
|
961
|
+
"Failed to parse #{name}.#{name_sym} as #{field_type.inspect}. " \
|
962
|
+
"To get the unparsed API response, use #{name}[:#{key}]."
|
963
|
+
)
|
964
|
+
end
|
936
965
|
end
|
937
|
-
end
|
938
966
|
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
967
|
+
# @private
|
968
|
+
#
|
969
|
+
# @param name_sym [Symbol]
|
970
|
+
#
|
971
|
+
# @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Converter, Class]
|
972
|
+
#
|
973
|
+
# @param spec [Hash{Symbol=>Object}] .
|
974
|
+
#
|
975
|
+
# @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
|
976
|
+
#
|
977
|
+
# @option spec [Proc] :enum
|
978
|
+
#
|
979
|
+
# @option spec [Proc] :union
|
980
|
+
#
|
981
|
+
# @option spec [Boolean] :"nil?"
|
982
|
+
#
|
983
|
+
def required(name_sym, type_info, spec = {})
|
984
|
+
add_field(name_sym, required: true, type_info: type_info, spec: spec)
|
985
|
+
end
|
958
986
|
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
987
|
+
# @private
|
988
|
+
#
|
989
|
+
# @param name_sym [Symbol]
|
990
|
+
#
|
991
|
+
# @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Converter, Class]
|
992
|
+
#
|
993
|
+
# @param spec [Hash{Symbol=>Object}] .
|
994
|
+
#
|
995
|
+
# @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
|
996
|
+
#
|
997
|
+
# @option spec [Proc] :enum
|
998
|
+
#
|
999
|
+
# @option spec [Proc] :union
|
1000
|
+
#
|
1001
|
+
# @option spec [Boolean] :"nil?"
|
1002
|
+
#
|
1003
|
+
def optional(name_sym, type_info, spec = {})
|
1004
|
+
add_field(name_sym, required: false, type_info: type_info, spec: spec)
|
1005
|
+
end
|
978
1006
|
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
1007
|
+
# @private
|
1008
|
+
#
|
1009
|
+
# `request_only` attributes not excluded from `.#coerce` when receiving responses
|
1010
|
+
# even if well behaved servers should not send them
|
1011
|
+
#
|
1012
|
+
# @param blk [Proc]
|
1013
|
+
#
|
1014
|
+
private def request_only(&blk)
|
1015
|
+
@mode = :dump
|
1016
|
+
blk.call
|
1017
|
+
ensure
|
1018
|
+
@mode = nil
|
1019
|
+
end
|
992
1020
|
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1021
|
+
# @private
|
1022
|
+
#
|
1023
|
+
# `response_only` attributes are omitted from `.#dump` when making requests
|
1024
|
+
#
|
1025
|
+
# @param blk [Proc]
|
1026
|
+
#
|
1027
|
+
private def response_only(&blk)
|
1028
|
+
@mode = :coerce
|
1029
|
+
blk.call
|
1030
|
+
ensure
|
1031
|
+
@mode = nil
|
1032
|
+
end
|
1004
1033
|
end
|
1005
1034
|
|
1006
1035
|
# @param other [Object]
|
@@ -1016,108 +1045,110 @@ module TerminalShop
|
|
1016
1045
|
end
|
1017
1046
|
end
|
1018
1047
|
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1048
|
+
class << self
|
1049
|
+
# @private
|
1050
|
+
#
|
1051
|
+
# @param value [TerminalShop::BaseModel, Hash{Object=>Object}, Object]
|
1052
|
+
#
|
1053
|
+
# @return [TerminalShop::BaseModel, Object]
|
1054
|
+
#
|
1055
|
+
def coerce(value)
|
1056
|
+
case TerminalShop::Util.coerce_hash(value)
|
1057
|
+
in Hash => coerced
|
1058
|
+
new(coerced)
|
1059
|
+
else
|
1060
|
+
value
|
1061
|
+
end
|
1031
1062
|
end
|
1032
|
-
end
|
1033
1063
|
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1064
|
+
# @private
|
1065
|
+
#
|
1066
|
+
# @param value [TerminalShop::BaseModel, Object]
|
1067
|
+
#
|
1068
|
+
# @return [Hash{Object=>Object}, Object]
|
1069
|
+
#
|
1070
|
+
def dump(value)
|
1071
|
+
unless (coerced = TerminalShop::Util.coerce_hash(value)).is_a?(Hash)
|
1072
|
+
return value
|
1073
|
+
end
|
1044
1074
|
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
else
|
1051
|
-
mode, type_fn, api_name = field.fetch_values(:mode, :type_fn, :key)
|
1052
|
-
case mode
|
1053
|
-
in :coerce
|
1054
|
-
next
|
1075
|
+
values = coerced.filter_map do |key, val|
|
1076
|
+
name = key.to_sym
|
1077
|
+
case (field = known_fields[name])
|
1078
|
+
in nil
|
1079
|
+
[name, val]
|
1055
1080
|
else
|
1056
|
-
|
1057
|
-
|
1081
|
+
mode, type_fn, api_name = field.fetch_values(:mode, :type_fn, :key)
|
1082
|
+
case mode
|
1083
|
+
in :coerce
|
1084
|
+
next
|
1085
|
+
else
|
1086
|
+
target = type_fn.call
|
1087
|
+
[api_name, TerminalShop::Converter.dump(target, val)]
|
1088
|
+
end
|
1058
1089
|
end
|
1059
|
-
end
|
1060
|
-
end.to_h
|
1061
|
-
|
1062
|
-
defaults.each do |key, val|
|
1063
|
-
next if values.key?(key)
|
1090
|
+
end.to_h
|
1064
1091
|
|
1065
|
-
|
1066
|
-
|
1092
|
+
defaults.each do |key, val|
|
1093
|
+
next if values.key?(key)
|
1067
1094
|
|
1068
|
-
|
1069
|
-
|
1095
|
+
values[key] = val
|
1096
|
+
end
|
1070
1097
|
|
1071
|
-
|
1072
|
-
#
|
1073
|
-
# @param value [Object]
|
1074
|
-
#
|
1075
|
-
# @return [Array(true, Object, nil), Array(false, Boolean, Integer)]
|
1076
|
-
#
|
1077
|
-
def self.try_strict_coerce(value)
|
1078
|
-
case value
|
1079
|
-
in Hash | TerminalShop::BaseModel
|
1080
|
-
value = value.to_h
|
1081
|
-
else
|
1082
|
-
return [false, false, 0]
|
1098
|
+
values
|
1083
1099
|
end
|
1084
1100
|
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1101
|
+
# @private
|
1102
|
+
#
|
1103
|
+
# @param value [Object]
|
1104
|
+
#
|
1105
|
+
# @return [Array(true, Object, nil), Array(false, Boolean, Integer)]
|
1106
|
+
#
|
1107
|
+
def try_strict_coerce(value)
|
1108
|
+
case value
|
1109
|
+
in Hash | TerminalShop::BaseModel
|
1110
|
+
value = value.to_h
|
1111
|
+
else
|
1112
|
+
return [false, false, 0]
|
1113
|
+
end
|
1089
1114
|
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1115
|
+
keys = value.keys.to_set
|
1116
|
+
great_success = true
|
1117
|
+
tally = 0
|
1118
|
+
acc = {}
|
1093
1119
|
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
case
|
1099
|
-
in [
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1120
|
+
known_fields.each_value do |field|
|
1121
|
+
mode, required, type_fn, api_name = field.fetch_values(:mode, :required, :type_fn, :key)
|
1122
|
+
keys.delete(api_name)
|
1123
|
+
|
1124
|
+
case [required && mode != :dump, value.key?(api_name)]
|
1125
|
+
in [_, true]
|
1126
|
+
target = type_fn.call
|
1127
|
+
item = value.fetch(api_name)
|
1128
|
+
case TerminalShop::Converter.try_strict_coerce(target, item)
|
1129
|
+
in [true, coerced, score]
|
1130
|
+
tally += score
|
1131
|
+
acc[api_name] = coerced
|
1132
|
+
in [false, true, score]
|
1133
|
+
great_success = false
|
1134
|
+
tally += score
|
1135
|
+
acc[api_name] = item
|
1136
|
+
in [false, false, _]
|
1137
|
+
great_success &&= item.nil?
|
1138
|
+
end
|
1139
|
+
in [true, false]
|
1103
1140
|
great_success = false
|
1104
|
-
|
1105
|
-
|
1106
|
-
in [false, false, _]
|
1107
|
-
great_success &&= item.nil?
|
1141
|
+
in [false, false]
|
1142
|
+
nil
|
1108
1143
|
end
|
1109
|
-
in [true, false]
|
1110
|
-
great_success = false
|
1111
|
-
in [false, false]
|
1112
|
-
nil
|
1113
1144
|
end
|
1114
|
-
end
|
1115
1145
|
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1146
|
+
keys.each do |key|
|
1147
|
+
acc[key] = value.fetch(key)
|
1148
|
+
end
|
1119
1149
|
|
1120
|
-
|
1150
|
+
great_success ? [true, new(acc), tally] : [false, true, tally]
|
1151
|
+
end
|
1121
1152
|
end
|
1122
1153
|
|
1123
1154
|
# Returns the raw value associated with the given key, if found. Otherwise, nil is
|