brand.dev 0.0.1.pre.alpha.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 (102) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +229 -0
  3. data/SECURITY.md +23 -0
  4. data/lib/brand_dev/client.rb +74 -0
  5. data/lib/brand_dev/errors.rb +192 -0
  6. data/lib/brand_dev/file_part.rb +55 -0
  7. data/lib/brand_dev/internal/transport/base_client.rb +555 -0
  8. data/lib/brand_dev/internal/transport/pooled_net_requester.rb +209 -0
  9. data/lib/brand_dev/internal/type/array_of.rb +162 -0
  10. data/lib/brand_dev/internal/type/base_model.rb +484 -0
  11. data/lib/brand_dev/internal/type/base_page.rb +55 -0
  12. data/lib/brand_dev/internal/type/boolean.rb +71 -0
  13. data/lib/brand_dev/internal/type/converter.rb +292 -0
  14. data/lib/brand_dev/internal/type/enum.rb +120 -0
  15. data/lib/brand_dev/internal/type/file_input.rb +103 -0
  16. data/lib/brand_dev/internal/type/hash_of.rb +182 -0
  17. data/lib/brand_dev/internal/type/request_parameters.rb +42 -0
  18. data/lib/brand_dev/internal/type/union.rb +227 -0
  19. data/lib/brand_dev/internal/type/unknown.rb +75 -0
  20. data/lib/brand_dev/internal/util.rb +915 -0
  21. data/lib/brand_dev/internal.rb +20 -0
  22. data/lib/brand_dev/models/brand_identify_from_transaction_params.rb +22 -0
  23. data/lib/brand_dev/models/brand_identify_from_transaction_response.rb +435 -0
  24. data/lib/brand_dev/models/brand_retrieve_by_ticker_params.rb +22 -0
  25. data/lib/brand_dev/models/brand_retrieve_by_ticker_response.rb +432 -0
  26. data/lib/brand_dev/models/brand_retrieve_naics_params.rb +27 -0
  27. data/lib/brand_dev/models/brand_retrieve_naics_response.rb +61 -0
  28. data/lib/brand_dev/models/brand_retrieve_params.rb +91 -0
  29. data/lib/brand_dev/models/brand_retrieve_response.rb +432 -0
  30. data/lib/brand_dev/models/brand_search_params.rb +22 -0
  31. data/lib/brand_dev/models/brand_search_response.rb +35 -0
  32. data/lib/brand_dev/models.rb +51 -0
  33. data/lib/brand_dev/request_options.rb +77 -0
  34. data/lib/brand_dev/resources/brand.rb +130 -0
  35. data/lib/brand_dev/version.rb +5 -0
  36. data/lib/brand_dev.rb +64 -0
  37. data/manifest.yaml +15 -0
  38. data/rbi/brand_dev/client.rbi +49 -0
  39. data/rbi/brand_dev/errors.rbi +162 -0
  40. data/rbi/brand_dev/file_part.rbi +37 -0
  41. data/rbi/brand_dev/internal/transport/base_client.rbi +293 -0
  42. data/rbi/brand_dev/internal/transport/pooled_net_requester.rbi +79 -0
  43. data/rbi/brand_dev/internal/type/array_of.rbi +104 -0
  44. data/rbi/brand_dev/internal/type/base_model.rbi +302 -0
  45. data/rbi/brand_dev/internal/type/base_page.rbi +42 -0
  46. data/rbi/brand_dev/internal/type/boolean.rbi +56 -0
  47. data/rbi/brand_dev/internal/type/converter.rbi +162 -0
  48. data/rbi/brand_dev/internal/type/enum.rbi +82 -0
  49. data/rbi/brand_dev/internal/type/file_input.rbi +59 -0
  50. data/rbi/brand_dev/internal/type/hash_of.rbi +104 -0
  51. data/rbi/brand_dev/internal/type/request_parameters.rbi +29 -0
  52. data/rbi/brand_dev/internal/type/union.rbi +116 -0
  53. data/rbi/brand_dev/internal/type/unknown.rbi +56 -0
  54. data/rbi/brand_dev/internal/util.rbi +485 -0
  55. data/rbi/brand_dev/internal.rbi +16 -0
  56. data/rbi/brand_dev/models/brand_identify_from_transaction_params.rbi +46 -0
  57. data/rbi/brand_dev/models/brand_identify_from_transaction_response.rbi +981 -0
  58. data/rbi/brand_dev/models/brand_retrieve_by_ticker_params.rbi +43 -0
  59. data/rbi/brand_dev/models/brand_retrieve_by_ticker_response.rbi +976 -0
  60. data/rbi/brand_dev/models/brand_retrieve_naics_params.rbi +44 -0
  61. data/rbi/brand_dev/models/brand_retrieve_naics_response.rbi +127 -0
  62. data/rbi/brand_dev/models/brand_retrieve_params.rbi +344 -0
  63. data/rbi/brand_dev/models/brand_retrieve_response.rbi +949 -0
  64. data/rbi/brand_dev/models/brand_search_params.rbi +40 -0
  65. data/rbi/brand_dev/models/brand_search_response.rbi +63 -0
  66. data/rbi/brand_dev/models.rbi +14 -0
  67. data/rbi/brand_dev/request_options.rbi +59 -0
  68. data/rbi/brand_dev/resources/brand.rbi +89 -0
  69. data/rbi/brand_dev/version.rbi +5 -0
  70. data/sig/brand_dev/client.rbs +26 -0
  71. data/sig/brand_dev/errors.rbs +101 -0
  72. data/sig/brand_dev/file_part.rbs +21 -0
  73. data/sig/brand_dev/internal/transport/base_client.rbs +131 -0
  74. data/sig/brand_dev/internal/transport/pooled_net_requester.rbs +45 -0
  75. data/sig/brand_dev/internal/type/array_of.rbs +48 -0
  76. data/sig/brand_dev/internal/type/base_model.rbs +102 -0
  77. data/sig/brand_dev/internal/type/base_page.rbs +24 -0
  78. data/sig/brand_dev/internal/type/boolean.rbs +26 -0
  79. data/sig/brand_dev/internal/type/converter.rbs +56 -0
  80. data/sig/brand_dev/internal/type/enum.rbs +32 -0
  81. data/sig/brand_dev/internal/type/file_input.rbs +25 -0
  82. data/sig/brand_dev/internal/type/hash_of.rbs +48 -0
  83. data/sig/brand_dev/internal/type/request_parameters.rbs +17 -0
  84. data/sig/brand_dev/internal/type/union.rbs +52 -0
  85. data/sig/brand_dev/internal/type/unknown.rbs +26 -0
  86. data/sig/brand_dev/internal/util.rbs +185 -0
  87. data/sig/brand_dev/internal.rbs +9 -0
  88. data/sig/brand_dev/models/brand_identify_from_transaction_params.rbs +24 -0
  89. data/sig/brand_dev/models/brand_identify_from_transaction_response.rbs +418 -0
  90. data/sig/brand_dev/models/brand_retrieve_by_ticker_params.rbs +23 -0
  91. data/sig/brand_dev/models/brand_retrieve_by_ticker_response.rbs +418 -0
  92. data/sig/brand_dev/models/brand_retrieve_naics_params.rbs +23 -0
  93. data/sig/brand_dev/models/brand_retrieve_naics_response.rbs +61 -0
  94. data/sig/brand_dev/models/brand_retrieve_params.rbs +148 -0
  95. data/sig/brand_dev/models/brand_retrieve_response.rbs +418 -0
  96. data/sig/brand_dev/models/brand_search_params.rbs +23 -0
  97. data/sig/brand_dev/models/brand_search_response.rbs +29 -0
  98. data/sig/brand_dev/models.rbs +11 -0
  99. data/sig/brand_dev/request_options.rbs +34 -0
  100. data/sig/brand_dev/resources/brand.rbs +33 -0
  101. data/sig/brand_dev/version.rbs +3 -0
  102. metadata +160 -0
