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.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +27 -19
  3. data/lib/terminal-shop/base_client.rb +2 -0
  4. data/lib/terminal-shop/base_model.rb +471 -440
  5. data/lib/terminal-shop/base_page.rb +20 -0
  6. data/lib/terminal-shop/models/cart.rb +35 -2
  7. data/lib/terminal-shop/models/cart_convert_params.rb +11 -1
  8. data/lib/terminal-shop/models/cart_redeem_gift_card_params.rb +24 -0
  9. data/lib/terminal-shop/models/cart_redeem_gift_card_response.rb +48 -0
  10. data/lib/terminal-shop/models/cart_remove_gift_card_params.rb +18 -0
  11. data/lib/terminal-shop/models/cart_remove_gift_card_response.rb +19 -0
  12. data/lib/terminal-shop/models/product.rb +11 -6
  13. data/lib/terminal-shop/pooled_net_requester.rb +23 -10
  14. data/lib/terminal-shop/resources/cart.rb +43 -1
  15. data/lib/terminal-shop/util.rb +146 -52
  16. data/lib/terminal-shop/version.rb +1 -1
  17. data/lib/terminal-shop.rb +4 -0
  18. data/rbi/lib/terminal-shop/base_client.rbi +23 -21
  19. data/rbi/lib/terminal-shop/base_model.rbi +235 -217
  20. data/rbi/lib/terminal-shop/client.rbi +2 -2
  21. data/rbi/lib/terminal-shop/errors.rbi +8 -8
  22. data/rbi/lib/terminal-shop/models/address.rbi +2 -2
  23. data/rbi/lib/terminal-shop/models/address_create_params.rbi +3 -13
  24. data/rbi/lib/terminal-shop/models/address_create_response.rbi +2 -2
  25. data/rbi/lib/terminal-shop/models/address_delete_params.rbi +5 -2
  26. data/rbi/lib/terminal-shop/models/address_delete_response.rbi +2 -2
  27. data/rbi/lib/terminal-shop/models/address_get_params.rbi +5 -2
  28. data/rbi/lib/terminal-shop/models/address_get_response.rbi +2 -2
  29. data/rbi/lib/terminal-shop/models/address_list_params.rbi +5 -2
  30. data/rbi/lib/terminal-shop/models/address_list_response.rbi +2 -2
  31. data/rbi/lib/terminal-shop/models/app.rbi +2 -2
  32. data/rbi/lib/terminal-shop/models/app_create_params.rbi +2 -2
  33. data/rbi/lib/terminal-shop/models/app_create_response.rbi +4 -4
  34. data/rbi/lib/terminal-shop/models/app_delete_params.rbi +5 -2
  35. data/rbi/lib/terminal-shop/models/app_delete_response.rbi +2 -2
  36. data/rbi/lib/terminal-shop/models/app_get_params.rbi +5 -2
  37. data/rbi/lib/terminal-shop/models/app_get_response.rbi +2 -2
  38. data/rbi/lib/terminal-shop/models/app_list_params.rbi +5 -2
  39. data/rbi/lib/terminal-shop/models/app_list_response.rbi +2 -2
  40. data/rbi/lib/terminal-shop/models/card.rbi +4 -4
  41. data/rbi/lib/terminal-shop/models/card_collect_params.rbi +5 -2
  42. data/rbi/lib/terminal-shop/models/card_collect_response.rbi +4 -4
  43. data/rbi/lib/terminal-shop/models/card_create_params.rbi +2 -2
  44. data/rbi/lib/terminal-shop/models/card_create_response.rbi +2 -2
  45. data/rbi/lib/terminal-shop/models/card_delete_params.rbi +5 -2
  46. data/rbi/lib/terminal-shop/models/card_delete_response.rbi +2 -2
  47. data/rbi/lib/terminal-shop/models/card_get_params.rbi +5 -2
  48. data/rbi/lib/terminal-shop/models/card_get_response.rbi +2 -2
  49. data/rbi/lib/terminal-shop/models/card_list_params.rbi +5 -2
  50. data/rbi/lib/terminal-shop/models/card_list_response.rbi +2 -2
  51. data/rbi/lib/terminal-shop/models/cart.rbi +45 -9
  52. data/rbi/lib/terminal-shop/models/cart_convert_params.rbi +17 -3
  53. data/rbi/lib/terminal-shop/models/cart_convert_response.rbi +2 -2
  54. data/rbi/lib/terminal-shop/models/cart_get_params.rbi +5 -2
  55. data/rbi/lib/terminal-shop/models/cart_get_response.rbi +2 -2
  56. data/rbi/lib/terminal-shop/models/cart_redeem_gift_card_params.rbi +32 -0
  57. data/rbi/lib/terminal-shop/models/cart_redeem_gift_card_response.rbi +66 -0
  58. data/rbi/lib/terminal-shop/models/cart_remove_gift_card_params.rbi +21 -0
  59. data/rbi/lib/terminal-shop/models/cart_remove_gift_card_response.rbi +23 -0
  60. data/rbi/lib/terminal-shop/models/cart_set_address_params.rbi +2 -2
  61. data/rbi/lib/terminal-shop/models/cart_set_address_response.rbi +2 -2
  62. data/rbi/lib/terminal-shop/models/cart_set_card_params.rbi +2 -2
  63. data/rbi/lib/terminal-shop/models/cart_set_card_response.rbi +2 -2
  64. data/rbi/lib/terminal-shop/models/cart_set_item_params.rbi +2 -2
  65. data/rbi/lib/terminal-shop/models/cart_set_item_response.rbi +2 -2
  66. data/rbi/lib/terminal-shop/models/email_create_params.rbi +2 -2
  67. data/rbi/lib/terminal-shop/models/email_create_response.rbi +2 -2
  68. data/rbi/lib/terminal-shop/models/order.rbi +10 -10
  69. data/rbi/lib/terminal-shop/models/order_create_params.rbi +2 -2
  70. data/rbi/lib/terminal-shop/models/order_create_response.rbi +2 -2
  71. data/rbi/lib/terminal-shop/models/order_get_params.rbi +5 -2
  72. data/rbi/lib/terminal-shop/models/order_get_response.rbi +2 -2
  73. data/rbi/lib/terminal-shop/models/order_list_params.rbi +5 -2
  74. data/rbi/lib/terminal-shop/models/order_list_response.rbi +2 -2
  75. data/rbi/lib/terminal-shop/models/product.rbi +29 -14
  76. data/rbi/lib/terminal-shop/models/product_get_params.rbi +5 -2
  77. data/rbi/lib/terminal-shop/models/product_get_response.rbi +2 -2
  78. data/rbi/lib/terminal-shop/models/product_list_params.rbi +5 -2
  79. data/rbi/lib/terminal-shop/models/product_list_response.rbi +2 -2
  80. data/rbi/lib/terminal-shop/models/product_variant.rbi +2 -2
  81. data/rbi/lib/terminal-shop/models/profile.rbi +4 -4
  82. data/rbi/lib/terminal-shop/models/profile_me_params.rbi +5 -2
  83. data/rbi/lib/terminal-shop/models/profile_me_response.rbi +2 -2
  84. data/rbi/lib/terminal-shop/models/profile_update_params.rbi +2 -2
  85. data/rbi/lib/terminal-shop/models/profile_update_response.rbi +2 -2
  86. data/rbi/lib/terminal-shop/models/subscription.rbi +15 -13
  87. data/rbi/lib/terminal-shop/models/subscription_create_params.rbi +5 -2
  88. data/rbi/lib/terminal-shop/models/subscription_create_response.rbi +2 -2
  89. data/rbi/lib/terminal-shop/models/subscription_delete_params.rbi +5 -2
  90. data/rbi/lib/terminal-shop/models/subscription_delete_response.rbi +2 -2
  91. data/rbi/lib/terminal-shop/models/subscription_get_params.rbi +5 -2
  92. data/rbi/lib/terminal-shop/models/subscription_get_response.rbi +2 -2
  93. data/rbi/lib/terminal-shop/models/subscription_list_params.rbi +5 -2
  94. data/rbi/lib/terminal-shop/models/subscription_list_response.rbi +2 -2
  95. data/rbi/lib/terminal-shop/models/token.rbi +2 -2
  96. data/rbi/lib/terminal-shop/models/token_create_params.rbi +5 -2
  97. data/rbi/lib/terminal-shop/models/token_create_response.rbi +4 -4
  98. data/rbi/lib/terminal-shop/models/token_delete_params.rbi +5 -2
  99. data/rbi/lib/terminal-shop/models/token_delete_response.rbi +2 -2
  100. data/rbi/lib/terminal-shop/models/token_get_params.rbi +5 -2
  101. data/rbi/lib/terminal-shop/models/token_get_response.rbi +2 -2
  102. data/rbi/lib/terminal-shop/models/token_list_params.rbi +5 -2
  103. data/rbi/lib/terminal-shop/models/token_list_response.rbi +2 -2
  104. data/rbi/lib/terminal-shop/models/view_init_params.rbi +5 -2
  105. data/rbi/lib/terminal-shop/models/view_init_response.rbi +5 -15
  106. data/rbi/lib/terminal-shop/pooled_net_requester.rbi +15 -10
  107. data/rbi/lib/terminal-shop/request_options.rbi +4 -0
  108. data/rbi/lib/terminal-shop/resources/address.rbi +2 -2
  109. data/rbi/lib/terminal-shop/resources/app.rbi +2 -2
  110. data/rbi/lib/terminal-shop/resources/card.rbi +2 -2
  111. data/rbi/lib/terminal-shop/resources/cart.rbi +24 -4
  112. data/rbi/lib/terminal-shop/resources/email.rbi +2 -2
  113. data/rbi/lib/terminal-shop/resources/order.rbi +2 -2
  114. data/rbi/lib/terminal-shop/resources/product.rbi +2 -2
  115. data/rbi/lib/terminal-shop/resources/profile.rbi +2 -2
  116. data/rbi/lib/terminal-shop/resources/subscription.rbi +2 -2
  117. data/rbi/lib/terminal-shop/resources/token.rbi +2 -2
  118. data/rbi/lib/terminal-shop/resources/view.rbi +2 -2
  119. data/rbi/lib/terminal-shop/util.rbi +181 -126
  120. data/rbi/lib/terminal-shop/version.rbi +1 -1
  121. data/sig/terminal-shop/models/cart.rbs +27 -2
  122. data/sig/terminal-shop/models/cart_convert_params.rbs +10 -2
  123. data/sig/terminal-shop/models/cart_redeem_gift_card_params.rbs +25 -0
  124. data/sig/terminal-shop/models/cart_redeem_gift_card_response.rbs +47 -0
  125. data/sig/terminal-shop/models/cart_remove_gift_card_params.rbs +19 -0
  126. data/sig/terminal-shop/models/cart_remove_gift_card_response.rbs +18 -0
  127. data/sig/terminal-shop/models/product.rbs +8 -2
  128. data/sig/terminal-shop/pooled_net_requester.rbs +4 -2
  129. data/sig/terminal-shop/request_options.rbs +4 -0
  130. data/sig/terminal-shop/resources/cart.rbs +20 -0
  131. data/sig/terminal-shop/util.rbs +27 -2
  132. data/sig/terminal-shop/version.rbs +1 -1
  133. 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 | true | false | Symbol | Integer | Float
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, Date::Error
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
- # @!parse
196
- # # @private
197
- # #
198
- # # @param value [Object]
199
- # #
200
- # # @return [Object]
201
- # #
202
- # def self.coerce(value) = super
203
-
204
- # @!parse
205
- # # @private
206
- # #
207
- # # @param value [Object]
208
- # #
209
- # # @return [Object]
210
- # #
211
- # def self.dump(value) = super
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
- # @private
214
- #
215
- # @param value [Object]
216
- #
217
- # @return [Array(true, Object, nil), Array(false, Boolean, Integer)]
218
- #
219
- def self.try_strict_coerce(value)
220
- # prevent unknown variant from being chosen during the first coercion pass
221
- [false, true, 0]
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
- # @!parse
250
- # # @private
251
- # #
252
- # # @param value [Boolean, Object]
253
- # #
254
- # # @return [Boolean, Object]
255
- # #
256
- # def self.coerce(value) = super
257
-
258
- # @!parse
259
- # # @private
260
- # #
261
- # # @param value [Boolean, Object]
262
- # #
263
- # # @return [Boolean, Object]
264
- # #
265
- # def self.dump(value) = super
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
- # @private
268
- #
269
- # @param value [Object]
270
- #
271
- # @return [Array(true, Object, nil), Array(false, Boolean, Integer)]
272
- #
273
- def self.try_strict_coerce(value)
274
- case value
275
- in true | false
276
- [true, value, 1]
277
- else
278
- [false, false, 0]
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
- # All of the valid Symbol values for this enum.
301
- #
302
- # @return [Array<NilClass, Boolean, Integer, Float, Symbol>]
303
- #
304
- def self.values = (@values ||= constants.map { const_get(_1) })
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
- # @private
307
- #
308
- # Guard against thread safety issues by instantiating `@values`.
309
- #
310
- private_class_method def self.finalize! = values
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
- # @private
329
- #
330
- # @param value [String, Symbol, Object]
331
- #
332
- # @return [Symbol, Object]
333
- #
334
- def self.coerce(value) = (value.is_a?(String) ? value.to_sym : value)
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
- # @!parse
337
- # # @private
338
- # #
339
- # # @param value [Symbol, Object]
340
- # #
341
- # # @return [Symbol, Object]
342
- # #
343
- # def self.dump(value) = super
364
+ # @!parse
365
+ # # @private
366
+ # #
367
+ # # @param value [Symbol, Object]
368
+ # #
369
+ # # @return [Symbol, Object]
370
+ # #
371
+ # def dump(value) = super
344
372
 
