galaxy-ruby 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +8 -0
  3. data/LICENSE +201 -0
  4. data/README.md +169 -0
  5. data/SECURITY.md +19 -0
  6. data/SKILL.md +83 -0
  7. data/api.md +188 -0
  8. data/lib/galaxy-ruby/client.rb +254 -0
  9. data/lib/galaxy-ruby/errors.rb +227 -0
  10. data/lib/galaxy-ruby/file_part.rb +58 -0
  11. data/lib/galaxy-ruby/internal/transport/base_client.rb +576 -0
  12. data/lib/galaxy-ruby/internal/transport/pooled_net_requester.rb +224 -0
  13. data/lib/galaxy-ruby/internal/type/array_of.rb +164 -0
  14. data/lib/galaxy-ruby/internal/type/base_model.rb +529 -0
  15. data/lib/galaxy-ruby/internal/type/base_page.rb +55 -0
  16. data/lib/galaxy-ruby/internal/type/boolean.rb +77 -0
  17. data/lib/galaxy-ruby/internal/type/converter.rb +333 -0
  18. data/lib/galaxy-ruby/internal/type/enum.rb +130 -0
  19. data/lib/galaxy-ruby/internal/type/file_input.rb +111 -0
  20. data/lib/galaxy-ruby/internal/type/hash_of.rb +184 -0
  21. data/lib/galaxy-ruby/internal/type/request_parameters.rb +42 -0
  22. data/lib/galaxy-ruby/internal/type/union.rb +234 -0
  23. data/lib/galaxy-ruby/internal/type/unknown.rb +81 -0
  24. data/lib/galaxy-ruby/internal/util.rb +960 -0
  25. data/lib/galaxy-ruby/internal.rb +15 -0
  26. data/lib/galaxy-ruby/models/authentication_create_token_params.rb +14 -0
  27. data/lib/galaxy-ruby/models/authentication_create_token_response.rb +16 -0
  28. data/lib/galaxy-ruby/models/authentication_create_user_params.rb +32 -0
  29. data/lib/galaxy-ruby/models/authentication_list_me_params.rb +14 -0
  30. data/lib/galaxy-ruby/models/celestial_body.rb +81 -0
  31. data/lib/galaxy-ruby/models/celestial_body_create_params.rb +20 -0
  32. data/lib/galaxy-ruby/models/credentials.rb +25 -0
  33. data/lib/galaxy-ruby/models/new_planet_webhook_event.rb +216 -0
  34. data/lib/galaxy-ruby/models/planet.rb +218 -0
  35. data/lib/galaxy-ruby/models/planet_create_params.rb +14 -0
  36. data/lib/galaxy-ruby/models/planet_delete_params.rb +20 -0
  37. data/lib/galaxy-ruby/models/planet_delte_image_params.rb +29 -0
  38. data/lib/galaxy-ruby/models/planet_delte_image_response.rb +48 -0
  39. data/lib/galaxy-ruby/models/planet_list_all_data_params.rb +30 -0
  40. data/lib/galaxy-ruby/models/planet_list_all_data_response.rb +51 -0
  41. data/lib/galaxy-ruby/models/planet_retrieve_params.rb +20 -0
  42. data/lib/galaxy-ruby/models/planet_update_params.rb +20 -0
  43. data/lib/galaxy-ruby/models/unwrap_webhook_event.rb +14 -0
  44. data/lib/galaxy-ruby/models/user.rb +26 -0
  45. data/lib/galaxy-ruby/models/webhook_unwrap_params.rb +14 -0
  46. data/lib/galaxy-ruby/models.rb +78 -0
  47. data/lib/galaxy-ruby/request_options.rb +77 -0
  48. data/lib/galaxy-ruby/resources/authentication.rb +80 -0
  49. data/lib/galaxy-ruby/resources/celestial_bodies.rb +37 -0
  50. data/lib/galaxy-ruby/resources/planets.rb +215 -0
  51. data/lib/galaxy-ruby/resources/webhooks.rb +34 -0
  52. data/lib/galaxy-ruby/version.rb +5 -0
  53. data/lib/galaxy-ruby.rb +78 -0
  54. data/rbi/galaxy-ruby/client.rbi +128 -0
  55. data/rbi/galaxy-ruby/errors.rbi +205 -0
  56. data/rbi/galaxy-ruby/file_part.rbi +37 -0
  57. data/rbi/galaxy-ruby/internal/transport/base_client.rbi +305 -0
  58. data/rbi/galaxy-ruby/internal/transport/pooled_net_requester.rbi +84 -0
  59. data/rbi/galaxy-ruby/internal/type/array_of.rbi +104 -0
  60. data/rbi/galaxy-ruby/internal/type/base_model.rbi +314 -0
  61. data/rbi/galaxy-ruby/internal/type/base_page.rbi +43 -0
  62. data/rbi/galaxy-ruby/internal/type/boolean.rbi +58 -0
  63. data/rbi/galaxy-ruby/internal/type/converter.rbi +222 -0
  64. data/rbi/galaxy-ruby/internal/type/enum.rbi +82 -0
  65. data/rbi/galaxy-ruby/internal/type/file_input.rbi +59 -0
  66. data/rbi/galaxy-ruby/internal/type/hash_of.rbi +104 -0
  67. data/rbi/galaxy-ruby/internal/type/request_parameters.rbi +31 -0
  68. data/rbi/galaxy-ruby/internal/type/union.rbi +128 -0
  69. data/rbi/galaxy-ruby/internal/type/unknown.rbi +58 -0
  70. data/rbi/galaxy-ruby/internal/util.rbi +515 -0
  71. data/rbi/galaxy-ruby/internal.rbi +18 -0
  72. data/rbi/galaxy-ruby/models/authentication_create_token_params.rbi +32 -0
  73. data/rbi/galaxy-ruby/models/authentication_create_token_response.rbi +29 -0
  74. data/rbi/galaxy-ruby/models/authentication_create_user_params.rbi +54 -0
  75. data/rbi/galaxy-ruby/models/authentication_list_me_params.rbi +32 -0
  76. data/rbi/galaxy-ruby/models/celestial_body.rbi +140 -0
  77. data/rbi/galaxy-ruby/models/celestial_body_create_params.rbi +53 -0
  78. data/rbi/galaxy-ruby/models/credentials.rbi +27 -0
  79. data/rbi/galaxy-ruby/models/new_planet_webhook_event.rbi +396 -0
  80. data/rbi/galaxy-ruby/models/planet.rbi +350 -0
  81. data/rbi/galaxy-ruby/models/planet_create_params.rbi +32 -0
  82. data/rbi/galaxy-ruby/models/planet_delete_params.rbi +38 -0
  83. data/rbi/galaxy-ruby/models/planet_delte_image_params.rbi +55 -0
  84. data/rbi/galaxy-ruby/models/planet_delte_image_response.rbi +85 -0
  85. data/rbi/galaxy-ruby/models/planet_list_all_data_params.rbi +60 -0
  86. data/rbi/galaxy-ruby/models/planet_list_all_data_response.rbi +110 -0
  87. data/rbi/galaxy-ruby/models/planet_retrieve_params.rbi +38 -0
  88. data/rbi/galaxy-ruby/models/planet_update_params.rbi +38 -0
  89. data/rbi/galaxy-ruby/models/unwrap_webhook_event.rbi +17 -0
  90. data/rbi/galaxy-ruby/models/user.rbi +33 -0
  91. data/rbi/galaxy-ruby/models/webhook_unwrap_params.rbi +32 -0
  92. data/rbi/galaxy-ruby/models.rbi +39 -0
  93. data/rbi/galaxy-ruby/request_options.rbi +59 -0
  94. data/rbi/galaxy-ruby/resources/authentication.rbi +47 -0
  95. data/rbi/galaxy-ruby/resources/celestial_bodies.rbi +28 -0
  96. data/rbi/galaxy-ruby/resources/planets.rbi +176 -0
  97. data/rbi/galaxy-ruby/resources/webhooks.rbi +29 -0
  98. data/rbi/galaxy-ruby/version.rbi +5 -0
  99. data/sig/galaxy-ruby/client.rbs +62 -0
  100. data/sig/galaxy-ruby/errors.rbs +117 -0
  101. data/sig/galaxy-ruby/file_part.rbs +21 -0
  102. data/sig/galaxy-ruby/internal/transport/base_client.rbs +133 -0
  103. data/sig/galaxy-ruby/internal/transport/pooled_net_requester.rbs +48 -0
  104. data/sig/galaxy-ruby/internal/type/array_of.rbs +48 -0
  105. data/sig/galaxy-ruby/internal/type/base_model.rbs +102 -0
  106. data/sig/galaxy-ruby/internal/type/base_page.rbs +24 -0
  107. data/sig/galaxy-ruby/internal/type/boolean.rbs +26 -0
  108. data/sig/galaxy-ruby/internal/type/converter.rbs +79 -0
  109. data/sig/galaxy-ruby/internal/type/enum.rbs +32 -0
  110. data/sig/galaxy-ruby/internal/type/file_input.rbs +25 -0
  111. data/sig/galaxy-ruby/internal/type/hash_of.rbs +48 -0
  112. data/sig/galaxy-ruby/internal/type/request_parameters.rbs +17 -0
  113. data/sig/galaxy-ruby/internal/type/union.rbs +52 -0
  114. data/sig/galaxy-ruby/internal/type/unknown.rbs +26 -0
  115. data/sig/galaxy-ruby/internal/util.rbs +199 -0
  116. data/sig/galaxy-ruby/internal.rbs +9 -0
  117. data/sig/galaxy-ruby/models/authentication_create_token_params.rbs +15 -0
  118. data/sig/galaxy-ruby/models/authentication_create_token_response.rbs +15 -0
  119. data/sig/galaxy-ruby/models/authentication_create_user_params.rbs +34 -0
  120. data/sig/galaxy-ruby/models/authentication_list_me_params.rbs +15 -0
  121. data/sig/galaxy-ruby/models/celestial_body.rbs +76 -0
  122. data/sig/galaxy-ruby/models/celestial_body_create_params.rbs +24 -0
  123. data/sig/galaxy-ruby/models/credentials.rbs +15 -0
  124. data/sig/galaxy-ruby/models/new_planet_webhook_event.rbs +211 -0
  125. data/sig/galaxy-ruby/models/planet.rbs +211 -0
  126. data/sig/galaxy-ruby/models/planet_create_params.rbs +15 -0
  127. data/sig/galaxy-ruby/models/planet_delete_params.rbs +23 -0
  128. data/sig/galaxy-ruby/models/planet_delte_image_params.rbs +32 -0
  129. data/sig/galaxy-ruby/models/planet_delte_image_response.rbs +50 -0
  130. data/sig/galaxy-ruby/models/planet_list_all_data_params.rbs +32 -0
  131. data/sig/galaxy-ruby/models/planet_list_all_data_response.rbs +64 -0
  132. data/sig/galaxy-ruby/models/planet_retrieve_params.rbs +23 -0
  133. data/sig/galaxy-ruby/models/planet_update_params.rbs +25 -0
  134. data/sig/galaxy-ruby/models/unwrap_webhook_event.rbs +11 -0
  135. data/sig/galaxy-ruby/models/user.rbs +19 -0
  136. data/sig/galaxy-ruby/models/webhook_unwrap_params.rbs +15 -0
  137. data/sig/galaxy-ruby/models.rbs +35 -0
  138. data/sig/galaxy-ruby/request_options.rbs +34 -0
  139. data/sig/galaxy-ruby/resources/authentication.rbs +24 -0
  140. data/sig/galaxy-ruby/resources/celestial_bodies.rbs +12 -0
  141. data/sig/galaxy-ruby/resources/planets.rbs +68 -0
  142. data/sig/galaxy-ruby/resources/webhooks.rbs +13 -0
  143. data/sig/galaxy-ruby/version.rbs +3 -0
  144. data/sig/manifest.yaml +6 -0
  145. metadata +245 -0
