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,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TerminalShop
4
+ module Type
5
+ # @api private
6
+ #
7
+ # @abstract
8
+ #
9
+ # Array of items of a given type.
10
+ class ArrayOf
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) = other.is_a?(Array) && other.all?(item_type)
30
+
31
+ # @param other [Object]
32
+ #
33
+ # @return [Boolean]
34
+ def ==(other)
35
+ other.is_a?(TerminalShop::ArrayOf) && other.nilable? == nilable? && other.item_type == item_type
36
+ end
37
+
38
+ # @api private
39
+ #
40
+ # @param value [Enumerable, Object]
41
+ #
42
+ # @param state [Hash{Symbol=>Object}] .
43
+ #
44
+ # @option state [Boolean, :strong] :strictness
45
+ #
46
+ # @option state [Hash{Symbol=>Object}] :exactness
47
+ #
48
+ # @option state [Integer] :branched
49
+ #
50
+ # @return [Array<Object>, Object]
51
+ def coerce(value, state:)
52
+ exactness = state.fetch(:exactness)
53
+
54
+ unless value.is_a?(Array)
55
+ exactness[:no] += 1
56
+ return value
57
+ end
58
+
59
+ target = item_type
60
+ exactness[:yes] += 1
61
+ value
62
+ .map do |item|
63
+ case [nilable?, item]
64
+ in [true, nil]
65
+ exactness[:yes] += 1
66
+ nil
67
+ else
68
+ TerminalShop::Type::Converter.coerce(target, item, state: state)
69
+ end
70
+ end
71
+ end
72
+
73
+ # @api private
74
+ #
75
+ # @param value [Enumerable, Object]
76
+ #
77
+ # @return [Array<Object>, Object]
78
+ def dump(value)
79
+ target = item_type
80
+ value.is_a?(Array) ? value.map { TerminalShop::Type::Converter.dump(target, _1) } : super
81
+ end
82
+
83
+ # @api private
84
+ #
85
+ # @return [TerminalShop::Type::Converter, Class]
86
+ protected def item_type = @item_type_fn.call
87
+
88
+ # @api private
89
+ #
90
+ # @return [Boolean]
91
+ protected def nilable? = @nilable
92
+
93
+ # @api private
94
+ #
95
+ # @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Type::Converter, Class]
96
+ #
97
+ # @param spec [Hash{Symbol=>Object}] .
98
+ #
99
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
100
+ #
101
+ # @option spec [Proc] :enum
102
+ #
103
+ # @option spec [Proc] :union
104
+ #
105
+ # @option spec [Boolean] :"nil?"
106
+ def initialize(type_info, spec = {})
107
+ @item_type_fn = TerminalShop::Type::Converter.type_info(type_info || spec)
108
+ @nilable = spec[:nil?]
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,364 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TerminalShop
4
+ module Type
5
+ # @abstract
6
+ #
7
+ # @example
8
+ # # `product_api` is a `TerminalShop::Models::ProductAPI`
9
+ # product_api => {
10
+ # id: id,
11
+ # description: description,
12
+ # name: name
13
+ # }
14
+ class BaseModel
15
+ extend TerminalShop::Type::Converter
16
+
17
+ class << self
18
+ # @api private
19
+ #
20
+ # Assumes superclass fields are totally defined before fields are accessed /
21
+ # defined on subclasses.
22
+ #
23
+ # @return [Hash{Symbol=>Hash{Symbol=>Object}}]
24
+ def known_fields
25
+ @known_fields ||= (self < TerminalShop::BaseModel ? superclass.known_fields.dup : {})
26
+ end
27
+
28
+ # @api private
29
+ #
30
+ # @return [Hash{Symbol=>Hash{Symbol=>Object}}]
31
+ def fields
32
+ known_fields.transform_values do |field|
33
+ {**field.except(:type_fn), type: field.fetch(:type_fn).call}
34
+ end
35
+ end
36
+
37
+ # @api private
38
+ #
39
+ # @param name_sym [Symbol]
40
+ #
41
+ # @param required [Boolean]
42
+ #
43
+ # @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Type::Converter, Class]
44
+ #
45
+ # @param spec [Hash{Symbol=>Object}] .
46
+ #
47
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
48
+ #
49
+ # @option spec [Proc] :enum
50
+ #
51
+ # @option spec [Proc] :union
52
+ #
53
+ # @option spec [Boolean] :"nil?"
54
+ private def add_field(name_sym, required:, type_info:, spec:)
55
+ type_fn, info =
56
+ case type_info
57
+ in Proc | TerminalShop::Type::Converter | Class
58
+ [TerminalShop::Type::Converter.type_info({**spec, union: type_info}), spec]
59
+ in Hash
60
+ [TerminalShop::Type::Converter.type_info(type_info), type_info]
61
+ end
62
+
63
+ setter = "#{name_sym}="
64
+ api_name = info.fetch(:api_name, name_sym)
65
+ nilable = info[:nil?]
66
+ const = if required && !nilable
67
+ info.fetch(
68
+ :const,
69
+ TerminalShop::Util::OMIT
70
+ )
71
+ else
72
+ TerminalShop::Util::OMIT
73
+ end
74
+
75
+ [name_sym, setter].each { undef_method(_1) } if known_fields.key?(name_sym)
76
+
77
+ known_fields[name_sym] =
78
+ {
79
+ mode: @mode,
80
+ api_name: api_name,
81
+ required: required,
82
+ nilable: nilable,
83
+ const: const,
84
+ type_fn: type_fn
85
+ }
86
+
87
+ define_method(setter) { @data.store(name_sym, _1) }
88
+
89
+ define_method(name_sym) do
90
+ target = type_fn.call
91
+ value = @data.fetch(name_sym) { const == TerminalShop::Util::OMIT ? nil : const }
92
+ state = {strictness: :strong, exactness: {yes: 0, no: 0, maybe: 0}, branched: 0}
93
+ if (nilable || !required) && value.nil?
94
+ nil
95
+ else
96
+ TerminalShop::Type::Converter.coerce(
97
+ target,
98
+ value,
99
+ state: state
100
+ )
101
+ end
102
+ rescue StandardError
103
+ cls = self.class.name.split("::").last
104
+ # rubocop:disable Layout/LineLength
105
+ message = "Failed to parse #{cls}.#{__method__} from #{value.class} to #{target.inspect}. To get the unparsed API response, use #{cls}[:#{__method__}]."
106
+ # rubocop:enable Layout/LineLength
107
+ raise TerminalShop::ConversionError.new(message)
108
+ end
109
+ end
110
+
111
+ # @api private
112
+ #
113
+ # @param name_sym [Symbol]
114
+ #
115
+ # @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Type::Converter, Class]
116
+ #
117
+ # @param spec [Hash{Symbol=>Object}] .
118
+ #
119
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
120
+ #
121
+ # @option spec [Proc] :enum
122
+ #
123
+ # @option spec [Proc] :union
124
+ #
125
+ # @option spec [Boolean] :"nil?"
126
+ def required(name_sym, type_info, spec = {})
127
+ add_field(name_sym, required: true, type_info: type_info, spec: spec)
128
+ end
129
+
130
+ # @api private
131
+ #
132
+ # @param name_sym [Symbol]
133
+ #
134
+ # @param type_info [Hash{Symbol=>Object}, Proc, TerminalShop::Type::Converter, Class]
135
+ #
136
+ # @param spec [Hash{Symbol=>Object}] .
137
+ #
138
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
139
+ #
140
+ # @option spec [Proc] :enum
141
+ #
142
+ # @option spec [Proc] :union
143
+ #
144
+ # @option spec [Boolean] :"nil?"
145
+ def optional(name_sym, type_info, spec = {})
146
+ add_field(name_sym, required: false, type_info: type_info, spec: spec)
147
+ end
148
+
149
+ # @api private
150
+ #
151
+ # `request_only` attributes not excluded from `.#coerce` when receiving responses
152
+ # even if well behaved servers should not send them
153
+ #
154
+ # @param blk [Proc]
155
+ private def request_only(&blk)
156
+ @mode = :dump
157
+ blk.call
158
+ ensure
159
+ @mode = nil
160
+ end
161
+
162
+ # @api private
163
+ #
164
+ # `response_only` attributes are omitted from `.#dump` when making requests
165
+ #
166
+ # @param blk [Proc]
167
+ private def response_only(&blk)
168
+ @mode = :coerce
169
+ blk.call
170
+ ensure
171
+ @mode = nil
172
+ end
173
+
174
+ # @param other [Object]
175
+ #
176
+ # @return [Boolean]
177
+ def ==(other) = other.is_a?(Class) && other <= TerminalShop::BaseModel && other.fields == fields
178
+ end
179
+
180
+ # @param other [Object]
181
+ #
182
+ # @return [Boolean]
183
+ def ==(other) = self.class == other.class && @data == other.to_h
184
+
185
+ class << self
186
+ # @api private
187
+ #
188
+ # @param value [TerminalShop::BaseModel, Hash{Object=>Object}, Object]
189
+ #
190
+ # @param state [Hash{Symbol=>Object}] .
191
+ #
192
+ # @option state [Boolean, :strong] :strictness
193
+ #
194
+ # @option state [Hash{Symbol=>Object}] :exactness
195
+ #
196
+ # @option state [Integer] :branched
197
+ #
198
+ # @return [TerminalShop::BaseModel, Object]
199
+ def coerce(value, state:)
200
+ exactness = state.fetch(:exactness)
201
+
202
+ if value.is_a?(self.class)
203
+ exactness[:yes] += 1
204
+ return value
205
+ end
206
+
207
+ unless (val = TerminalShop::Util.coerce_hash(value)).is_a?(Hash)
208
+ exactness[:no] += 1
209
+ return value
210
+ end
211
+ exactness[:yes] += 1
212
+
213
+ keys = val.keys.to_set
214
+ instance = new
215
+ data = instance.to_h
216
+
217
+ # rubocop:disable Metrics/BlockLength
218
+ fields.each do |name, field|
219
+ mode, required, target = field.fetch_values(:mode, :required, :type)
220
+ api_name, nilable, const = field.fetch_values(:api_name, :nilable, :const)
221
+
222
+ unless val.key?(api_name)
223
+ if required && mode != :dump && const == TerminalShop::Util::OMIT
224
+ exactness[nilable ? :maybe : :no] += 1
225
+ else
226
+ exactness[:yes] += 1
227
+ end
228
+ next
229
+ end
230
+
231
+ item = val.fetch(api_name)
232
+ keys.delete(api_name)
233
+
234
+ converted =
235
+ if item.nil? && (nilable || !required)
236
+ exactness[nilable ? :yes : :maybe] += 1
237
+ nil
238
+ else
239
+ coerced = TerminalShop::Type::Converter.coerce(target, item, state: state)
240
+ case target
241
+ in TerminalShop::Type::Converter | Symbol
242
+ coerced
243
+ else
244
+ item
245
+ end
246
+ end
247
+ data.store(name, converted)
248
+ end
249
+ # rubocop:enable Metrics/BlockLength
250
+
251
+ keys.each { data.store(_1, val.fetch(_1)) }
252
+ instance
253
+ end
254
+
255
+ # @api private
256
+ #
257
+ # @param value [TerminalShop::BaseModel, Object]
258
+ #
259
+ # @return [Hash{Object=>Object}, Object]
260
+ def dump(value)
261
+ unless (coerced = TerminalShop::Util.coerce_hash(value)).is_a?(Hash)
262
+ return super
263
+ end
264
+
265
+ acc = {}
266
+
267
+ coerced.each do |key, val|
268
+ name = key.is_a?(String) ? key.to_sym : key
269
+ case (field = known_fields[name])
270
+ in nil
271
+ acc.store(name, super(val))
272
+ else
273
+ mode, api_name, type_fn = field.fetch_values(:mode, :api_name, :type_fn)
274
+ case mode
275
+ in :coerce
276
+ next
277
+ else
278
+ target = type_fn.call
279
+ acc.store(api_name, TerminalShop::Type::Converter.dump(target, val))
280
+ end
281
+ end
282
+ end
283
+
284
+ known_fields.each_value do |field|
285
+ mode, api_name, const = field.fetch_values(:mode, :api_name, :const)
286
+ next if mode == :coerce || acc.key?(api_name) || const == TerminalShop::Util::OMIT
287
+ acc.store(api_name, const)
288
+ end
289
+
290
+ acc
291
+ end
292
+ end
293
+
294
+ # Returns the raw value associated with the given key, if found. Otherwise, nil is
295
+ # returned.
296
+ #
297
+ # It is valid to lookup keys that are not in the API spec, for example to access
298
+ # undocumented features. This method does not parse response data into
299
+ # higher-level types. Lookup by anything other than a Symbol is an ArgumentError.
300
+ #
301
+ # @param key [Symbol]
302
+ #
303
+ # @return [Object, nil]
304
+ def [](key)
305
+ unless key.instance_of?(Symbol)
306
+ raise ArgumentError.new("Expected symbol key for lookup, got #{key.inspect}")
307
+ end
308
+
309
+ @data[key]
310
+ end
311
+
312
+ # Returns a Hash of the data underlying this object. O(1)
313
+ #
314
+ # Keys are Symbols and values are the raw values from the response. The return
315
+ # value indicates which values were ever set on the object. i.e. there will be a
316
+ # key in this hash if they ever were, even if the set value was nil.
317
+ #
318
+ # This method is not recursive. The returned value is shared by the object, so it
319
+ # should not be mutated.
320
+ #
321
+ # @return [Hash{Symbol=>Object}]
322
+ def to_h = @data
323
+
324
+ alias_method :to_hash, :to_h
325
+
326
+ # @param keys [Array<Symbol>, nil]
327
+ #
328
+ # @return [Hash{Symbol=>Object}]
329
+ def deconstruct_keys(keys)
330
+ (keys || self.class.known_fields.keys)
331
+ .filter_map do |k|
332
+ unless self.class.known_fields.key?(k)
333
+ next
334
+ end
335
+
336
+ [k, public_send(k)]
337
+ end
338
+ .to_h
339
+ end
340
+
341
+ # Create a new instance of a model.
342
+ #
343
+ # @param data [Hash{Symbol=>Object}, TerminalShop::BaseModel]
344
+ def initialize(data = {})
345
+ case TerminalShop::Util.coerce_hash(data)
346
+ in Hash => coerced
347
+ @data = coerced
348
+ else
349
+ raise ArgumentError.new("Expected a #{Hash} or #{TerminalShop::BaseModel}, got #{data.inspect}")
350
+ end
351
+ end
352
+
353
+ # @return [String]
354
+ def inspect
355
+ rows = self.class.known_fields.keys.map do
356
+ "#{_1}=#{@data.key?(_1) ? public_send(_1) : ''}"
357
+ rescue TerminalShop::ConversionError
358
+ "#{_1}=#{@data.fetch(_1)}"
359
+ end
360
+ "#<#{self.class.name}:0x#{object_id.to_s(16)} #{rows.join(' ')}>"
361
+ end
362
+ end
363
+ end
364
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TerminalShop
4
+ module Type
5
+ # @example
6
+ # if page.has_next?
7
+ # page = page.next_page
8
+ # end
9
+ #
10
+ # @example
11
+ # page.auto_paging_each do |product|
12
+ # puts(product)
13
+ # end
14
+ #
15
+ # @example
16
+ # products =
17
+ # page
18
+ # .to_enum
19
+ # .lazy
20
+ # .select { _1.object_id.even? }
21
+ # .map(&:itself)
22
+ # .take(2)
23
+ # .to_a
24
+ #
25
+ # products => Array
26
+ module BasePage
27
+ # rubocop:disable Lint/UnusedMethodArgument
28
+
29
+ # @return [Boolean]
30
+ def next_page? = (raise NotImplementedError)
31
+
32
+ # @raise [TerminalShop::APIError]
33
+ # @return [TerminalShop::Type::BasePage]
34
+ def next_page = (raise NotImplementedError)
35
+
36
+ # @param blk [Proc]
37
+ #
38
+ # @return [void]
39
+ def auto_paging_each(&blk) = (raise NotImplementedError)
40
+
41
+ # @return [Enumerable]
42
+ def to_enum = super(:auto_paging_each)
43
+
44
+ alias_method :enum_for, :to_enum
45
+
46
+ # @api private
47
+ #
48
+ # @param client [TerminalShop::Transport::BaseClient]
49
+ # @param req [Hash{Symbol=>Object}]
50
+ # @param headers [Hash{String=>String}, Net::HTTPHeader]
51
+ # @param page_data [Object]
52
+ def initialize(client:, req:, headers:, page_data:)
53
+ @client = client
54
+ @req = req
55
+ super()
56
+ end
57
+
58
+ # rubocop:enable Lint/UnusedMethodArgument
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TerminalShop
4
+ module Type
5
+ # @api private
6
+ #
7
+ # @abstract
8
+ #
9
+ # Ruby has no Boolean class; this is something for models to refer to.
10
+ class BooleanModel
11
+ extend TerminalShop::Type::Converter
12
+
13
+ # @param other [Object]
14
+ #
15
+ # @return [Boolean]
16
+ def self.===(other) = other == true || other == false
17
+
18
+ # @param other [Object]
19
+ #
20
+ # @return [Boolean]
21
+ def self.==(other) = other.is_a?(Class) && other <= TerminalShop::BooleanModel
22
+
23
+ class << self
24
+ # @api private
25
+ #
26
+ # @param value [Boolean, Object]
27
+ #
28
+ # @param state [Hash{Symbol=>Object}] .
29
+ #
30
+ # @option state [Boolean, :strong] :strictness
31
+ #
32
+ # @option state [Hash{Symbol=>Object}] :exactness
33
+ #
34
+ # @option state [Integer] :branched
35
+ #
36
+ # @return [Boolean, Object]
37
+ def coerce(value, state:)
38
+ state.fetch(:exactness)[value == true || value == false ? :yes : :no] += 1
39
+ value
40
+ end
41
+
42
+ # @!parse
43
+ # # @api private
44
+ # #
45
+ # # @param value [Boolean, Object]
46
+ # #
47
+ # # @return [Boolean, Object]
48
+ # def dump(value) = super
49
+ end
50
+ end
51
+ end
52
+ end