345
- # @private
346
- #
347
- # @param value [Object]
348
- #
349
- # @return [Array(true, Object, nil), Array(false, Boolean, Integer)]
350
- #
351
- def self.try_strict_coerce(value)
352
- return [true, value, 1] if values.include?(value)
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
- case value
355
- in String if values.include?(val = value.to_sym)
356
- [true, val, 1]
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
- [false, false, 0]
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
- # @private
396
- #
397
- # @param property [Symbol]
398
- #
399
- private_class_method def self.discriminator(property)
400
- case property
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
- [key, TerminalShop::Converter.type_info(spec)]
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
- known_variants << variant_info
430
- end
431
-
432
- # @private
433
- #
434
- # @param value [Object]
435
- #
436
- # @return [TerminalShop::Converter, Class, nil]
437
- #
438
- private_class_method def self.resolve_variant(value)
439
- case [@discriminator, value]
440
- in [_, TerminalShop::BaseModel]
441
- value.class
442
- in [Symbol, Hash]
443
- key =
444
- if value.key?(@discriminator)
445
- value.fetch(@discriminator)
446
- elsif value.key?((discriminator = @discriminator.to_s))
447
- value.fetch(discriminator)
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
- key = key.to_sym if key.is_a?(String)
451
- _, resolved = known_variants.find { |k,| k == key }
452
- resolved.nil? ? TerminalShop::Unknown : resolved.call
453
- else
454
- nil
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
- # @private
482
- #
483
- # @param value [Object]
484
- #
485
- # @return [Object]
486
- #
487
- def self.coerce(value)
488
- if (variant = resolve_variant(value))
489
- return TerminalShop::Converter.coerce(variant, value)
490
- end
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
- matches = []
522
+ matches = []
493
523
 
