terminal-shop 2.0.0 → 2.1.1

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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -8
  3. data/lib/terminal-shop/client.rb +4 -4
  4. data/lib/terminal-shop/models/address_create_params.rb +1 -1
  5. data/lib/terminal-shop/models/address_delete_params.rb +1 -1
  6. data/lib/terminal-shop/models/address_get_params.rb +1 -1
  7. data/lib/terminal-shop/models/address_list_params.rb +1 -1
  8. data/lib/terminal-shop/models/app_create_params.rb +1 -1
  9. data/lib/terminal-shop/models/app_delete_params.rb +1 -1
  10. data/lib/terminal-shop/models/app_get_params.rb +1 -1
  11. data/lib/terminal-shop/models/app_list_params.rb +1 -1
  12. data/lib/terminal-shop/models/card_collect_params.rb +1 -1
  13. data/lib/terminal-shop/models/card_create_params.rb +1 -1
  14. data/lib/terminal-shop/models/card_delete_params.rb +1 -1
  15. data/lib/terminal-shop/models/card_get_params.rb +1 -1
  16. data/lib/terminal-shop/models/card_list_params.rb +1 -1
  17. data/lib/terminal-shop/models/cart_clear_params.rb +1 -1
  18. data/lib/terminal-shop/models/cart_convert_params.rb +1 -1
  19. data/lib/terminal-shop/models/cart_get_params.rb +1 -1
  20. data/lib/terminal-shop/models/cart_set_address_params.rb +1 -1
  21. data/lib/terminal-shop/models/cart_set_card_params.rb +1 -1
  22. data/lib/terminal-shop/models/cart_set_item_params.rb +1 -1
  23. data/lib/terminal-shop/models/email_create_params.rb +1 -1
  24. data/lib/terminal-shop/models/order_create_params.rb +1 -1
  25. data/lib/terminal-shop/models/order_get_params.rb +1 -1
  26. data/lib/terminal-shop/models/order_list_params.rb +1 -1
  27. data/lib/terminal-shop/models/product_get_params.rb +1 -1
  28. data/lib/terminal-shop/models/product_list_params.rb +1 -1
  29. data/lib/terminal-shop/models/profile_me_params.rb +1 -1
  30. data/lib/terminal-shop/models/profile_update_params.rb +1 -1
  31. data/lib/terminal-shop/models/subscription_create_params.rb +1 -1
  32. data/lib/terminal-shop/models/subscription_delete_params.rb +1 -1
  33. data/lib/terminal-shop/models/subscription_get_params.rb +1 -1
  34. data/lib/terminal-shop/models/subscription_list_params.rb +1 -1
  35. data/lib/terminal-shop/models/token_create_params.rb +1 -1
  36. data/lib/terminal-shop/models/token_delete_params.rb +1 -1
  37. data/lib/terminal-shop/models/token_get_params.rb +1 -1
  38. data/lib/terminal-shop/models/token_list_params.rb +1 -1
  39. data/lib/terminal-shop/models/view_init_params.rb +1 -1
  40. data/lib/terminal-shop/request_options.rb +0 -33
  41. data/lib/terminal-shop/transport/base_client.rb +459 -0
  42. data/lib/terminal-shop/transport/pooled_net_requester.rb +182 -0
  43. data/lib/terminal-shop/type/array_of.rb +112 -0
  44. data/lib/terminal-shop/type/base_model.rb +364 -0
  45. data/lib/terminal-shop/type/base_page.rb +61 -0
  46. data/lib/terminal-shop/type/boolean_model.rb +52 -0
  47. data/lib/terminal-shop/type/converter.rb +217 -0
  48. data/lib/terminal-shop/type/enum.rb +101 -0
  49. data/lib/terminal-shop/type/hash_of.rb +138 -0
  50. data/lib/terminal-shop/type/request_parameters.rb +38 -0
  51. data/lib/terminal-shop/type/union.rb +185 -0
  52. data/lib/terminal-shop/type/unknown.rb +56 -0
  53. data/lib/terminal-shop/type.rb +23 -0
  54. data/lib/terminal-shop/util.rb +3 -5
  55. data/lib/terminal-shop/version.rb +1 -1
  56. data/lib/terminal-shop.rb +29 -20
  57. data/manifest.yaml +1 -0
  58. data/rbi/lib/terminal-shop/client.rbi +4 -4
  59. data/rbi/lib/terminal-shop/models/address_create_params.rbi +12 -2
  60. data/rbi/lib/terminal-shop/models/address_delete_params.rbi +1 -1
  61. data/rbi/lib/terminal-shop/models/address_get_params.rbi +1 -1
  62. data/rbi/lib/terminal-shop/models/address_list_params.rbi +1 -1
  63. data/rbi/lib/terminal-shop/models/app_create_params.rbi +1 -1
  64. data/rbi/lib/terminal-shop/models/app_delete_params.rbi +1 -1
  65. data/rbi/lib/terminal-shop/models/app_get_params.rbi +1 -1
  66. data/rbi/lib/terminal-shop/models/app_list_params.rbi +1 -1
  67. data/rbi/lib/terminal-shop/models/card_collect_params.rbi +1 -1
  68. data/rbi/lib/terminal-shop/models/card_create_params.rbi +1 -1
  69. data/rbi/lib/terminal-shop/models/card_delete_params.rbi +1 -1
  70. data/rbi/lib/terminal-shop/models/card_get_params.rbi +1 -1
  71. data/rbi/lib/terminal-shop/models/card_list_params.rbi +1 -1
  72. data/rbi/lib/terminal-shop/models/cart_clear_params.rbi +1 -1
  73. data/rbi/lib/terminal-shop/models/cart_convert_params.rbi +1 -1
  74. data/rbi/lib/terminal-shop/models/cart_get_params.rbi +1 -1
  75. data/rbi/lib/terminal-shop/models/cart_set_address_params.rbi +1 -1
  76. data/rbi/lib/terminal-shop/models/cart_set_card_params.rbi +1 -1
  77. data/rbi/lib/terminal-shop/models/cart_set_item_params.rbi +1 -1
  78. data/rbi/lib/terminal-shop/models/email_create_params.rbi +1 -1
  79. data/rbi/lib/terminal-shop/models/order_create_params.rbi +1 -1
  80. data/rbi/lib/terminal-shop/models/order_get_params.rbi +1 -1
  81. data/rbi/lib/terminal-shop/models/order_list_params.rbi +1 -1
  82. data/rbi/lib/terminal-shop/models/product_get_params.rbi +1 -1
  83. data/rbi/lib/terminal-shop/models/product_list_params.rbi +1 -1
  84. data/rbi/lib/terminal-shop/models/profile_me_params.rbi +1 -1
  85. data/rbi/lib/terminal-shop/models/profile_update_params.rbi +1 -1
  86. data/rbi/lib/terminal-shop/models/subscription_create_params.rbi +1 -1
  87. data/rbi/lib/terminal-shop/models/subscription_delete_params.rbi +1 -1
  88. data/rbi/lib/terminal-shop/models/subscription_get_params.rbi +1 -1
  89. data/rbi/lib/terminal-shop/models/subscription_list_params.rbi +1 -1
  90. data/rbi/lib/terminal-shop/models/token_create_params.rbi +1 -1
  91. data/rbi/lib/terminal-shop/models/token_delete_params.rbi +1 -1
  92. data/rbi/lib/terminal-shop/models/token_get_params.rbi +1 -1
  93. data/rbi/lib/terminal-shop/models/token_list_params.rbi +1 -1
  94. data/rbi/lib/terminal-shop/models/view_init_params.rbi +1 -1
  95. data/rbi/lib/terminal-shop/models/view_init_response.rbi +12 -1
  96. data/rbi/lib/terminal-shop/request_options.rbi +0 -15
  97. data/rbi/lib/terminal-shop/transport/base_client.rbi +208 -0
  98. data/rbi/lib/terminal-shop/transport/pooled_net_requester.rbi +64 -0
  99. data/rbi/lib/terminal-shop/type/array_of.rbi +82 -0
  100. data/rbi/lib/terminal-shop/type/base_model.rbi +194 -0
  101. data/rbi/lib/terminal-shop/type/base_page.rbi +38 -0
  102. data/rbi/lib/terminal-shop/type/boolean_model.rbi +41 -0
  103. data/rbi/lib/terminal-shop/type/converter.rbi +101 -0
  104. data/rbi/lib/terminal-shop/type/enum.rbi +58 -0
  105. data/rbi/lib/terminal-shop/type/hash_of.rbi +85 -0
  106. data/rbi/lib/terminal-shop/type/request_parameters.rbi +20 -0
  107. data/rbi/lib/terminal-shop/type/union.rbi +68 -0
  108. data/rbi/lib/terminal-shop/type/unknown.rbi +37 -0
  109. data/rbi/lib/terminal-shop/type.rbi +23 -0
  110. data/rbi/lib/terminal-shop/version.rbi +1 -1
  111. data/sig/terminal-shop/client.rbs +3 -3
  112. data/sig/terminal-shop/models/address_create_params.rbs +1 -1
  113. data/sig/terminal-shop/models/address_delete_params.rbs +1 -1
  114. data/sig/terminal-shop/models/address_get_params.rbs +1 -1
  115. data/sig/terminal-shop/models/address_list_params.rbs +1 -1
  116. data/sig/terminal-shop/models/app_create_params.rbs +1 -1
  117. data/sig/terminal-shop/models/app_delete_params.rbs +1 -1
  118. data/sig/terminal-shop/models/app_get_params.rbs +1 -1
  119. data/sig/terminal-shop/models/app_list_params.rbs +1 -1
  120. data/sig/terminal-shop/models/card_collect_params.rbs +1 -1
  121. data/sig/terminal-shop/models/card_create_params.rbs +1 -1
  122. data/sig/terminal-shop/models/card_delete_params.rbs +1 -1
  123. data/sig/terminal-shop/models/card_get_params.rbs +1 -1
  124. data/sig/terminal-shop/models/card_list_params.rbs +1 -1
  125. data/sig/terminal-shop/models/cart_clear_params.rbs +1 -1
  126. data/sig/terminal-shop/models/cart_convert_params.rbs +1 -1
  127. data/sig/terminal-shop/models/cart_get_params.rbs +1 -1
  128. data/sig/terminal-shop/models/cart_set_address_params.rbs +1 -1
  129. data/sig/terminal-shop/models/cart_set_card_params.rbs +1 -1
  130. data/sig/terminal-shop/models/cart_set_item_params.rbs +1 -1
  131. data/sig/terminal-shop/models/email_create_params.rbs +1 -1
  132. data/sig/terminal-shop/models/order_create_params.rbs +1 -1
  133. data/sig/terminal-shop/models/order_get_params.rbs +1 -1
  134. data/sig/terminal-shop/models/order_list_params.rbs +1 -1
  135. data/sig/terminal-shop/models/product_get_params.rbs +1 -1
  136. data/sig/terminal-shop/models/product_list_params.rbs +1 -1
  137. data/sig/terminal-shop/models/profile_me_params.rbs +1 -1
  138. data/sig/terminal-shop/models/profile_update_params.rbs +1 -1
  139. data/sig/terminal-shop/models/subscription_create_params.rbs +1 -1
  140. data/sig/terminal-shop/models/subscription_delete_params.rbs +1 -1
  141. data/sig/terminal-shop/models/subscription_get_params.rbs +1 -1
  142. data/sig/terminal-shop/models/subscription_list_params.rbs +1 -1
  143. data/sig/terminal-shop/models/token_create_params.rbs +1 -1
  144. data/sig/terminal-shop/models/token_delete_params.rbs +1 -1
  145. data/sig/terminal-shop/models/token_get_params.rbs +1 -1
  146. data/sig/terminal-shop/models/token_list_params.rbs +1 -1
  147. data/sig/terminal-shop/models/view_init_params.rbs +1 -1
  148. data/sig/terminal-shop/request_options.rbs +0 -10
  149. data/sig/terminal-shop/transport/base_client.rbs +110 -0
  150. data/sig/terminal-shop/transport/pooled_net_requester.rbs +39 -0
  151. data/sig/terminal-shop/type/array_of.rbs +36 -0
  152. data/sig/terminal-shop/type/base_model.rbs +73 -0
  153. data/sig/terminal-shop/type/base_page.rbs +22 -0
  154. data/sig/terminal-shop/type/boolean_model.rbs +18 -0
  155. data/sig/terminal-shop/type/converter.rbs +42 -0
  156. data/sig/terminal-shop/type/enum.rbs +22 -0
  157. data/sig/terminal-shop/type/hash_of.rbs +36 -0
  158. data/sig/terminal-shop/type/request_parameters.rbs +13 -0
  159. data/sig/terminal-shop/type/union.rbs +40 -0
  160. data/sig/terminal-shop/type/unknown.rbs +18 -0
  161. data/sig/terminal-shop/type.rbs +22 -0
  162. data/sig/terminal-shop/version.rbs +1 -1
  163. metadata +41 -17
  164. data/lib/terminal-shop/base_client.rb +0 -457
  165. data/lib/terminal-shop/base_model.rb +0 -1201
  166. data/lib/terminal-shop/base_page.rb +0 -59
  167. data/lib/terminal-shop/extern.rb +0 -7
  168. data/lib/terminal-shop/pooled_net_requester.rb +0 -180
  169. data/rbi/lib/terminal-shop/base_client.rbi +0 -197
  170. data/rbi/lib/terminal-shop/base_model.rbi +0 -645
  171. data/rbi/lib/terminal-shop/base_page.rbi +0 -36
  172. data/rbi/lib/terminal-shop/extern.rbi +0 -7
  173. data/rbi/lib/terminal-shop/pooled_net_requester.rbi +0 -59
  174. data/sig/terminal-shop/base_client.rbs +0 -108
  175. data/sig/terminal-shop/base_model.rbs +0 -262
  176. data/sig/terminal-shop/base_page.rbs +0 -20
  177. data/sig/terminal-shop/extern.rbs +0 -4
  178. data/sig/terminal-shop/pooled_net_requester.rbs +0 -37
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TerminalShop
4
+ module Type
5
+ # rubocop:disable Metrics/ModuleLength
6
+ # @api private
7
+ module Converter
8
+ # rubocop:disable Lint/UnusedMethodArgument
9
+
10
+ # @api private
11
+ #
12
+ # @param value [Object]
13
+ #
14
+ # @param state [Hash{Symbol=>Object}] .
15
+ #
16
+ # @option state [Boolean, :strong] :strictness
17
+ #
18
+ # @option state [Hash{Symbol=>Object}] :exactness
19
+ #
20
+ # @option state [Integer] :branched
21
+ #
22
+ # @return [Object]
23
+ def coerce(value, state:) = (raise NotImplementedError)
24
+
25
+ # @api private
26
+ #
27
+ # @param value [Object]
28
+ #
29
+ # @return [Object]
30
+ def dump(value)
31
+ case value
32
+ in Array
33
+ value.map { TerminalShop::Unknown.dump(_1) }
34
+ in Hash
35
+ value.transform_values { TerminalShop::Unknown.dump(_1) }
36
+ in TerminalShop::BaseModel
37
+ value.class.dump(value)
38
+ else
39
+ value
40
+ end
41
+ end
42
+
43
+ # rubocop:enable Lint/UnusedMethodArgument
44
+
45
+ class << self
46
+ # @api private
47
+ #
48
+ # @param spec [Hash{Symbol=>Object}, Proc, TerminalShop::Type::Converter, Class] .
49
+ #
50
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
51
+ #
52
+ # @option spec [Proc] :enum
53
+ #
54
+ # @option spec [Proc] :union
55
+ #
56
+ # @option spec [Boolean] :"nil?"
57
+ #
58
+ # @return [Proc]
59
+ def type_info(spec)
60
+ case spec
61
+ in Proc
62
+ spec
63
+ in Hash
64
+ type_info(spec.slice(:const, :enum, :union).first&.last)
65
+ in true | false
66
+ -> { TerminalShop::BooleanModel }
67
+ in TerminalShop::Type::Converter | Class | Symbol
68
+ -> { spec }
69
+ in NilClass | Integer | Float
70
+ -> { spec.class }
71
+ end
72
+ end
73
+
74
+ # @api private
75
+ #
76
+ # Based on `target`, transform `value` into `target`, to the extent possible:
77
+ #
78
+ # 1. if the given `value` conforms to `target` already, return the given `value`
79
+ # 2. if it's possible and safe to convert the given `value` to `target`, then the
80
+ # converted value
81
+ # 3. otherwise, the given `value` unaltered
82
+ #
83
+ # The coercion process is subject to improvement between minor release versions.
84
+ # See https://docs.pydantic.dev/latest/concepts/unions/#smart-mode
85
+ #
86
+ # @param target [TerminalShop::Type::Converter, Class]
87
+ #
88
+ # @param value [Object]
89
+ #
90
+ # @param state [Hash{Symbol=>Object}] The `strictness` is one of `true`, `false`, or `:strong`. This informs the
91
+ # coercion strategy when we have to decide between multiple possible conversion
92
+ # targets:
93
+ #
94
+ # - `true`: the conversion must be exact, with minimum coercion.
95
+ # - `false`: the conversion can be approximate, with some coercion.
96
+ # - `:strong`: the conversion must be exact, with no coercion, and raise an error
97
+ # if not possible.
98
+ #
99
+ # The `exactness` is `Hash` with keys being one of `yes`, `no`, or `maybe`. For
100
+ # any given conversion attempt, the exactness will be updated based on how closely
101
+ # the value recursively matches the target type:
102
+ #
103
+ # - `yes`: the value can be converted to the target type with minimum coercion.
104
+ # - `maybe`: the value can be converted to the target type with some reasonable
105
+ # coercion.
106
+ # - `no`: the value cannot be converted to the target type.
107
+ #
108
+ # See implementation below for more details.
109
+ #
110
+ # @option state [Boolean, :strong] :strictness
111
+ #
112
+ # @option state [Hash{Symbol=>Object}] :exactness
113
+ #
114
+ # @option state [Integer] :branched
115
+ #
116
+ # @return [Object]
117
+ def coerce(
118
+ target,
119
+ value,
120
+ state: {strictness: true, exactness: {yes: 0, no: 0, maybe: 0}, branched: 0}
121
+ )
122
+ # rubocop:disable Lint/SuppressedException
123
+ # rubocop:disable Metrics/BlockNesting
124
+ strictness, exactness = state.fetch_values(:strictness, :exactness)
125
+
126
+ case target
127
+ in TerminalShop::Type::Converter
128
+ return target.coerce(value, state: state)
129
+ in Class
130
+ if value.is_a?(target)
131
+ exactness[:yes] += 1
132
+ return value
133
+ end
134
+
135
+ case target
136
+ in -> { _1 <= NilClass }
137
+ exactness[value.nil? ? :yes : :maybe] += 1
138
+ return nil
139
+ in -> { _1 <= Integer }
140
+ if value.is_a?(Integer)
141
+ exactness[:yes] += 1
142
+ return value
143
+ elsif strictness == :strong
144
+ message = "no implicit conversion of #{value.class} into #{target.inspect}"
145
+ raise TypeError.new(message)
146
+ else
147
+ Kernel.then do
148
+ return Integer(value).tap { exactness[:maybe] += 1 }
149
+ rescue ArgumentError, TypeError
150
+ end
151
+ end
152
+ in -> { _1 <= Float }
153
+ if value.is_a?(Numeric)
154
+ exactness[:yes] += 1
155
+ return Float(value)
156
+ elsif strictness == :strong
157
+ message = "no implicit conversion of #{value.class} into #{target.inspect}"
158
+ raise TypeError.new(message)
159
+ else
160
+ Kernel.then do
161
+ return Float(value).tap { exactness[:maybe] += 1 }
162
+ rescue ArgumentError, TypeError
163
+ end
164
+ end
165
+ in -> { _1 <= String }
166
+ case value
167
+ in String | Symbol | Numeric
168
+ exactness[value.is_a?(Numeric) ? :maybe : :yes] += 1
169
+ return value.to_s
170
+ else
171
+ if strictness == :strong
172
+ message = "no implicit conversion of #{value.class} into #{target.inspect}"
173
+ raise TypeError.new(message)
174
+ end
175
+ end
176
+ in -> { _1 <= Date || _1 <= Time }
177
+ Kernel.then do
178
+ return target.parse(value).tap { exactness[:yes] += 1 }
179
+ rescue ArgumentError, TypeError => e
180
+ raise e if strictness == :strong
181
+ end
182
+ in -> { _1 <= IO } if value.is_a?(String)
183
+ exactness[:yes] += 1
184
+ return StringIO.new(value.b)
185
+ else
186
+ end
187
+ in Symbol
188
+ if (value.is_a?(Symbol) || value.is_a?(String)) && value.to_sym == target
189
+ exactness[:yes] += 1
190
+ return target
191
+ elsif strictness == :strong
192
+ message = "cannot convert non-matching #{value.class} into #{target.inspect}"
193
+ raise ArgumentError.new(message)
194
+ end
195
+ else
196
+ end
197
+
198
+ exactness[:no] += 1
199
+ value
200
+ # rubocop:enable Metrics/BlockNesting
201
+ # rubocop:enable Lint/SuppressedException
202
+ end
203
+
204
+ # @api private
205
+ #
206
+ # @param target [TerminalShop::Type::Converter, Class]
207
+ # @param value [Object]
208
+ #
209
+ # @return [Object]
210
+ def dump(target, value)
211
+ target.is_a?(TerminalShop::Type::Converter) ? target.dump(value) : TerminalShop::Unknown.dump(value)
212
+ end
213
+ end
214
+ end
215
+ # rubocop:enable Metrics/ModuleLength
216
+ end
217
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TerminalShop
4
+ module Type
5
+ # @api private
6
+ #
7
+ # A value from among a specified list of options. OpenAPI enum values map to Ruby
8
+ # values in the SDK as follows:
9
+ #
10
+ # 1. boolean => true | false
11
+ # 2. integer => Integer
12
+ # 3. float => Float
13
+ # 4. string => Symbol
14
+ #
15
+ # We can therefore convert string values to Symbols, but can't convert other
16
+ # values safely.
17
+ #
18
+ # @example
19
+ # # `region` is a `TerminalShop::Models::Region`
20
+ # case region
21
+ # when TerminalShop::Models::Region::EU
22
+ # # ...
23
+ # when TerminalShop::Models::Region::NA
24
+ # # ...
25
+ # else
26
+ # puts(region)
27
+ # end
28
+ #
29
+ # @example
30
+ # case region
31
+ # in :eu
32
+ # # ...
33
+ # in :na
34
+ # # ...
35
+ # else
36
+ # puts(region)
37
+ # end
38
+ module Enum
39
+ include TerminalShop::Type::Converter
40
+
41
+ # All of the valid Symbol values for this enum.
42
+ #
43
+ # @return [Array<NilClass, Boolean, Integer, Float, Symbol>]
44
+ def values = (@values ||= constants.map { const_get(_1) })
45
+
46
+ # @api private
47
+ #
48
+ # Guard against thread safety issues by instantiating `@values`.
49
+ private def finalize! = values
50
+
51
+ # @param other [Object]
52
+ #
53
+ # @return [Boolean]
54
+ def ===(other) = values.include?(other)
55
+
56
+ # @param other [Object]
57
+ #
58
+ # @return [Boolean]
59
+ def ==(other)
60
+ other.is_a?(Module) && other.singleton_class <= TerminalShop::Enum && other.values.to_set == values.to_set
61
+ end
62
+
63
+ # @api private
64
+ #
65
+ # Unlike with primitives, `Enum` additionally validates that the value is a member
66
+ # of the enum.
67
+ #
68
+ # @param value [String, Symbol, Object]
69
+ #
70
+ # @param state [Hash{Symbol=>Object}] .
71
+ #
72
+ # @option state [Boolean, :strong] :strictness
73
+ #
74
+ # @option state [Hash{Symbol=>Object}] :exactness
75
+ #
76
+ # @option state [Integer] :branched
77
+ #
78
+ # @return [Symbol, Object]
79
+ def coerce(value, state:)
80
+ exactness = state.fetch(:exactness)
81
+ val = value.is_a?(String) ? value.to_sym : value
82
+
83
+ if values.include?(val)
84
+ exactness[:yes] += 1
85
+ val
86
+ else
87
+ exactness[values.first&.class == val.class ? :maybe : :no] += 1
88
+ value
89
+ end
90
+ end
91
+
92
+ # @!parse
93
+ # # @api private
94
+ # #
95
+ # # @param value [Symbol, Object]
96
+ # #
97
+ # # @return [Symbol, Object]
98
+ # def dump(value) = super
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TerminalShop
4
+ module Type
5
+ # @api private
6
+ #
7
+ # @abstract
8
+ #
9
+ # Hash of items of a given type.
10
+ class HashOf
11
+ include TerminalShop::Type::Converter
12
+
13
+ # @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Type::Converter, Class]
14
+ #
15
+ # @param spec [Hash{Symbol=>Object}] .
16
+ #
17
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
18
+ #
19
+ # @option spec [Proc] :enum
20
+ #
21
+ # @option spec [Proc] :union
22
+ #
23
+ # @option spec [Boolean] :"nil?"
24
+ def self.[](type_info, spec = {}) = new(type_info, spec)
25
+
26
+ # @param other [Object]
27
+ #
28
+ # @return [Boolean]
29
+ def ===(other)
30
+ type = item_type
31
+ case other
32
+ in Hash
33
+ other.all? do |key, val|
34
+ case [key, val]
35
+ in [Symbol | String, ^type]
36
+ true
37
+ else
38
+ false
39
+ end
40
+ end
41
+ else
42
+ false
43
+ end
44
+ end
45
+
46
+ # @param other [Object]
47
+ #
48
+ # @return [Boolean]
49
+ def ==(other)
50
+ other.is_a?(TerminalShop::HashOf) && other.nilable? == nilable? && other.item_type == item_type
51
+ end
52
+
53
+ # @api private
54
+ #
55
+ # @param value [Hash{Object=>Object}, Object]
56
+ #
57
+ # @param state [Hash{Symbol=>Object}] .
58
+ #
59
+ # @option state [Boolean, :strong] :strictness
60
+ #
61
+ # @option state [Hash{Symbol=>Object}] :exactness
62
+ #
63
+ # @option state [Integer] :branched
64
+ #
65
+ # @return [Hash{Symbol=>Object}, Object]
66
+ def coerce(value, state:)
67
+ exactness = state.fetch(:exactness)
68
+
69
+ unless value.is_a?(Hash)
70
+ exactness[:no] += 1
71
+ return value
72
+ end
73
+
74
+ target = item_type
75
+ exactness[:yes] += 1
76
+ value
77
+ .to_h do |key, val|
78
+ k = key.is_a?(String) ? key.to_sym : key
79
+ v =
80
+ case [nilable?, val]
81
+ in [true, nil]
82
+ exactness[:yes] += 1
83
+ nil
84
+ else
85
+ TerminalShop::Type::Converter.coerce(target, val, state: state)
86
+ end
87
+
88
+ exactness[:no] += 1 unless k.is_a?(Symbol)
89
+ [k, v]
90
+ end
91
+ end
92
+
93
+ # @api private
94
+ #
95
+ # @param value [Hash{Object=>Object}, Object]
96
+ #
97
+ # @return [Hash{Symbol=>Object}, Object]
98
+ def dump(value)
99
+ target = item_type
100
+ if value.is_a?(Hash)
101
+ value.transform_values do
102
+ TerminalShop::Type::Converter.dump(target, _1)
103
+ end
104
+ else
105
+ super
106
+ end
107
+ end
108
+
109
+ # @api private
110
+ #
111
+ # @return [TerminalShop::Type::Converter, Class]
112
+ protected def item_type = @item_type_fn.call
113
+
114
+ # @api private
115
+ #
116
+ # @return [Boolean]
117
+ protected def nilable? = @nilable
118
+
119
+ # @api private
120
+ #
121
+ # @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Type::Converter, Class]
122
+ #
123
+ # @param spec [Hash{Symbol=>Object}] .
124
+ #
125
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
126
+ #
127
+ # @option spec [Proc] :enum
128
+ #
129
+ # @option spec [Proc] :union
130
+ #
131
+ # @option spec [Boolean] :"nil?"
132
+ def initialize(type_info, spec = {})
133
+ @item_type_fn = TerminalShop::Type::Converter.type_info(type_info || spec)
134
+ @nilable = spec[:nil?]
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TerminalShop
4
+ module Type
5
+ # @api private
6
+ module RequestParameters
7
+ # @!parse
8
+ # # Options to specify HTTP behaviour for this request.
9
+ # # @return [TerminalShop::RequestOptions, Hash{Symbol=>Object}]
10
+ # attr_accessor :request_options
11
+
12
+ # @param mod [Module]
13
+ def self.included(mod)
14
+ return unless mod <= TerminalShop::BaseModel
15
+
16
+ mod.extend(TerminalShop::Type::RequestParameters::Converter)
17
+ mod.optional(:request_options, TerminalShop::RequestOptions)
18
+ end
19
+
20
+ # @api private
21
+ module Converter
22
+ # @api private
23
+ #
24
+ # @param params [Object]
25
+ #
26
+ # @return [Array(Object, Hash{Symbol=>Object})]
27
+ def dump_request(params)
28
+ case (dumped = dump(params))
29
+ in Hash
30
+ [dumped.except(:request_options), dumped[:request_options]]
31
+ else
32
+ [dumped, nil]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TerminalShop
4
+ module Type
5
+ # @api private
6
+ module Union
7
+ include TerminalShop::Type::Converter
8
+
9
+ # @api private
10
+ #
11
+ # All of the specified variant info for this union.
12
+ #
13
+ # @return [Array<Array(Symbol, Proc)>]
14
+ private def known_variants = (@known_variants ||= [])
15
+
16
+ # @api private
17
+ #
18
+ # @return [Array<Array(Symbol, Object)>]
19
+ protected def derefed_variants
20
+ @known_variants.map { |key, variant_fn| [key, variant_fn.call] }
21
+ end
22
+
23
+ # All of the specified variants for this union.
24
+ #
25
+ # @return [Array<Object>]
26
+ def variants = derefed_variants.map(&:last)
27
+
28
+ # @api private
29
+ #
30
+ # @param property [Symbol]
31
+ private def discriminator(property)
32
+ case property
33
+ in Symbol
34
+ @discriminator = property
35
+ end
36
+ end
37
+
38
+ # @api private
39
+ #
40
+ # @param key [Symbol, Hash{Symbol=>Object}, Proc, TerminalShop::Type::Converter, Class]
41
+ #
42
+ # @param spec [Hash{Symbol=>Object}, Proc, TerminalShop::Type::Converter, Class] .
43
+ #
44
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
45
+ #
46
+ # @option spec [Proc] :enum
47
+ #
48
+ # @option spec [Proc] :union
49
+ #
50
+ # @option spec [Boolean] :"nil?"
51
+ private def variant(key, spec = nil)
52
+ variant_info =
53
+ case key
54
+ in Symbol
55
+ [key, TerminalShop::Type::Converter.type_info(spec)]
56
+ in Proc | TerminalShop::Type::Converter | Class | Hash
57
+ [nil, TerminalShop::Type::Converter.type_info(key)]
58
+ end
59
+
60
+ known_variants << variant_info
61
+ end
62
+
63
+ # @api private
64
+ #
65
+ # @param value [Object]
66
+ #
67
+ # @return [TerminalShop::Type::Converter, Class, nil]
68
+ private def resolve_variant(value)
69
+ case [@discriminator, value]
70
+ in [_, TerminalShop::BaseModel]
71
+ value.class
72
+ in [Symbol, Hash]
73
+ key = value.fetch(@discriminator) do
74
+ value.fetch(@discriminator.to_s, TerminalShop::Util::OMIT)
75
+ end
76
+
77
+ return nil if key == TerminalShop::Util::OMIT
78
+
79
+ key = key.to_sym if key.is_a?(String)
80
+ known_variants.find { |k,| k == key }&.last&.call
81
+ else
82
+ nil
83
+ end
84
+ end
85
+
86
+ # rubocop:disable Style/HashEachMethods
87
+ # rubocop:disable Style/CaseEquality
88
+
89
+ # @param other [Object]
90
+ #
91
+ # @return [Boolean]
92
+ def ===(other)
93
+ known_variants.any? do |_, variant_fn|
94
+ variant_fn.call === other
95
+ end
96
+ end
97
+
98
+ # @param other [Object]
99
+ #
100
+ # @return [Boolean]
101
+ def ==(other)
102
+ # rubocop:disable Layout/LineLength
103
+ other.is_a?(Module) && other.singleton_class <= TerminalShop::Union && other.derefed_variants == derefed_variants
104
+ # rubocop:enable Layout/LineLength
105
+ end
106
+
107
+ # @api private
108
+ #
109
+ # @param value [Object]
110
+ #
111
+ # @param state [Hash{Symbol=>Object}] .
112
+ #
113
+ # @option state [Boolean, :strong] :strictness
114
+ #
115
+ # @option state [Hash{Symbol=>Object}] :exactness
116
+ #
117
+ # @option state [Integer] :branched
118
+ #
119
+ # @return [Object]
120
+ def coerce(value, state:)
121
+ if (target = resolve_variant(value))
122
+ return TerminalShop::Type::Converter.coerce(target, value, state: state)
123
+ end
124
+
125
+ strictness = state.fetch(:strictness)
126
+ exactness = state.fetch(:exactness)
127
+ state[:strictness] = strictness == :strong ? true : strictness
128
+
129
+ alternatives = []
130
+ known_variants.each do |_, variant_fn|
131
+ target = variant_fn.call
132
+ exact = state[:exactness] = {yes: 0, no: 0, maybe: 0}
133
+ state[:branched] += 1
134
+
135
+ coerced = TerminalShop::Type::Converter.coerce(target, value, state: state)
136
+ yes, no, maybe = exact.values
137
+ if (no + maybe).zero? || (!strictness && yes.positive?)
138
+ exact.each { exactness[_1] += _2 }
139
+ state[:exactness] = exactness
140
+ return coerced
141
+ elsif maybe.positive?
142
+ alternatives << [[-yes, -maybe, no], exact, coerced]
143
+ end
144
+ end
145
+
146
+ case alternatives.sort_by(&:first)
147
+ in []
148
+ exactness[:no] += 1
149
+ if strictness == :strong
150
+ message = "no possible conversion of #{value.class} into a variant of #{target.inspect}"
151
+ raise ArgumentError.new(message)
152
+ end
153
+ value
154
+ in [[_, exact, coerced], *]
155
+ exact.each { exactness[_1] += _2 }
156
+ coerced
157
+ end
158
+ .tap { state[:exactness] = exactness }
159
+ ensure
160
+ state[:strictness] = strictness
161
+ end
162
+
163
+ # @api private
164
+ #
165
+ # @param value [Object]
166
+ #
167
+ # @return [Object]
168
+ def dump(value)
169
+ if (target = resolve_variant(value))
170
+ return TerminalShop::Type::Converter.dump(target, value)
171
+ end
172
+
173
+ known_variants.each do
174
+ target = _2.call
175
+ return TerminalShop::Type::Converter.dump(target, value) if target === value
176
+ end
177
+
178
+ super
179
+ end
180
+
181
+ # rubocop:enable Style/CaseEquality
182
+ # rubocop:enable Style/HashEachMethods
183
+ end
184
+ end
185
+ end