terminal-shop 1.0.0 → 1.1.0

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