494
- known_variants.each do |_, variant_fn|
495
- variant = variant_fn.call
524
+ known_variants.each do |_, variant_fn|
525
+ variant = variant_fn.call
496
526
 
497
- case TerminalShop::Converter.try_strict_coerce(variant, value)
498
- in [true, coerced, _]
499
- return coerced
500
- in [false, true, score]
501
- matches << [score, variant]
502
- in [false, false, _]
503
- nil
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
- # @private
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
- known_variants.each do |_, variant_fn|
523
- variant = variant_fn.call
524
- if variant === value
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
- # @private
532
- #
533
- # @param value [Object]
534
- #
535
- # @return [Array(true, Object, nil), Array(false, Boolean, Integer)]
536
- #
537
- def self.try_strict_coerce(value)
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
- coercible = false
545
- max_score = 0
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
- known_variants.each do |_, variant_fn|
548
- variant = variant_fn.call
574
+ coercible = false
575
+ max_score = 0
549
576
 
550
- case TerminalShop::Converter.try_strict_coerce(variant, value)
551
- in [true, coerced, score]
552
- return [true, coerced, score]
553
- in [false, true, score]
554
- coercible = true
555
- max_score = [max_score, score].max
556
- in [false, false, _]
557
- nil
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
- [false, coercible, max_score]
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
- # @private
878
- #
879
- # @return [Hash{Symbol=>Proc}]
880
- #
881
- def self.defaults = (@defaults ||= {})
905
+ # @private
906
+ #
907
+ # @return [Hash{Symbol=>Proc}]
908
+ #
909
+ def defaults = (@defaults ||= {})
882
910
 
