yasmina-motor-ruby 0.0.8
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.
- checksums.yaml +7 -0
- data/.fern/metadata.json +10 -0
- data/.fern/replay.lock +10 -0
- data/.fernignore +4 -0
- data/.rubocop.yml +103 -0
- data/CONTRIBUTING.md +120 -0
- data/LICENSE +21 -0
- data/README.md +173 -0
- data/Rakefile +20 -0
- data/custom.gemspec.rb +16 -0
- data/lib/yasminaai/client.rb +37 -0
- data/lib/yasminaai/environment.rb +9 -0
- data/lib/yasminaai/errors/api_error.rb +8 -0
- data/lib/yasminaai/errors/client_error.rb +17 -0
- data/lib/yasminaai/errors/redirect_error.rb +8 -0
- data/lib/yasminaai/errors/response_error.rb +42 -0
- data/lib/yasminaai/errors/server_error.rb +11 -0
- data/lib/yasminaai/errors/timeout_error.rb +8 -0
- data/lib/yasminaai/internal/errors/constraint_error.rb +10 -0
- data/lib/yasminaai/internal/errors/type_error.rb +10 -0
- data/lib/yasminaai/internal/http/base_request.rb +51 -0
- data/lib/yasminaai/internal/http/raw_client.rb +215 -0
- data/lib/yasminaai/internal/iterators/cursor_item_iterator.rb +28 -0
- data/lib/yasminaai/internal/iterators/cursor_page_iterator.rb +63 -0
- data/lib/yasminaai/internal/iterators/item_iterator.rb +65 -0
- data/lib/yasminaai/internal/iterators/offset_item_iterator.rb +30 -0
- data/lib/yasminaai/internal/iterators/offset_page_iterator.rb +103 -0
- data/lib/yasminaai/internal/json/request.rb +41 -0
- data/lib/yasminaai/internal/json/serializable.rb +25 -0
- data/lib/yasminaai/internal/multipart/multipart_encoder.rb +141 -0
- data/lib/yasminaai/internal/multipart/multipart_form_data.rb +78 -0
- data/lib/yasminaai/internal/multipart/multipart_form_data_part.rb +51 -0
- data/lib/yasminaai/internal/multipart/multipart_request.rb +40 -0
- data/lib/yasminaai/internal/types/array.rb +47 -0
- data/lib/yasminaai/internal/types/boolean.rb +34 -0
- data/lib/yasminaai/internal/types/enum.rb +56 -0
- data/lib/yasminaai/internal/types/hash.rb +36 -0
- data/lib/yasminaai/internal/types/model/field.rb +38 -0
- data/lib/yasminaai/internal/types/model.rb +208 -0
- data/lib/yasminaai/internal/types/type.rb +35 -0
- data/lib/yasminaai/internal/types/union.rb +161 -0
- data/lib/yasminaai/internal/types/unknown.rb +15 -0
- data/lib/yasminaai/internal/types/utils.rb +116 -0
- data/lib/yasminaai/ot_ps/client.rb +79 -0
- data/lib/yasminaai/ot_ps/types/post_issue_otp_request.rb +21 -0
- data/lib/yasminaai/ot_ps/types/post_quote_otp_request.rb +15 -0
- data/lib/yasminaai/policies/client.rb +144 -0
- data/lib/yasminaai/policies/types/get_policies_car_policy_request.rb +11 -0
- data/lib/yasminaai/policies/types/get_policies_request.rb +35 -0
- data/lib/yasminaai/policies/types/post_policies_request.rb +21 -0
- data/lib/yasminaai/quotes/client.rb +164 -0
- data/lib/yasminaai/quotes/types/delete_quote_requests_id_request.rb +11 -0
- data/lib/yasminaai/quotes/types/delete_quote_requests_id_response.rb +11 -0
- data/lib/yasminaai/quotes/types/get_quote_requests_id_request.rb +11 -0
- data/lib/yasminaai/quotes/types/get_quote_requests_request.rb +17 -0
- data/lib/yasminaai/quotes/types/post_quote_requests_request.rb +37 -0
- data/lib/yasminaai/quotes/types/post_quote_requests_request_accept_language.rb +13 -0
- data/lib/yasminaai/quotes/types/post_quote_requests_request_drivers_item.rb +15 -0
- data/lib/yasminaai/types/bad_request_error_body.rb +11 -0
- data/lib/yasminaai/types/benefit.rb +21 -0
- data/lib/yasminaai/types/company_quote.rb +25 -0
- data/lib/yasminaai/types/company_quote_type.rb +12 -0
- data/lib/yasminaai/types/error.rb +11 -0
- data/lib/yasminaai/types/paginated_policy_response.rb +35 -0
- data/lib/yasminaai/types/paginated_quote_response.rb +35 -0
- data/lib/yasminaai/types/pagination_link.rb +13 -0
- data/lib/yasminaai/types/policy.rb +39 -0
- data/lib/yasminaai/types/policy_aggregates.rb +14 -0
- data/lib/yasminaai/types/policy_month_aggregate.rb +11 -0
- data/lib/yasminaai/types/quote_price.rb +19 -0
- data/lib/yasminaai/types/quote_request_aggregates.rb +12 -0
- data/lib/yasminaai/types/quote_response.rb +37 -0
- data/lib/yasminaai/types/quote_response_drivers_item.rb +13 -0
- data/lib/yasminaai/types/quote_response_quotes_item.rb +25 -0
- data/lib/yasminaai/types/quote_response_quotes_item_type.rb +12 -0
- data/lib/yasminaai/types/unauthorized_error_body.rb +11 -0
- data/lib/yasminaai/version.rb +5 -0
- data/lib/yasminaai.rb +72 -0
- data/reference.md +872 -0
- metadata +121 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yasminaai
|
|
4
|
+
module Internal
|
|
5
|
+
module Types
|
|
6
|
+
# @abstract
|
|
7
|
+
#
|
|
8
|
+
# An abstract model that all data objects will inherit from
|
|
9
|
+
class Model
|
|
10
|
+
include Type
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
# The defined fields for this model
|
|
14
|
+
#
|
|
15
|
+
# @api private
|
|
16
|
+
#
|
|
17
|
+
# @return [Hash<Symbol, Field>]
|
|
18
|
+
def fields
|
|
19
|
+
@fields ||= if self < Yasminaai::Internal::Types::Model
|
|
20
|
+
superclass.fields.dup
|
|
21
|
+
else
|
|
22
|
+
{}
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Any extra fields that have been created from instantiation
|
|
27
|
+
#
|
|
28
|
+
# @api private
|
|
29
|
+
#
|
|
30
|
+
# @return [Hash<Symbol, Field>]
|
|
31
|
+
def extra_fields
|
|
32
|
+
@extra_fields ||= {}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Define a new field on this model
|
|
36
|
+
#
|
|
37
|
+
# @param name [Symbol] The name of the field
|
|
38
|
+
# @param type [Class] Type of the field
|
|
39
|
+
# @option optional [Boolean] If it is an optional field
|
|
40
|
+
# @option nullable [Boolean] If it is a nullable field
|
|
41
|
+
# @option api_name [Symbol, String] Name in the API of this field. When serializing/deserializing, will use
|
|
42
|
+
# this field name
|
|
43
|
+
# @return [void]
|
|
44
|
+
def field(name, type, optional: false, nullable: false, api_name: nil, default: nil)
|
|
45
|
+
add_field_definition(name: name, type: type, optional: optional, nullable: nullable, api_name: api_name,
|
|
46
|
+
default: default)
|
|
47
|
+
|
|
48
|
+
define_accessor(name)
|
|
49
|
+
define_setter(name)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Define a new literal for this model
|
|
53
|
+
#
|
|
54
|
+
# @param name [Symbol]
|
|
55
|
+
# @param value [Object]
|
|
56
|
+
# @option api_name [Symbol, String]
|
|
57
|
+
# @return [void]
|
|
58
|
+
def literal(name, value, api_name: nil)
|
|
59
|
+
add_field_definition(name: name, type: value.class, optional: false, nullable: false, api_name: api_name,
|
|
60
|
+
value: value)
|
|
61
|
+
|
|
62
|
+
define_accessor(name)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Adds a new field definition into the class's fields registry
|
|
66
|
+
#
|
|
67
|
+
# @api private
|
|
68
|
+
#
|
|
69
|
+
# @param name [Symbol]
|
|
70
|
+
# @param type [Class]
|
|
71
|
+
# @option optional [Boolean]
|
|
72
|
+
# @return [void]
|
|
73
|
+
private def add_field_definition(name:, type:, optional:, nullable:, api_name:, default: nil, value: nil)
|
|
74
|
+
fields[name.to_sym] =
|
|
75
|
+
Field.new(name: name, type: type, optional: optional, nullable: nullable, api_name: api_name,
|
|
76
|
+
value: value, default: default)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Adds a new field definition into the class's extra fields registry
|
|
80
|
+
#
|
|
81
|
+
# @api private
|
|
82
|
+
#
|
|
83
|
+
# @param name [Symbol]
|
|
84
|
+
# @param type [Class]
|
|
85
|
+
# @option required [Boolean]
|
|
86
|
+
# @option optional [Boolean]
|
|
87
|
+
# @return [void]
|
|
88
|
+
def add_extra_field_definition(name:, type:)
|
|
89
|
+
return if extra_fields.key?(name.to_sym)
|
|
90
|
+
|
|
91
|
+
extra_fields[name.to_sym] = Field.new(name: name, type: type, optional: true, nullable: false)
|
|
92
|
+
|
|
93
|
+
define_accessor(name)
|
|
94
|
+
define_setter(name)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @api private
|
|
98
|
+
private def define_accessor(name)
|
|
99
|
+
method_name = name.to_sym
|
|
100
|
+
|
|
101
|
+
define_method(method_name) do
|
|
102
|
+
@data[name]
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @api private
|
|
107
|
+
private def define_setter(name)
|
|
108
|
+
method_name = :"#{name}="
|
|
109
|
+
|
|
110
|
+
define_method(method_name) do |val|
|
|
111
|
+
@data[name] = val
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def coerce(value, strict: (respond_to?(:strict?) ? strict? : false)) # rubocop:disable Lint/UnusedMethodArgument
|
|
116
|
+
return value if value.is_a?(self)
|
|
117
|
+
|
|
118
|
+
return value unless value.is_a?(::Hash)
|
|
119
|
+
|
|
120
|
+
new(value)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def load(str)
|
|
124
|
+
coerce(::JSON.parse(str, symbolize_names: true))
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def ===(instance)
|
|
128
|
+
instance.class.ancestors.include?(self)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Creates a new instance of this model
|
|
133
|
+
# TODO: Should all this logic be in `#coerce` instead?
|
|
134
|
+
#
|
|
135
|
+
# @param values [Hash]
|
|
136
|
+
# @option strict [Boolean]
|
|
137
|
+
# @return [self]
|
|
138
|
+
def initialize(values = {})
|
|
139
|
+
@data = {}
|
|
140
|
+
|
|
141
|
+
values = Utils.symbolize_keys(values.dup)
|
|
142
|
+
|
|
143
|
+
self.class.fields.each do |field_name, field|
|
|
144
|
+
value = values.delete(field.api_name.to_sym) || values.delete(field.api_name) || values.delete(field_name)
|
|
145
|
+
|
|
146
|
+
field_value = value || (if field.literal?
|
|
147
|
+
field.value
|
|
148
|
+
elsif field.default
|
|
149
|
+
field.default
|
|
150
|
+
end)
|
|
151
|
+
|
|
152
|
+
@data[field_name] = Utils.coerce(field.type, field_value)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Any remaining values in the input become extra fields
|
|
156
|
+
values.each do |name, value|
|
|
157
|
+
self.class.add_extra_field_definition(name: name, type: value.class)
|
|
158
|
+
|
|
159
|
+
@data[name.to_sym] = value
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def to_h
|
|
164
|
+
result = self.class.fields.merge(self.class.extra_fields).each_with_object({}) do |(name, field), acc|
|
|
165
|
+
# If there is a value present in the data, use that value
|
|
166
|
+
# If there is a `nil` value present in the data, and it is optional but NOT nullable, exclude key altogether
|
|
167
|
+
# If there is a `nil` value present in the data, and it is optional and nullable, use the nil value
|
|
168
|
+
|
|
169
|
+
value = @data[name]
|
|
170
|
+
|
|
171
|
+
next if value.nil? && field.optional && !field.nullable
|
|
172
|
+
|
|
173
|
+
if value.is_a?(::Array)
|
|
174
|
+
value = value.map { |item| item.respond_to?(:to_h) ? item.to_h : item }
|
|
175
|
+
elsif value.respond_to?(:to_h)
|
|
176
|
+
value = value.to_h
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
acc[field.api_name] = value
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Inject union discriminant if this instance was coerced from a discriminated union
|
|
183
|
+
# and the discriminant key is not already present in the result
|
|
184
|
+
discriminant_key = instance_variable_get(:@_fern_union_discriminant_key)
|
|
185
|
+
discriminant_value = instance_variable_get(:@_fern_union_discriminant_value)
|
|
186
|
+
result[discriminant_key] = discriminant_value if discriminant_key && discriminant_value && !result.key?(discriminant_key)
|
|
187
|
+
|
|
188
|
+
result
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def ==(other)
|
|
192
|
+
self.class == other.class && to_h == other.to_h
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# @return [String]
|
|
196
|
+
def inspect
|
|
197
|
+
attrs = @data.map do |name, value|
|
|
198
|
+
field = self.class.fields[name] || self.class.extra_fields[name]
|
|
199
|
+
display_value = field&.sensitive? ? "[REDACTED]" : value.inspect
|
|
200
|
+
"#{name}=#{display_value}"
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
"#<#{self.class.name}:0x#{object_id&.to_s(16)} #{attrs.join(" ")}>"
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yasminaai
|
|
4
|
+
module Internal
|
|
5
|
+
module Types
|
|
6
|
+
# @abstract
|
|
7
|
+
module Type
|
|
8
|
+
include Yasminaai::Internal::JSON::Serializable
|
|
9
|
+
|
|
10
|
+
# Coerces a value to this type
|
|
11
|
+
#
|
|
12
|
+
# @param value [unknown]
|
|
13
|
+
# @option strict [Boolean] If we should strictly coerce this value
|
|
14
|
+
def coerce(value, strict: strict?)
|
|
15
|
+
raise NotImplementedError
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Returns if strictness is on for this type, defaults to `false`
|
|
19
|
+
#
|
|
20
|
+
# @return [Boolean]
|
|
21
|
+
def strict?
|
|
22
|
+
@strict ||= false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Enable strictness by default for this type
|
|
26
|
+
#
|
|
27
|
+
# @return [void]
|
|
28
|
+
def strict!
|
|
29
|
+
@strict = true
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yasminaai
|
|
4
|
+
module Internal
|
|
5
|
+
module Types
|
|
6
|
+
# Define a union between two types
|
|
7
|
+
module Union
|
|
8
|
+
include Yasminaai::Internal::Types::Type
|
|
9
|
+
|
|
10
|
+
def members
|
|
11
|
+
@members ||= []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Add a member to this union
|
|
15
|
+
#
|
|
16
|
+
# @param type [Object]
|
|
17
|
+
# @option key [Symbol, String]
|
|
18
|
+
# @return [void]
|
|
19
|
+
def member(type, key: nil)
|
|
20
|
+
members.push([key, Utils.wrap_type(type)])
|
|
21
|
+
self
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def type_member?(type)
|
|
25
|
+
members.any? { |_key, type_fn| type == type_fn.call }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Set the discriminant for this union
|
|
29
|
+
#
|
|
30
|
+
# @param key [Symbol, String]
|
|
31
|
+
# @return [void]
|
|
32
|
+
def discriminant(key)
|
|
33
|
+
@discriminant = key
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @api private
|
|
37
|
+
private def discriminated?
|
|
38
|
+
!@discriminant.nil?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Check if value matches a type, handling type wrapper instances
|
|
42
|
+
# (Internal::Types::Hash and Internal::Types::Array instances)
|
|
43
|
+
#
|
|
44
|
+
# @param value [Object]
|
|
45
|
+
# @param member_type [Object]
|
|
46
|
+
# @return [Boolean]
|
|
47
|
+
private def type_matches?(value, member_type)
|
|
48
|
+
case member_type
|
|
49
|
+
when Yasminaai::Internal::Types::Hash
|
|
50
|
+
value.is_a?(::Hash)
|
|
51
|
+
when Yasminaai::Internal::Types::Array
|
|
52
|
+
value.is_a?(::Array)
|
|
53
|
+
when Class, Module
|
|
54
|
+
value.is_a?(member_type)
|
|
55
|
+
else
|
|
56
|
+
false
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Resolves the type of a value to be one of the members
|
|
61
|
+
#
|
|
62
|
+
# @param value [Object]
|
|
63
|
+
# @return [Class]
|
|
64
|
+
private def resolve_member(value)
|
|
65
|
+
if discriminated? && value.is_a?(::Hash)
|
|
66
|
+
# Try both symbol and string keys for the discriminant
|
|
67
|
+
discriminant_value = value.fetch(@discriminant, nil) || value.fetch(@discriminant.to_s, nil)
|
|
68
|
+
|
|
69
|
+
return if discriminant_value.nil?
|
|
70
|
+
|
|
71
|
+
# Convert to string for consistent comparison
|
|
72
|
+
discriminant_str = discriminant_value.to_s
|
|
73
|
+
|
|
74
|
+
# First try exact match
|
|
75
|
+
members_hash = members.to_h
|
|
76
|
+
result = members_hash[discriminant_str]&.call
|
|
77
|
+
return result if result
|
|
78
|
+
|
|
79
|
+
# Try case-insensitive match as fallback
|
|
80
|
+
discriminant_lower = discriminant_str.downcase
|
|
81
|
+
matching_keys = members_hash.keys.select { |k| k.to_s.downcase == discriminant_lower }
|
|
82
|
+
|
|
83
|
+
# Only use case-insensitive match if exactly one key matches (avoid ambiguity)
|
|
84
|
+
return members_hash[matching_keys.first]&.call if matching_keys.length == 1
|
|
85
|
+
|
|
86
|
+
nil
|
|
87
|
+
else
|
|
88
|
+
# First try exact type matching
|
|
89
|
+
result = members.find do |_key, mem|
|
|
90
|
+
member_type = Utils.unwrap_type(mem)
|
|
91
|
+
type_matches?(value, member_type)
|
|
92
|
+
end&.last&.call
|
|
93
|
+
|
|
94
|
+
return result if result
|
|
95
|
+
|
|
96
|
+
# For Hash values, try to coerce into Model member types
|
|
97
|
+
if value.is_a?(::Hash)
|
|
98
|
+
members.find do |_key, mem|
|
|
99
|
+
member_type = Utils.unwrap_type(mem)
|
|
100
|
+
# Check if member_type is a Model class
|
|
101
|
+
next unless member_type.is_a?(Class) && member_type <= Model
|
|
102
|
+
|
|
103
|
+
# Try to coerce the hash into this model type with strict mode
|
|
104
|
+
begin
|
|
105
|
+
candidate = Utils.coerce(member_type, value, strict: true)
|
|
106
|
+
|
|
107
|
+
# Validate that all required (non-optional) fields are present
|
|
108
|
+
# This ensures undiscriminated unions properly distinguish between member types
|
|
109
|
+
member_type.fields.each do |field_name, field|
|
|
110
|
+
raise Errors::TypeError, "Required field `#{field_name}` missing for union member #{member_type.name}" if candidate.instance_variable_get(:@data)[field_name].nil? && !field.optional
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
true
|
|
114
|
+
rescue Errors::TypeError
|
|
115
|
+
false
|
|
116
|
+
end
|
|
117
|
+
end&.last&.call
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def coerce(value, strict: strict?)
|
|
123
|
+
type = resolve_member(value)
|
|
124
|
+
|
|
125
|
+
unless type
|
|
126
|
+
return value unless strict
|
|
127
|
+
|
|
128
|
+
if discriminated?
|
|
129
|
+
raise Errors::TypeError,
|
|
130
|
+
"value of type `#{value.class}` not member of union #{self}"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
raise Errors::TypeError, "could not resolve to member of union #{self}"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
coerced = Utils.coerce(type, value, strict: strict)
|
|
137
|
+
|
|
138
|
+
# For discriminated unions, store the discriminant info on the coerced instance
|
|
139
|
+
# so it can be injected back during serialization (to_h)
|
|
140
|
+
if discriminated? && value.is_a?(::Hash) && coerced.is_a?(Model)
|
|
141
|
+
discriminant_value = value.fetch(@discriminant, nil) || value.fetch(@discriminant.to_s, nil)
|
|
142
|
+
if discriminant_value
|
|
143
|
+
coerced.instance_variable_set(:@_fern_union_discriminant_key, @discriminant.to_s)
|
|
144
|
+
coerced.instance_variable_set(:@_fern_union_discriminant_value, discriminant_value)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
coerced
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Parse JSON string and coerce to the correct union member type
|
|
152
|
+
#
|
|
153
|
+
# @param str [String] JSON string to parse
|
|
154
|
+
# @return [Object] Coerced value matching a union member
|
|
155
|
+
def load(str)
|
|
156
|
+
coerce(::JSON.parse(str, symbolize_names: true))
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yasminaai
|
|
4
|
+
module Internal
|
|
5
|
+
module Types
|
|
6
|
+
# Utilities for dealing with and checking types
|
|
7
|
+
module Utils
|
|
8
|
+
# Wraps a type into a type function
|
|
9
|
+
#
|
|
10
|
+
# @param type [Proc, Object]
|
|
11
|
+
# @return [Proc]
|
|
12
|
+
def self.wrap_type(type)
|
|
13
|
+
case type
|
|
14
|
+
when Proc
|
|
15
|
+
type
|
|
16
|
+
else
|
|
17
|
+
-> { type }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Resolves a type or type function into a type
|
|
22
|
+
#
|
|
23
|
+
# @param type [Proc, Object]
|
|
24
|
+
# @return [Object]
|
|
25
|
+
def self.unwrap_type(type)
|
|
26
|
+
type.is_a?(Proc) ? type.call : type
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.coerce(target, value, strict: false)
|
|
30
|
+
type = unwrap_type(target)
|
|
31
|
+
|
|
32
|
+
case type
|
|
33
|
+
in Array
|
|
34
|
+
case value
|
|
35
|
+
when ::Array
|
|
36
|
+
return type.coerce(value, strict: strict)
|
|
37
|
+
when Set, ::Hash
|
|
38
|
+
return coerce(type, value.to_a)
|
|
39
|
+
end
|
|
40
|
+
in Hash
|
|
41
|
+
case value
|
|
42
|
+
when ::Hash
|
|
43
|
+
return type.coerce(value, strict: strict)
|
|
44
|
+
when ::Array
|
|
45
|
+
return coerce(type, value.to_h)
|
|
46
|
+
end
|
|
47
|
+
in ->(t) { t <= NilClass }
|
|
48
|
+
return nil
|
|
49
|
+
in ->(t) { t <= String }
|
|
50
|
+
case value
|
|
51
|
+
when String, Symbol, Numeric, TrueClass, FalseClass
|
|
52
|
+
return value.to_s
|
|
53
|
+
end
|
|
54
|
+
in ->(t) { t <= Symbol }
|
|
55
|
+
case value
|
|
56
|
+
when Symbol, String
|
|
57
|
+
return value.to_sym
|
|
58
|
+
end
|
|
59
|
+
in ->(t) { t <= Integer }
|
|
60
|
+
case value
|
|
61
|
+
when Numeric, String, Time
|
|
62
|
+
return value.to_i
|
|
63
|
+
end
|
|
64
|
+
in ->(t) { t <= Float }
|
|
65
|
+
case value
|
|
66
|
+
when Numeric, Time, String
|
|
67
|
+
return value.to_f
|
|
68
|
+
end
|
|
69
|
+
in ->(t) { t <= Model }
|
|
70
|
+
case value
|
|
71
|
+
when type
|
|
72
|
+
return value
|
|
73
|
+
when ::Hash
|
|
74
|
+
return type.coerce(value, strict: strict)
|
|
75
|
+
end
|
|
76
|
+
in Module
|
|
77
|
+
case type
|
|
78
|
+
in ->(t) {
|
|
79
|
+
t.singleton_class.included_modules.include?(Enum) ||
|
|
80
|
+
t.singleton_class.included_modules.include?(Union)
|
|
81
|
+
}
|
|
82
|
+
return type.coerce(value, strict: strict)
|
|
83
|
+
else
|
|
84
|
+
value # rubocop:disable Lint/Void
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
value # rubocop:disable Lint/Void
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
raise Errors::TypeError, "cannot coerce value of type `#{value.class}` to `#{target}`" if strict
|
|
91
|
+
|
|
92
|
+
value
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.symbolize_keys(hash)
|
|
96
|
+
hash.transform_keys(&:to_sym)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Converts camelCase keys to snake_case symbols
|
|
100
|
+
# This allows SDK methods to accept both snake_case and camelCase keys
|
|
101
|
+
# e.g., { refundMethod: ... } becomes { refund_method: ... }
|
|
102
|
+
#
|
|
103
|
+
# @param hash [Hash]
|
|
104
|
+
# @return [Hash]
|
|
105
|
+
def self.normalize_keys(hash)
|
|
106
|
+
hash.transform_keys do |key|
|
|
107
|
+
key_str = key.to_s
|
|
108
|
+
# Convert camelCase to snake_case
|
|
109
|
+
snake_case = key_str.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
|
110
|
+
snake_case.to_sym
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yasminaai
|
|
4
|
+
module OtPs
|
|
5
|
+
class Client
|
|
6
|
+
# @param client [Yasminaai::Internal::Http::RawClient]
|
|
7
|
+
#
|
|
8
|
+
# @return [void]
|
|
9
|
+
def initialize(client:)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# This endpoint sends a one-time password (OTP) to the provided email and phone number for quote verification. It
|
|
14
|
+
# should be called before creating a quote request.
|
|
15
|
+
#
|
|
16
|
+
# @param request_options [Hash]
|
|
17
|
+
# @param params [Yasminaai::OtPs::Types::PostQuoteOtpRequest]
|
|
18
|
+
# @option request_options [String] :base_url
|
|
19
|
+
# @option request_options [Hash{String => Object}] :additional_headers
|
|
20
|
+
# @option request_options [Hash{String => Object}] :additional_query_parameters
|
|
21
|
+
# @option request_options [Hash{String => Object}] :additional_body_parameters
|
|
22
|
+
# @option request_options [Integer] :timeout_in_seconds
|
|
23
|
+
#
|
|
24
|
+
# @return [untyped]
|
|
25
|
+
def request_otp_for_quote_verification(request_options: {}, **params)
|
|
26
|
+
params = Yasminaai::Internal::Types::Utils.normalize_keys(params)
|
|
27
|
+
request = Yasminaai::Internal::JSON::Request.new(
|
|
28
|
+
base_url: request_options[:base_url],
|
|
29
|
+
method: "POST",
|
|
30
|
+
path: "quote-otp",
|
|
31
|
+
body: Yasminaai::OtPs::Types::PostQuoteOtpRequest.new(params).to_h,
|
|
32
|
+
request_options: request_options
|
|
33
|
+
)
|
|
34
|
+
begin
|
|
35
|
+
response = @client.send(request)
|
|
36
|
+
rescue Net::HTTPRequestTimeout
|
|
37
|
+
raise Yasminaai::Errors::TimeoutError
|
|
38
|
+
end
|
|
39
|
+
code = response.code.to_i
|
|
40
|
+
return if code.between?(200, 299)
|
|
41
|
+
|
|
42
|
+
error_class = Yasminaai::Errors::ResponseError.subclass_for_code(code)
|
|
43
|
+
raise error_class.new(response.body, code: code)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# This endpoint sends a one-time password (OTP). It should be called before issuing a policy.
|
|
47
|
+
#
|
|
48
|
+
# @param request_options [Hash]
|
|
49
|
+
# @param params [Yasminaai::OtPs::Types::PostIssueOtpRequest]
|
|
50
|
+
# @option request_options [String] :base_url
|
|
51
|
+
# @option request_options [Hash{String => Object}] :additional_headers
|
|
52
|
+
# @option request_options [Hash{String => Object}] :additional_query_parameters
|
|
53
|
+
# @option request_options [Hash{String => Object}] :additional_body_parameters
|
|
54
|
+
# @option request_options [Integer] :timeout_in_seconds
|
|
55
|
+
#
|
|
56
|
+
# @return [untyped]
|
|
57
|
+
def request_otp_for_issuing_policy(request_options: {}, **params)
|
|
58
|
+
params = Yasminaai::Internal::Types::Utils.normalize_keys(params)
|
|
59
|
+
request = Yasminaai::Internal::JSON::Request.new(
|
|
60
|
+
base_url: request_options[:base_url],
|
|
61
|
+
method: "POST",
|
|
62
|
+
path: "issue-otp",
|
|
63
|
+
body: Yasminaai::OtPs::Types::PostIssueOtpRequest.new(params).to_h,
|
|
64
|
+
request_options: request_options
|
|
65
|
+
)
|
|
66
|
+
begin
|
|
67
|
+
response = @client.send(request)
|
|
68
|
+
rescue Net::HTTPRequestTimeout
|
|
69
|
+
raise Yasminaai::Errors::TimeoutError
|
|
70
|
+
end
|
|
71
|
+
code = response.code.to_i
|
|
72
|
+
return if code.between?(200, 299)
|
|
73
|
+
|
|
74
|
+
error_class = Yasminaai::Errors::ResponseError.subclass_for_code(code)
|
|
75
|
+
raise error_class.new(response.body, code: code)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yasminaai
|
|
4
|
+
module OtPs
|
|
5
|
+
module Types
|
|
6
|
+
class PostIssueOtpRequest < Internal::Types::Model
|
|
7
|
+
field :email, -> { String }, optional: false, nullable: false
|
|
8
|
+
|
|
9
|
+
field :phone, -> { String }, optional: false, nullable: false
|
|
10
|
+
|
|
11
|
+
field :owner_id, -> { String }, optional: false, nullable: false
|
|
12
|
+
|
|
13
|
+
field :quote_request_id, -> { Integer }, optional: false, nullable: false
|
|
14
|
+
|
|
15
|
+
field :quote_reference_id, -> { String }, optional: false, nullable: false
|
|
16
|
+
|
|
17
|
+
field :quote_price_id, -> { String }, optional: false, nullable: false
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yasminaai
|
|
4
|
+
module OtPs
|
|
5
|
+
module Types
|
|
6
|
+
class PostQuoteOtpRequest < Internal::Types::Model
|
|
7
|
+
field :email, -> { String }, optional: false, nullable: false
|
|
8
|
+
|
|
9
|
+
field :phone, -> { String }, optional: false, nullable: false
|
|
10
|
+
|
|
11
|
+
field :owner_id, -> { String }, optional: false, nullable: false
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|