@@ -0,0 +1,333 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ScalarGalaxy
4
+ module Internal
5
+ module Type
6
+ # @api private
7
+ module Converter
8
+ extend ScalarGalaxy::Internal::Util::SorbetRuntimeSupport
9
+
10
+ # rubocop:disable Lint/UnusedMethodArgument
11
+
12
+ # @api private
13
+ #
14
+ # @param value [Object]
15
+ #
16
+ # @param state [Hash{Symbol=>Object}] .
17
+ #
18
+ # @option state [Boolean] :translate_names
19
+ #
20
+ # @option state [Boolean] :strictness
21
+ #
22
+ # @option state [Hash{Symbol=>Object}] :exactness
23
+ #
24
+ # @option state [Class<StandardError>] :error
25
+ #
26
+ # @option state [Integer] :branched
27
+ #
28
+ # @return [Object]
29
+ def coerce(value, state:) = (raise NotImplementedError)
30
+
31
+ # @api private
32
+ #
33
+ # @param value [Object]
34
+ #
35
+ # @param state [Hash{Symbol=>Object}] .
36
+ #
37
+ # @option state [Boolean] :can_retry
38
+ #
39
+ # @return [Object]
40
+ def dump(value, state:)
41
+ case value
42
+ in Array
43
+ value.map { ScalarGalaxy::Internal::Type::Unknown.dump(_1, state: state) }
44
+ in Hash
45
+ value.transform_values { ScalarGalaxy::Internal::Type::Unknown.dump(_1, state: state) }
46
+ in ScalarGalaxy::Internal::Type::BaseModel
47
+ value.class.dump(value, state: state)
48
+ in StringIO
49
+ value.string
50
+ in Pathname | IO
51
+ state[:can_retry] = false if value.is_a?(IO)
52
+ ScalarGalaxy::FilePart.new(value)
53
+ in ScalarGalaxy::FilePart
54
+ state[:can_retry] = false if value.content.is_a?(IO)
55
+ value
56
+ else
57
+ value
58
+ end
59
+ end
60
+
61
+ # @api private
62
+ #
63
+ # @param depth [Integer]
64
+ #
65
+ # @return [String]
66
+ def inspect(depth: 0)
67
+ super()
68
+ end
69
+
70
+ # rubocop:enable Lint/UnusedMethodArgument
71
+
72
+ class << self
73
+ # @api private
74
+ #
75
+ # @param spec [Hash{Symbol=>Object}, Proc, ScalarGalaxy::Internal::Type::Converter, Class] .
76
+ #
77
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
78
+ #
79
+ # @option spec [Proc] :enum
80
+ #
81
+ # @option spec [Proc] :union
82
+ #
83
+ # @option spec [Boolean] :"nil?"
84
+ #
85
+ # @return [Proc]
86
+ def type_info(spec)
87
+ case spec
88
+ in Proc
89
+ spec
90
+ in Hash
91
+ type_info(spec.slice(:const, :enum, :union).first&.last)
92
+ in true | false
93
+ -> { ScalarGalaxy::Internal::Type::Boolean }
94
+ in ScalarGalaxy::Internal::Type::Converter | Class | Symbol
95
+ -> { spec }
96
+ in NilClass | Integer | Float
97
+ -> { spec.class }
98
+ end
99
+ end
100
+
101
+ # @api private
102
+ #
103
+ # @param type_info [Hash{Symbol=>Object}, Proc, ScalarGalaxy::Internal::Type::Converter, Class] .
104
+ #
105
+ # @option type_info [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
106
+ #
107
+ # @option type_info [Proc] :enum
108
+ #
109
+ # @option type_info [Proc] :union
110
+ #
111
+ # @option type_info [Boolean] :"nil?"
112
+ #
113
+ # @param spec [Hash{Symbol=>Object}, Proc, ScalarGalaxy::Internal::Type::Converter, Class] .
114
+ #
115
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
116
+ #
117
+ # @option spec [Proc] :enum
118
+ #
119
+ # @option spec [Proc] :union
120
+ #
121
+ # @option spec [Boolean] :"nil?"
122
+ #
123
+ # @return [Hash{Symbol=>Object}]
124
+ def meta_info(type_info, spec)
125
+ [spec, type_info].grep(Hash).first.to_h.except(:const, :enum, :union, :nil?)
126
+ end
127
+
128
+ # @api private
129
+ #
130
+ # @param translate_names [Boolean]
131
+ #
132
+ # @return [Hash{Symbol=>Object}]
133
+ def new_coerce_state(translate_names: true)
134
+ {
135
+ translate_names: translate_names,
136
+ strictness: true,
137
+ exactness: {
138
+ yes: 0,
139
+ no: 0,
140
+ maybe: 0
141
+ },
142
+ error: nil,
143
+ branched: 0
144
+ }
145
+ end
146
+
147
+ # @api private
148
+ #
149
+ # Based on `target`, transform `value` into `target`, to the extent possible:
150
+ #
151
+ # 1. if the given `value` conforms to `target` already, return the given `value`
152
+ # 2. if it's possible and safe to convert the given `value` to `target`, then the
153
+ # converted value
154
+ # 3. otherwise, the given `value` unaltered
155
+ #
156
+ # The coercion process is subject to improvement between minor release versions.
157
+ # See https://docs.pydantic.dev/latest/concepts/unions/#smart-mode
158
+ #
159
+ # @param target [ScalarGalaxy::Internal::Type::Converter, Class]
160
+ #
161
+ # @param value [Object]
162
+ #
163
+ # @param state [Hash{Symbol=>Object}] The `strictness` is one of `true`, `false`. This informs the coercion strategy
164
+ # when we have to decide between multiple possible conversion targets:
165
+ #
166
+ # - `true`: the conversion must be exact, with minimum coercion.
167
+ # - `false`: the conversion can be approximate, with some coercion.
168
+ #
169
+ # The `exactness` is `Hash` with keys being one of `yes`, `no`, or `maybe`. For
170
+ # any given conversion attempt, the exactness will be updated based on how closely
171
+ # the value recursively matches the target type:
172
+ #
173
+ # - `yes`: the value can be converted to the target type with minimum coercion.
174
+ # - `maybe`: the value can be converted to the target type with some reasonable
175
+ # coercion.
176
+ # - `no`: the value cannot be converted to the target type.
177
+ #
178
+ # See implementation below for more details.
179
+ #
180
+ # @option state [Boolean] :translate_names
181
+ #
182
+ # @option state [Boolean] :strictness
183
+ #
184
+ # @option state [Hash{Symbol=>Object}] :exactness
185
+ #
186
+ # @option state [Class<StandardError>] :error
187
+ #
188
+ # @option state [Integer] :branched
189
+ #
190
+ # @return [Object]
191
+ def coerce(target, value, state: ScalarGalaxy::Internal::Type::Converter.new_coerce_state)
192
+ # rubocop:disable Metrics/BlockNesting
193
+ exactness = state.fetch(:exactness)
194
+
195
+ case target
196
+ in ScalarGalaxy::Internal::Type::Converter
197
+ return target.coerce(value, state: state)
198
+ in Class
199
+ if value.is_a?(target)
200
+ exactness[:yes] += 1
201
+ return value
202
+ end
203
+
204
+ case target
205
+ in -> { _1 <= NilClass }
206
+ exactness[value.nil? ? :yes : :maybe] += 1
207
+ return nil
208
+ in -> { _1 <= Integer }
209
+ case value
210
+ in Integer
211
+ exactness[:yes] += 1
212
+ return value
213
+ else
214
+ Kernel.then do
215
+ return Integer(value).tap { exactness[:maybe] += 1 }
216
+ rescue ArgumentError, TypeError => e
217
+ state[:error] = e
218
+ end
219
+ end
220
+ in -> { _1 <= Float }
221
+ if value.is_a?(Numeric)
222
+ exactness[:yes] += 1
223
+ return Float(value)
224
+ else
225
+ Kernel.then do
226
+ return Float(value).tap { exactness[:maybe] += 1 }
227
+ rescue ArgumentError, TypeError => e
228
+ state[:error] = e
229
+ end
230
+ end
231
+ in -> { _1 <= String }
232
+ case value
233
+ in String | Symbol | Numeric
234
+ exactness[value.is_a?(Numeric) ? :maybe : :yes] += 1
235
+ return value.to_s
236
+ in StringIO
237
+ exactness[:yes] += 1
238
+ return value.string
239
+ else
240
+ state[:error] = TypeError.new("#{value.class} can't be coerced into #{String}")
241
+ end
242
+ in -> { _1 <= Date || _1 <= Time }
243
+ Kernel.then do
244
+ return target.parse(value).tap { exactness[:yes] += 1 }
245
+ rescue ArgumentError, TypeError => e
246
+ state[:error] = e
247
+ end
248
+ in -> { _1 <= StringIO } if value.is_a?(String)
249
+ exactness[:yes] += 1
250
+ return StringIO.new(value.b)
251
+ else
252
+ end
253
+ in Symbol
254
+ case value
255
+ in Symbol | String
256
+ if value.to_sym == target
257
+ exactness[:yes] += 1
258
+ return target
259
+ else
260
+ exactness[:maybe] += 1
261
+ return value
262
+ end
263
+ else
264
+ message = "cannot convert non-matching #{value.class} into #{target.inspect}"
265
+ state[:error] = ArgumentError.new(message)
266
+ end
267
+ else
268
+ end
269
+
270
+ exactness[:no] += 1
271
+ value
272
+ # rubocop:enable Metrics/BlockNesting
273
+ end
274
+
275
+ # @api private
276
+ #
277
+ # @param target [ScalarGalaxy::Internal::Type::Converter, Class]
278
+ #
279
+ # @param value [Object]
280
+ #
281
+ # @param state [Hash{Symbol=>Object}] .
282
+ #
283
+ # @option state [Boolean] :can_retry
284
+ #
285
+ # @return [Object]
286
+ def dump(target, value, state: {can_retry: true})
287
+ case target
288
+ in ScalarGalaxy::Internal::Type::Converter
289
+ target.dump(value, state: state)
290
+ else
291
+ ScalarGalaxy::Internal::Type::Unknown.dump(value, state: state)
292
+ end
293
+ end
294
+
295
+ # @api private
296
+ #
297
+ # @param target [Object]
298
+ # @param depth [Integer]
299
+ #
300
+ # @return [String]
301
+ def inspect(target, depth:)
302
+ case target
303
+ in ScalarGalaxy::Internal::Type::Converter
304
+ target.inspect(depth: depth.succ)
305
+ else
306
+ target.inspect
307
+ end
308
+ end
309
+ end
310
+
311
+ define_sorbet_constant!(:Input) do
312
+ T.type_alias { T.any(ScalarGalaxy::Internal::Type::Converter, T::Class[T.anything]) }
313
+ end
314
+ define_sorbet_constant!(:CoerceState) do
315
+ T.type_alias do
316
+ {
317
+ translate_names: T::Boolean,
318
+ strictness: T::Boolean,
319
+ exactness: {
320
+ yes: Integer,
321
+ no: Integer,
322
+ maybe: Integer
323
+ },
324
+ error: T::Class[StandardError],
325
+ branched: Integer
326
+ }
327
+ end
328
+ end
329
+ define_sorbet_constant!(:DumpState) { T.type_alias { {can_retry: T::Boolean} } }
330
+ end
331
+ end
332
+ end
333
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ScalarGalaxy
4
+ module Internal
5
+ module Type
6
+ # @api private
7
+ #
8
+ # A value from among a specified list of options. OpenAPI enum values map to Ruby
9
+ # values in the SDK as follows:
10
+ #
11
+ # 1. boolean => true | false
12
+ # 2. integer => Integer
13
+ # 3. float => Float
14
+ # 4. string => Symbol
15
+ #
16
+ # We can therefore convert string values to Symbols, but can't convert other
17
+ # values safely.
18
+ #
19
+ module Enum
20
+ include ScalarGalaxy::Internal::Type::Converter
21
+ include ScalarGalaxy::Internal::Util::SorbetRuntimeSupport
22
+
23
+ # All of the valid Symbol values for this enum.
24
+ #
25
+ # @return [Array<NilClass, Boolean, Integer, Float, Symbol>]
26
+ def values = constants.map { const_get(_1) }
27
+
28
+ # @api public
29
+ #
30
+ # @param other [Object]
31
+ #
32
+ # @return [Boolean]
33
+ def ===(other) = values.include?(other)
34
+
35
+ # @api public
36
+ #
37
+ # @param other [Object]
38
+ #
39
+ # @return [Boolean]
40
+ def ==(other)
41
+ # rubocop:disable Style/CaseEquality
42
+ ScalarGalaxy::Internal::Type::Enum === other && other.values.to_set == values.to_set
43
+ # rubocop:enable Style/CaseEquality
44
+ end
45
+
46
+ # @api public
47
+ #
48
+ # @return [Integer]
49
+ def hash = values.to_set.hash
50
+
51
+ # @api private
52
+ #
53
+ # Unlike with primitives, `Enum` additionally validates that the value is a member
54
+ # of the enum.
55
+ #
56
+ # @param value [String, Symbol, Object]
57
+ #
58
+ # @param state [Hash{Symbol=>Object}] .
59
+ #
60
+ # @option state [Boolean] :translate_names
61
+ #
62
+ # @option state [Boolean] :strictness
63
+ #
64
+ # @option state [Hash{Symbol=>Object}] :exactness
65
+ #
66
+ # @option state [Class<StandardError>] :error
67
+ #
68
+ # @option state [Integer] :branched
69
+ #
70
+ # @return [Symbol, Object]
71
+ def coerce(value, state:)
72
+ exactness = state.fetch(:exactness)
73
+ val = value.is_a?(String) ? value.to_sym : value
74
+
75
+ if values.include?(val)
76
+ exactness[:yes] += 1
77
+ val
78
+ elsif values.first&.class == val.class
79
+ exactness[:maybe] += 1
80
+ value
81
+ else
82
+ exactness[:no] += 1
83
+ state[:error] = TypeError.new("#{value.class} can't be coerced into #{self}")
84
+ value
85
+ end
86
+ end
87
+
88
+ # @!method dump(value, state:)
89
+ # @api private
90
+ #
91
+ # @param value [Symbol, Object]
92
+ #
93
+ # @param state [Hash{Symbol=>Object}] .
94
+ #
95
+ # @option state [Boolean] :can_retry
96
+ #
97
+ # @return [Symbol, Object]
98
+
99
+ # @api private
100
+ #
101
+ # @return [Object]
102
+ def to_sorbet_type
103
+ types = values.map { ScalarGalaxy::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(_1) }.uniq
104
+ case types
105
+ in []
106
+ T.noreturn
107
+ in [type]
108
+ type
109
+ else
110
+ T.any(*types)
111
+ end
112
+ end
113
+
114
+ # @api private
115
+ #
116
+ # @param depth [Integer]
117
+ #
118
+ # @return [String]
119
+ def inspect(depth: 0)
120
+ return is_a?(Module) ? super() : self.class.name if depth.positive?
121
+
122
+ members = values.map { ScalarGalaxy::Internal::Type::Converter.inspect(_1, depth: depth.succ) }
123
+ prefix = is_a?(Module) ? name : self.class.name
124
+
125
+ "#{prefix}[#{members.join(" | ")}]"
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ScalarGalaxy
4
+ module Internal
5
+ module Type
6
+ # @api private
7
+ #
8
+ # @abstract
9
+ #
10
+ # Either `Pathname` or `StringIO`, or `IO`, or
11
+ # `ScalarGalaxy::Internal::Type::FileInput`.
12
+ #
13
+ # Note: when `IO` is used, all retries are disabled, since many IO` streams are
14
+ # not rewindable.
15
+ class FileInput
16
+ extend ScalarGalaxy::Internal::Type::Converter
17
+
18
+ private_class_method :new
19
+
20
+ # @api public
21
+ #
22
+ # @param other [Object]
23
+ #
24
+ # @return [Boolean]
25
+ def self.===(other)
26
+ case other
27
+ in Pathname | StringIO | IO | String | ScalarGalaxy::FilePart
28
+ true
29
+ else
30
+ false
31
+ end
32
+ end
33
+
34
+ # @api public
35
+ #
36
+ # @param other [Object]
37
+ #
38
+ # @return [Boolean]
39
+ def self.==(other) = other.is_a?(Class) && other <= ScalarGalaxy::Internal::Type::FileInput
40
+
41
+ class << self
42
+ # @api private
43
+ #
44
+ # @param value [StringIO, String, Object]
45
+ #
46
+ # @param state [Hash{Symbol=>Object}] .
47
+ #
48
+ # @option state [Boolean] :translate_names
49
+ #
50
+ # @option state [Boolean] :strictness
51
+ #
52
+ # @option state [Hash{Symbol=>Object}] :exactness
53
+ #
54
+ # @option state [Class<StandardError>] :error
55
+ #
56
+ # @option state [Integer] :branched
57
+ #
58
+ # @return [StringIO, Object]
59
+ def coerce(value, state:)
60
+ exactness = state.fetch(:exactness)
61
+ case value
62
+ in String
63
+ exactness[:yes] += 1
64
+ StringIO.new(value)
65
+ in StringIO
66
+ exactness[:yes] += 1
67
+ value
68
+ else
69
+ state[:error] = TypeError.new("#{value.class} can't be coerced into #{StringIO}")
70
+ exactness[:no] += 1
71
+ value
72
+ end
73
+ end
74
+
75
+ # @api private
76
+ #
77
+ # @param value [Pathname, StringIO, IO, String, Object]
78
+ #
79
+ # @param state [Hash{Symbol=>Object}] .
80
+ #
81
+ # @option state [Boolean] :can_retry
82
+ #
83
+ # @return [Pathname, StringIO, IO, String, Object]
84
+ def dump(value, state:)
85
+ case value
86
+ in StringIO | String
87
+ # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2
88
+ # while not required, a filename is recommended, and in practice many servers do expect this
89
+ ScalarGalaxy::FilePart.new(value, filename: "upload")
90
+ in IO
91
+ state[:can_retry] = false
92
+ value.to_path.nil? ? ScalarGalaxy::FilePart.new(value, filename: "upload") : value
93
+ in ScalarGalaxy::FilePart if value.content.is_a?(IO)
94
+ state[:can_retry] = false
95
+ value
96
+ else
97
+ value
98
+ end
99
+ end
100
+
101
+ # @api private
102
+ #
103
+ # @return [Object]
104
+ def to_sorbet_type
105
+ T.any(Pathname, StringIO, IO, String, ScalarGalaxy::FilePart)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end