883
- # @private
884
- #
885
- # @param name_sym [Symbol]
886
- #
887
- # @param required [Boolean]
888
- #
889
- # @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Converter, Class]
890
- #
891
- # @param spec [Hash{Symbol=>Object}] .
892
- #
893
- # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
894
- #
895
- # @option spec [Proc] :enum
896
- #
897
- # @option spec [Proc] :union
898
- #
899
- # @option spec [Boolean] :"nil?"
900
- #
901
- private_class_method def self.add_field(name_sym, required:, type_info:, spec:)
902
- type_fn, info =
903
- case type_info
904
- in Proc | Class | TerminalShop::Converter
905
- [TerminalShop::Converter.type_info({**spec, union: type_info}), spec]
906
- in Hash
907
- [TerminalShop::Converter.type_info(type_info), type_info]
908
- end
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
- fallback = info[:const]
911
- defaults[name_sym] = fallback if required && !info[:nil?] && info.key?(:const)
938
+ fallback = info[:const]
939
+ defaults[name_sym] = fallback if required && !info[:nil?] && info.key?(:const)
912
940
 
913
- key = info.fetch(:api_name, name_sym)
914
- setter = "#{name_sym}="
941
+ key = info.fetch(:api_name, name_sym)
942
+ setter = "#{name_sym}="
915
943
 