@@ -0,0 +1,292 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BrandDev
4
+ module Internal
5
+ module Type
6
+ # @api private
7
+ module Converter
8
+ extend BrandDev::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, :strong] :strictness
19
+ #
20
+ # @option state [Hash{Symbol=>Object}] :exactness
21
+ #
22
+ # @option state [Integer] :branched
23
+ #
24
+ # @return [Object]
25
+ def coerce(value, state:) = (raise NotImplementedError)
26
+
27
+ # @api private
28
+ #
29
+ # @param value [Object]
30
+ #
31
+ # @param state [Hash{Symbol=>Object}] .
32
+ #
33
+ # @option state [Boolean] :can_retry
34
+ #
35
+ # @return [Object]
36
+ def dump(value, state:)
37
+ case value
38
+ in Array
39
+ value.map { BrandDev::Internal::Type::Unknown.dump(_1, state: state) }
40
+ in Hash
41
+ value.transform_values { BrandDev::Internal::Type::Unknown.dump(_1, state: state) }
42
+ in BrandDev::Internal::Type::BaseModel
43
+ value.class.dump(value, state: state)
44
+ in StringIO
45
+ value.string
46
+ in Pathname | IO
47
+ state[:can_retry] = false if value.is_a?(IO)
48
+ BrandDev::FilePart.new(value)
49
+ in BrandDev::FilePart
50
+ state[:can_retry] = false if value.content.is_a?(IO)
51
+ value
52
+ else
53
+ value
54
+ end
55
+ end
56
+
57
+ # @api private
58
+ #
59
+ # @param depth [Integer]
60
+ #
61
+ # @return [String]
62
+ def inspect(depth: 0)
63
+ super()
64
+ end
65
+
66
+ # rubocop:enable Lint/UnusedMethodArgument
67
+
68
+ class << self
69
+ # @api private
70
+ #
71
+ # @param spec [Hash{Symbol=>Object}, Proc, BrandDev::Internal::Type::Converter, Class] .
72
+ #
73
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
74
+ #
75
+ # @option spec [Proc] :enum
76
+ #
77
+ # @option spec [Proc] :union
78
+ #
79
+ # @option spec [Boolean] :"nil?"
80
+ #
81
+ # @return [Proc]
82
+ def type_info(spec)
83
+ case spec
84
+ in Proc
85
+ spec
86
+ in Hash
87
+ type_info(spec.slice(:const, :enum, :union).first&.last)
88
+ in true | false
89
+ -> { BrandDev::Internal::Type::Boolean }
90
+ in BrandDev::Internal::Type::Converter | Class | Symbol
91
+ -> { spec }
92
+ in NilClass | Integer | Float
93
+ -> { spec.class }
94
+ end
95
+ end
96
+
97
+ # @api private
98
+ #
99
+ # Based on `target`, transform `value` into `target`, to the extent possible:
100
+ #
101
+ # 1. if the given `value` conforms to `target` already, return the given `value`
102
+ # 2. if it's possible and safe to convert the given `value` to `target`, then the
103
+ # converted value
104
+ # 3. otherwise, the given `value` unaltered
105
+ #
106
+ # The coercion process is subject to improvement between minor release versions.
107
+ # See https://docs.pydantic.dev/latest/concepts/unions/#smart-mode
108
+ #
109
+ # @param target [BrandDev::Internal::Type::Converter, Class]
110
+ #
111
+ # @param value [Object]
112
+ #
113
+ # @param state [Hash{Symbol=>Object}] The `strictness` is one of `true`, `false`, or `:strong`. This informs the
114
+ # coercion strategy when we have to decide between multiple possible conversion
115
+ # targets:
116
+ #
117
+ # - `true`: the conversion must be exact, with minimum coercion.
118
+ # - `false`: the conversion can be approximate, with some coercion.
119
+ # - `:strong`: the conversion must be exact, with no coercion, and raise an error
120
+ # if not possible.
121
+ #
122
+ # The `exactness` is `Hash` with keys being one of `yes`, `no`, or `maybe`. For
123
+ # any given conversion attempt, the exactness will be updated based on how closely
124
+ # the value recursively matches the target type:
125
+ #
126
+ # - `yes`: the value can be converted to the target type with minimum coercion.
127
+ # - `maybe`: the value can be converted to the target type with some reasonable
128
+ # coercion.
129
+ # - `no`: the value cannot be converted to the target type.
130
+ #
131
+ # See implementation below for more details.
132
+ #
133
+ # @option state [Boolean, :strong] :strictness
134
+ #
135
+ # @option state [Hash{Symbol=>Object}] :exactness
136
+ #
137
+ # @option state [Integer] :branched
138
+ #
139
+ # @return [Object]
140
+ def coerce(
141
+ target,
142
+ value,
143
+ state: {strictness: true, exactness: {yes: 0, no: 0, maybe: 0}, branched: 0}
144
+ )
145
+ # rubocop:disable Lint/SuppressedException
146
+ # rubocop:disable Metrics/BlockNesting
147
+ strictness, exactness = state.fetch_values(:strictness, :exactness)
148
+
149
+ case target
150
+ in BrandDev::Internal::Type::Converter
151
+ return target.coerce(value, state: state)
152
+ in Class
153
+ if value.is_a?(target)
154
+ exactness[:yes] += 1
155
+ return value
156
+ end
157
+
158
+ case target
159
+ in -> { _1 <= NilClass }
160
+ exactness[value.nil? ? :yes : :maybe] += 1
161
+ return nil
162
+ in -> { _1 <= Integer }
163
+ if value.is_a?(Integer)
164
+ exactness[:yes] += 1
165
+ return value
166
+ elsif strictness == :strong && Integer(value, exception: false) != value
167
+ message = "no implicit conversion of #{value.class} into #{target.inspect}"
168
+ raise value.is_a?(Numeric) ? ArgumentError.new(message) : TypeError.new(message)
169
+ else
170
+ Kernel.then do
171
+ return Integer(value).tap { exactness[:maybe] += 1 }
172
+ rescue ArgumentError, TypeError
173
+ end
174
+ end
175
+ in -> { _1 <= Float }
176
+ if value.is_a?(Numeric)
177
+ exactness[:yes] += 1
178
+ return Float(value)
179
+ elsif strictness == :strong
180
+ message = "no implicit conversion of #{value.class} into #{target.inspect}"
181
+ raise TypeError.new(message)
182
+ else
183
+ Kernel.then do
184
+ return Float(value).tap { exactness[:maybe] += 1 }
185
+ rescue ArgumentError, TypeError
186
+ end
187
+ end
188
+ in -> { _1 <= String }
189
+ case value
190
+ in String | Symbol | Numeric
191
+ exactness[value.is_a?(Numeric) ? :maybe : :yes] += 1
192
+ return value.to_s
193
+ in StringIO
194
+ exactness[:yes] += 1
195
+ return value.string
196
+ else
197
+ if strictness == :strong
198
+ message = "no implicit conversion of #{value.class} into #{target.inspect}"
199
+ raise TypeError.new(message)
200
+ end
201
+ end
202
+ in -> { _1 <= Date || _1 <= Time }
203
+ Kernel.then do
204
+ return target.parse(value).tap { exactness[:yes] += 1 }
205
+ rescue ArgumentError, TypeError => e
206
+ raise e if strictness == :strong
207
+ end
208
+ in -> { _1 <= StringIO } if value.is_a?(String)
209
+ exactness[:yes] += 1
210
+ return StringIO.new(value.b)
211
+ else
212
+ end
213
+ in Symbol
214
+ case value
215
+ in Symbol | String
216
+ if value.to_sym == target
217
+ exactness[:yes] += 1
218
+ return target
219
+ else
220
+ exactness[:maybe] += 1
221
+ return value
222
+ end
223
+ else
224
+ if strictness == :strong
225
+ message = "cannot convert non-matching #{value.class} into #{target.inspect}"
226
+ raise ArgumentError.new(message)
227
+ end
228
+ end
229
+ else
230
+ end
231
+
232
+ exactness[:no] += 1
233
+ value
234
+ # rubocop:enable Metrics/BlockNesting
235
+ # rubocop:enable Lint/SuppressedException
236
+ end
237
+
238
+ # @api private
239
+ #
240
+ # @param target [BrandDev::Internal::Type::Converter, Class]
241
+ #
242
+ # @param value [Object]
243
+ #
244
+ # @param state [Hash{Symbol=>Object}] .
245
+ #
246
+ # @option state [Boolean] :can_retry
247
+ #
248
+ # @return [Object]
249
+ def dump(target, value, state: {can_retry: true})
250
+ case target
251
+ in BrandDev::Internal::Type::Converter
252
+ target.dump(value, state: state)
253
+ else
254
+ BrandDev::Internal::Type::Unknown.dump(value, state: state)
255
+ end
256
+ end
257
+
258
+ # @api private
259
+ #
260
+ # @param target [Object]
261
+ # @param depth [Integer]
262
+ #
263
+ # @return [String]
264
+ def inspect(target, depth:)
265
+ case target
266
+ in BrandDev::Internal::Type::Converter
267
+ target.inspect(depth: depth.succ)
268
+ else
269
+ target.inspect
270
+ end
271
+ end
272
+ end
273
+
274
+ define_sorbet_constant!(:Input) do
275
+ T.type_alias { T.any(BrandDev::Internal::Type::Converter, T::Class[T.anything]) }
276
+ end
277
+ define_sorbet_constant!(:CoerceState) do
278
+ T.type_alias do
279
+ {
280
+ strictness: T.any(T::Boolean, Symbol),
281
+ exactness: {yes: Integer, no: Integer, maybe: Integer},
282
+ branched: Integer
283
+ }
284
+ end
285
+ end
286
+ define_sorbet_constant!(:DumpState) do
287
+ T.type_alias { {can_retry: T::Boolean} }
288
+ end
289
+ end
290
+ end
291
+ end
292
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BrandDev
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
+ module Enum
19
+ include BrandDev::Internal::Type::Converter
20
+ include BrandDev::Internal::Util::SorbetRuntimeSupport
21
+
22
+ # All of the valid Symbol values for this enum.
23
+ #
24
+ # @return [Array<NilClass, Boolean, Integer, Float, Symbol>]
25
+ def values = constants.map { const_get(_1) }
26
+
27
+ # @api public
28
+ #
29
+ # @param other [Object]
30
+ #
31
+ # @return [Boolean]
32
+ def ===(other) = values.include?(other)
33
+
34
+ # @api public
35
+ #
36
+ # @param other [Object]
37
+ #
38
+ # @return [Boolean]
39
+ def ==(other)
40
+ # rubocop:disable Style/CaseEquality
41
+ BrandDev::Internal::Type::Enum === other && other.values.to_set == values.to_set
42
+ # rubocop:enable Style/CaseEquality
43
+ end
44
+
45
+ # @api public
46
+ #
47
+ # @return [Integer]
48
+ def hash = values.to_set.hash
49
+
50
+ # @api private
51
+ #
52
+ # Unlike with primitives, `Enum` additionally validates that the value is a member
53
+ # of the enum.
54
+ #
55
+ # @param value [String, Symbol, 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 [Symbol, Object]
66
+ def coerce(value, state:)
67
+ exactness = state.fetch(:exactness)
68
+ val = value.is_a?(String) ? value.to_sym : value
69
+
70
+ if values.include?(val)
71
+ exactness[:yes] += 1
72
+ val
73
+ else
74
+ exactness[values.first&.class == val.class ? :maybe : :no] += 1
75
+ value
76
+ end
77
+ end
78
+
79
+ # @!method dump(value, state:)
80
+ # @api private
81
+ #
82
+ # @param value [Symbol, Object]
83
+ #
84
+ # @param state [Hash{Symbol=>Object}] .
85
+ #
86
+ # @option state [Boolean] :can_retry
87
+ #
88
+ # @return [Symbol, Object]
89
+
90
+ # @api private
91
+ #
92
+ # @return [Object]
93
+ def to_sorbet_type
94
+ case values
95
+ in []
96
+ T.noreturn
97
+ in [value, *_]
98
+ T.all(BrandDev::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(value), self)
99
+ end
100
+ end
101
+
102
+ # @api private
103
+ #
104
+ # @param depth [Integer]
105
+ #
106
+ # @return [String]
107
+ def inspect(depth: 0)
108
+ if depth.positive?
109
+ return is_a?(Module) ? super() : self.class.name
110
+ end
111
+
112
+ members = values.map { BrandDev::Internal::Type::Converter.inspect(_1, depth: depth.succ) }
113
+ prefix = is_a?(Module) ? name : self.class.name
114
+
115
+ "#{prefix}[#{members.join(' | ')}]"
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BrandDev
4
+ module Internal
5
+ module Type
6
+ # @api private
7
+ #
8
+ # @abstract
9
+ #
10
+ # Either `Pathname` or `StringIO`, or `IO`, or
11
+ # `BrandDev::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 BrandDev::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 | BrandDev::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 <= BrandDev::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, :strong] :strictness
49
+ #
50
+ # @option state [Hash{Symbol=>Object}] :exactness
51
+ #
52
+ # @option state [Integer] :branched
53
+ #
54
+ # @return [StringIO, Object]
55
+ def coerce(value, state:)
56
+ exactness = state.fetch(:exactness)
57
+ case value
58
+ in String
59
+ exactness[:yes] += 1
60
+ StringIO.new(value)
61
+ in StringIO
62
+ exactness[:yes] += 1
63
+ value
64
+ else
65
+ exactness[:no] += 1
66
+ value
67
+ end
68
+ end
69
+
70
+ # @api private
71
+ #
72
+ # @param value [Pathname, StringIO, IO, String, Object]
73
+ #
74
+ # @param state [Hash{Symbol=>Object}] .
75
+ #
76
+ # @option state [Boolean] :can_retry
77
+ #
78
+ # @return [Pathname, StringIO, IO, String, Object]
79
+ def dump(value, state:)
80
+ # rubocop:disable Lint/DuplicateBranch
81
+ case value
82
+ in IO
83
+ state[:can_retry] = false
84
+ in BrandDev::FilePart if value.content.is_a?(IO)
85
+ state[:can_retry] = false
86
+ else
87
+ end
88
+ # rubocop:enable Lint/DuplicateBranch
89
+
90
+ value
91
+ end
92
+
93
+ # @api private
94
+ #
95
+ # @return [Object]
96
+ def to_sorbet_type
97
+ T.any(Pathname, StringIO, IO, String, BrandDev::FilePart)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BrandDev
4
+ module Internal
5
+ module Type
6
+ # @api private
7
+ #
8
+ # @abstract
9
+ #
10
+ # @generic Elem
11
+ #
12
+ # Hash of items of a given type.
13
+ class HashOf
14
+ include BrandDev::Internal::Type::Converter
15
+ include BrandDev::Internal::Util::SorbetRuntimeSupport
16
+
17
+ private_class_method :new
18
+
19
+ # @overload [](type_info, spec = {})
20
+ #
21
+ # @param type_info [Hash{Symbol=>Object}, Proc, BrandDev::Internal::Type::Converter, Class]
22
+ #
23
+ # @param spec [Hash{Symbol=>Object}] .
24
+ #
25
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
26
+ #
27
+ # @option spec [Proc] :enum
28
+ #
29
+ # @option spec [Proc] :union
30
+ #
31
+ # @option spec [Boolean] :"nil?"
32
+ #
33
+ # @return [self]
34
+ def self.[](...) = new(...)
35
+
36
+ # @api public
37
+ #
38
+ # @param other [Object]
39
+ #
40
+ # @return [Boolean]
41
+ def ===(other)
42
+ type = item_type
43
+ case other
44
+ in Hash
45
+ other.all? do |key, val|
46
+ case [key, val]
47
+ in [Symbol | String, ^type]
48
+ true
49
+ else
50
+ false
51
+ end
52
+ end
53
+ else
54
+ false
55
+ end
56
+ end
57
+
58
+ # @api public
59
+ #
60
+ # @param other [Object]
61
+ #
62
+ # @return [Boolean]
63
+ def ==(other)
64
+ # rubocop:disable Layout/LineLength
65
+ other.is_a?(BrandDev::Internal::Type::HashOf) && other.nilable? == nilable? && other.item_type == item_type
66
+ # rubocop:enable Layout/LineLength
67
+ end
68
+
69
+ # @api public
70
+ #
71
+ # @return [Integer]
72
+ def hash = [self.class, item_type].hash
73
+
74
+ # @api private
75
+ #
76
+ # @param value [Hash{Object=>Object}, Object]
77
+ #
78
+ # @param state [Hash{Symbol=>Object}] .
79
+ #
80
+ # @option state [Boolean, :strong] :strictness
81
+ #
82
+ # @option state [Hash{Symbol=>Object}] :exactness
83
+ #
84
+ # @option state [Integer] :branched
85
+ #
86
+ # @return [Hash{Symbol=>Object}, Object]
87
+ def coerce(value, state:)
88
+ exactness = state.fetch(:exactness)
89
+
90
+ unless value.is_a?(Hash)
91
+ exactness[:no] += 1
92
+ return value
93
+ end
94
+
95
+ target = item_type
96
+ exactness[:yes] += 1
97
+ value
98
+ .to_h do |key, val|
99
+ k = key.is_a?(String) ? key.to_sym : key
100
+ v =
101
+ case [nilable?, val]
102
+ in [true, nil]
103
+ exactness[:yes] += 1
104
+ nil
105
+ else
106
+ BrandDev::Internal::Type::Converter.coerce(target, val, state: state)
107
+ end
108
+
109
+ exactness[:no] += 1 unless k.is_a?(Symbol)
110
+ [k, v]
111
+ end
112
+ end
113
+
114
+ # @api private
115
+ #
116
+ # @param value [Hash{Object=>Object}, Object]
117
+ #
118
+ # @param state [Hash{Symbol=>Object}] .
119
+ #
120
+ # @option state [Boolean] :can_retry
121
+ #
122
+ # @return [Hash{Symbol=>Object}, Object]
123
+ def dump(value, state:)
124
+ target = item_type
125
+ if value.is_a?(Hash)
126
+ value.transform_values do
127
+ BrandDev::Internal::Type::Converter.dump(target, _1, state: state)
128
+ end
129
+ else
130
+ super
131
+ end
132
+ end
133
+
134
+ # @api private
135
+ #
136
+ # @return [Object]
137
+ def to_sorbet_type
138
+ T::Hash[BrandDev::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(item_type)]
139
+ end
140
+
141
+ # @api private
142
+ #
143
+ # @return [generic<Elem>]
144
+ protected def item_type = @item_type_fn.call
145
+
146
+ # @api private
147
+ #
148
+ # @return [Boolean]
149
+ protected def nilable? = @nilable
150
+
151
+ # @api private
152
+ #
153
+ # @param type_info [Hash{Symbol=>Object}, Proc, BrandDev::Internal::Type::Converter, Class]
154
+ #
155
+ # @param spec [Hash{Symbol=>Object}] .
156
+ #
157
+ # @option spec [NilClass, TrueClass, FalseClass, Integer, Float, Symbol] :const
158
+ #
159
+ # @option spec [Proc] :enum
160
+ #
161
+ # @option spec [Proc] :union
162
+ #
163
+ # @option spec [Boolean] :"nil?"
164
+ def initialize(type_info, spec = {})
165
+ @item_type_fn = BrandDev::Internal::Type::Converter.type_info(type_info || spec)
166
+ @nilable = spec.fetch(:nil?, false)
167
+ end
168
+
169
+ # @api private
170
+ #
171
+ # @param depth [Integer]
172
+ #
173
+ # @return [String]
174
+ def inspect(depth: 0)
175
+ items = BrandDev::Internal::Type::Converter.inspect(item_type, depth: depth.succ)
176
+
177
+ "#{self.class}[#{[items, nilable? ? 'nil' : nil].compact.join(' | ')}]"
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end