916
- if known_fields.key?(name_sym)
917
- [name_sym, setter].each { undef_method(_1) }
918
- end
944
+ if known_fields.key?(name_sym)
945
+ [name_sym, setter].each { undef_method(_1) }
946
+ end
919
947
 
920
- known_fields[name_sym] = {mode: @mode, key: key, required: required, type_fn: type_fn}
948
+ known_fields[name_sym] = {mode: @mode, key: key, required: required, type_fn: type_fn}
921
949
 
922
- define_method(setter) do |val|
923
- @data[key] = val
924
- end
950
+ define_method(setter) do |val|
951
+ @data[key] = val
952
+ end
925
953
 
926
- define_method(name_sym) do
927
- field_type = type_fn.call
928
- value = @data.fetch(key) { self.class.defaults[key] }
929
- TerminalShop::Converter.coerce(field_type, value)
930
- rescue StandardError
931
- name = self.class.name.split("::").last
932
- raise TerminalShop::ConversionError.new(
933
- "Failed to parse #{name}.#{name_sym} as #{field_type.inspect}. " \
934
- "To get the unparsed API response, use #{name}[:#{key}]."
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
- # @private
940
- #
941
- # @param name_sym [Symbol]
942
- #
943
- # @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Converter, Class]
944
- #
945
- # @param spec [Hash{Symbol=>Object}] .
946
- #
947
- # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
948
- #
949
- # @option spec [Proc] :enum
950
- #
951
- # @option spec [Proc] :union
952
- #
953
- # @option spec [Boolean] :"nil?"
954
- #
955
- def self.required(name_sym, type_info, spec = {})
956
- add_field(name_sym, required: true, type_info: type_info, spec: spec)
957
- end
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
- # @private
960
- #
961
- # @param name_sym [Symbol]
962
- #
963
- # @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Converter, Class]
964
- #
965
- # @param spec [Hash{Symbol=>Object}] .
966
- #
967
- # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
968
- #
969
- # @option spec [Proc] :enum
970
- #
971
- # @option spec [Proc] :union
972
- #
973
- # @option spec [Boolean] :"nil?"
974
- #
975
- def self.optional(name_sym, type_info, spec = {})
976
- add_field(name_sym, required: false, type_info: type_info, spec: spec)
977
- end
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
- # @private
980
- #
981
- # `request_only` attributes not excluded from `.#coerce` when receiving responses
982
- # even if well behaved servers should not send them
983
- #
984
- # @param blk [Proc]
985
- #
986
- private_class_method def self.request_only(&blk)
987
- @mode = :dump
988
- blk.call
989
- ensure
990
- @mode = nil
991
- end
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
- # @private
994
- #
995
- # `response_only` attributes are omitted from `.#dump` when making requests
996
- #
997
- # @param blk [Proc]
998
- #
999
- private_class_method def self.response_only(&blk)
1000
- @mode = :coerce
1001
- blk.call
1002
- ensure
1003
- @mode = nil
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
- # @private
1020
- #
1021
- # @param value [TerminalShop::BaseModel, Hash{Object=>Object}, Object]
1022
- #
1023
- # @return [TerminalShop::BaseModel, Object]
1024
- #
1025
- def self.coerce(value)
1026
- case TerminalShop::Util.coerce_hash(value)
1027
- in Hash => coerced
1028
- new(coerced)
1029
- else
1030
- value
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
- # @private
1035
- #
1036
- # @param value [TerminalShop::BaseModel, Object]
1037
- #
1038
- # @return [Hash{Object=>Object}, Object]
1039
- #
1040
- def self.dump(value)
1041
- unless (coerced = TerminalShop::Util.coerce_hash(value)).is_a?(Hash)
1042
- return value
1043
- end
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
- values = coerced.filter_map do |key, val|
1046
- name = key.to_sym
1047
- case (field = known_fields[name])
1048
- in nil
1049
- [name, val]
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
- target = type_fn.call
1057
- [api_name, TerminalShop::Converter.dump(target, val)]
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
- values[key] = val
1066
- end
1092
+ defaults.each do |key, val|
1093
+ next if values.key?(key)
1067
1094
 
1068
- values
1069
- end
1095
+ values[key] = val
1096
+ end
1070
1097
 
1071
- # @private
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
- keys = value.keys.to_set
1086
- great_success = true
1087
- tally = 0
1088
- acc = {}
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
- known_fields.each_value do |field|
1091
- mode, required, type_fn, api_name = field.fetch_values(:mode, :required, :type_fn, :key)
1092
- keys.delete(api_name)
1115
+ keys = value.keys.to_set
1116
+ great_success = true
1117
+ tally = 0
1118
+ acc = {}
1093
1119
 
1094
- case [required && mode != :dump, value.key?(api_name)]
1095
- in [_, true]
1096
- target = type_fn.call
1097
- item = value.fetch(api_name)
1098
- case TerminalShop::Converter.try_strict_coerce(target, item)
1099
- in [true, coerced, score]
1100
- tally += score
1101
- acc[api_name] = coerced
1102
- in [false, true, score]
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
- tally += score
1105
- acc[api_name] = item
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
- keys.each do |key|
1117
- acc[key] = value.fetch(key)
1118
- end
1146
+ keys.each do |key|
1147
+ acc[key] = value.fetch(key)
1148
+ end
1119
1149
 
1120
- great_success ? [true, new(acc), tally] : [false, true, tally]
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