pcp-server-ruby-sdk 1.4.0 → 1.5.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.
@@ -1,5 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'openssl'
6
+ require 'socket'
7
+
3
8
  require_relative '../lib/PCP-server-Ruby-SDK.rb'
4
9
  require_relative 'commerce_case_api_example'
5
10
 
@@ -71,6 +76,66 @@ def demonstrate_http_client_customization(api_key, api_secret)
71
76
  puts "\n=== HTTP Client Customization Examples Complete ==="
72
77
  end
73
78
 
79
+ CRL_CACHE = {}
80
+
81
+ def fetch_crls_for_host(uri)
82
+ cached = CRL_CACHE[uri.host]
83
+ return cached if cached
84
+
85
+ crls = []
86
+ tcp = nil
87
+ ssl_socket = nil
88
+ begin
89
+ port = uri.port || uri.default_port || (uri.scheme == 'https' ? 443 : 80)
90
+ tcp = TCPSocket.new(uri.host, port)
91
+ ssl_ctx = OpenSSL::SSL::SSLContext.new
92
+ ssl_ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_NONE)
93
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp, ssl_ctx)
94
+ ssl_socket.hostname = uri.host if ssl_socket.respond_to?(:hostname=)
95
+ ssl_socket.connect
96
+
97
+ certificates = [ssl_socket.peer_cert]
98
+ if ssl_socket.respond_to?(:peer_cert_chain) && ssl_socket.peer_cert_chain
99
+ certificates.concat(ssl_socket.peer_cert_chain)
100
+ end
101
+
102
+ crl_urls = certificates.compact.flat_map { |cert|
103
+ cert.extensions.select { |ext| ext.oid == 'crlDistributionPoints' }
104
+ .flat_map { |ext| ext.value.scan(/URI:(\S+)/).flatten }
105
+ }.uniq
106
+
107
+ crl_urls.each do |crl_url|
108
+ begin
109
+ parsed = URI(crl_url)
110
+ next unless parsed.is_a?(URI::HTTP)
111
+ response = Net::HTTP.get_response(parsed)
112
+ if response.is_a?(Net::HTTPSuccess)
113
+ crls << OpenSSL::X509::CRL.new(response.body)
114
+ else
115
+ $stderr.puts "[example] CRL fetch failed for #{crl_url} (status #{response.code})"
116
+ end
117
+ rescue StandardError => fetch_error
118
+ $stderr.puts "[example] CRL fetch error for #{crl_url}: #{fetch_error.class}: #{fetch_error.message}"
119
+ end
120
+ end
121
+ rescue StandardError => handshake_error
122
+ $stderr.puts "[example] Failed to inspect certificates for #{uri.host}: #{handshake_error.class}: #{handshake_error.message}"
123
+ ensure
124
+ begin
125
+ ssl_socket&.sysclose
126
+ rescue StandardError
127
+ # ignore
128
+ end
129
+ begin
130
+ tcp&.close
131
+ rescue StandardError
132
+ # ignore
133
+ end
134
+ end
135
+
136
+ CRL_CACHE[uri.host] = crls
137
+ end
138
+
74
139
  def run
75
140
  api_key = ENV['API_KEY']
76
141
  api_secret = ENV['API_SECRET']
@@ -88,6 +153,25 @@ def run
88
153
  api_secret,
89
154
  'https://api.preprod.commerce.payone.com'
90
155
  )
156
+ communicator_configuration.http_client = proc do |uri|
157
+ http = Net::HTTP.new(uri.host, uri.port || uri.default_port)
158
+ http.use_ssl = uri.scheme == 'https'
159
+
160
+ store = OpenSSL::X509::Store.new
161
+ store.set_default_paths
162
+
163
+ crls = fetch_crls_for_host(uri)
164
+ if crls && !crls.empty?
165
+ crls.each { |crl| store.add_crl(crl) }
166
+ store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK
167
+ else
168
+ $stderr.puts "[example] No CRLs available for #{uri.host}; proceeding without CRL check"
169
+ end
170
+
171
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
172
+ http.cert_store = store
173
+ http
174
+ end
91
175
 
92
176
  commerce_case_api_client_example = CommerceCaseApiExample.new(communicator_configuration)
93
177
 
@@ -7,10 +7,13 @@ module PCPServerSDK
7
7
  class CompletePaymentMethodSpecificInput
8
8
  attr_accessor :payment_product3391_specific_input
9
9
 
10
+ attr_accessor :payment_product840_specific_input
11
+
10
12
  # Attribute mapping from ruby-style variable name to JSON key.
11
13
  def self.attribute_map
12
14
  {
13
- :'payment_product3391_specific_input' => :'paymentProduct3391SpecificInput'
15
+ :'payment_product3391_specific_input' => :'paymentProduct3391SpecificInput',
16
+ :'payment_product840_specific_input' => :'paymentProduct840SpecificInput'
14
17
  }
15
18
  end
16
19
 
@@ -22,7 +25,8 @@ module PCPServerSDK
22
25
  # Attribute type mapping.
23
26
  def self.openapi_types
24
27
  {
25
- :'payment_product3391_specific_input' => :'PaymentProduct3391SpecificInput'
28
+ :'payment_product3391_specific_input' => :'PaymentProduct3391SpecificInput',
29
+ :'payment_product840_specific_input' => :'CompletePaymentProduct840SpecificInput'
26
30
  }
27
31
  end
28
32
 
@@ -50,6 +54,10 @@ module PCPServerSDK
50
54
  if attributes.key?(:'payment_product3391_specific_input')
51
55
  self.payment_product3391_specific_input = attributes[:'payment_product3391_specific_input']
52
56
  end
57
+
58
+ if attributes.key?(:'payment_product840_specific_input')
59
+ self.payment_product840_specific_input = attributes[:'payment_product840_specific_input']
60
+ end
53
61
  end
54
62
 
55
63
  # Checks equality by comparing each attribute.
@@ -57,7 +65,8 @@ module PCPServerSDK
57
65
  def ==(o)
58
66
  return true if self.equal?(o)
59
67
  self.class == o.class &&
60
- payment_product3391_specific_input == o.payment_product3391_specific_input
68
+ payment_product3391_specific_input == o.payment_product3391_specific_input &&
69
+ payment_product840_specific_input == o.payment_product840_specific_input
61
70
  end
62
71
 
63
72
  # @see the `==` method
@@ -69,7 +78,7 @@ module PCPServerSDK
69
78
  # Calculates hash code according to all attributes.
70
79
  # @return [Integer] Hash code
71
80
  def hash
72
- [payment_product3391_specific_input].hash
81
+ [payment_product3391_specific_input, payment_product840_specific_input].hash
73
82
  end
74
83
 
75
84
  # Builds the object from hash
@@ -0,0 +1,232 @@
1
+
2
+ require 'date'
3
+ require 'time'
4
+
5
+ # Object containing the specific input details for PayPal payments completed by the merchant.
6
+ module PCPServerSDK
7
+ module Models
8
+ class CompletePaymentProduct840SpecificInput
9
+ # Indicates whether the PayPal JavaScript SDK flow is used.
10
+ attr_accessor :java_script_sdk_flow
11
+
12
+ # Confirmation of the order status in case of PayPal SDK integration.
13
+ attr_accessor :action
14
+
15
+ class EnumAttributeValidator
16
+ attr_reader :datatype
17
+ attr_reader :allowable_values
18
+
19
+ def initialize(datatype, allowable_values)
20
+ @allowable_values = allowable_values.map do |value|
21
+ case datatype.to_s
22
+ when /Integer/i
23
+ value.to_i
24
+ when /Float/i
25
+ value.to_f
26
+ else
27
+ value
28
+ end
29
+ end
30
+ end
31
+
32
+ def valid?(value)
33
+ !value || allowable_values.include?(value)
34
+ end
35
+ end
36
+
37
+ # Attribute mapping from ruby-style variable name to JSON key.
38
+ def self.attribute_map
39
+ {
40
+ :'java_script_sdk_flow' => :'javaScriptSdkFlow',
41
+ :'action' => :'action'
42
+ }
43
+ end
44
+
45
+ # Returns all the JSON keys this model knows about
46
+ def self.acceptable_attributes
47
+ attribute_map.values
48
+ end
49
+
50
+ # Attribute type mapping.
51
+ def self.openapi_types
52
+ {
53
+ :'java_script_sdk_flow' => :'Boolean',
54
+ :'action' => :'String'
55
+ }
56
+ end
57
+
58
+ # List of attributes with nullable: true
59
+ def self.openapi_nullable
60
+ Set.new([
61
+ ])
62
+ end
63
+
64
+ # Initializes the object
65
+ # @param [Hash] attributes Model attributes in the form of hash
66
+ def initialize(attributes = {})
67
+ if (!attributes.is_a?(Hash))
68
+ fail ArgumentError, "The input argument (attributes) must be a hash in `CompletePaymentProduct840SpecificInput` initialize method"
69
+ end
70
+
71
+ # check to see if the attribute exists and convert string to symbol for hash key
72
+ attributes = attributes.each_with_object({}) { |(k, v), h|
73
+ if (!self.class.attribute_map.key?(k.to_sym))
74
+ fail ArgumentError, "`#{k}` is not a valid attribute in `CompletePaymentProduct840SpecificInput`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect
75
+ end
76
+ h[k.to_sym] = v
77
+ }
78
+
79
+ if attributes.key?(:'java_script_sdk_flow')
80
+ self.java_script_sdk_flow = attributes[:'java_script_sdk_flow']
81
+ end
82
+
83
+ if attributes.key?(:'action')
84
+ self.action = attributes[:'action']
85
+ end
86
+ end
87
+
88
+ # Checks equality by comparing each attribute.
89
+ # @param [Object] Object to be compared
90
+ def ==(o)
91
+ return true if self.equal?(o)
92
+ self.class == o.class &&
93
+ java_script_sdk_flow == o.java_script_sdk_flow &&
94
+ action == o.action
95
+ end
96
+
97
+ # @see the `==` method
98
+ # @param [Object] Object to be compared
99
+ def eql?(o)
100
+ self == o
101
+ end
102
+
103
+ # Calculates hash code according to all attributes.
104
+ # @return [Integer] Hash code
105
+ def hash
106
+ [java_script_sdk_flow, action].hash
107
+ end
108
+
109
+ # Builds the object from hash
110
+ # @param [Hash] attributes Model attributes in the form of hash
111
+ # @return [Object] Returns the model itself
112
+ def self.build_from_hash(attributes)
113
+ return nil unless attributes.is_a?(Hash)
114
+ attributes = attributes.transform_keys(&:to_sym)
115
+ transformed_hash = {}
116
+ openapi_types.each_pair do |key, type|
117
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
118
+ transformed_hash["#{key}"] = nil
119
+ elsif type =~ /\AArray<(.*)>/i
120
+ # check to ensure the input is an array given that the attribute
121
+ # is documented as an array but the input is not
122
+ if attributes[attribute_map[key]].is_a?(Array)
123
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
124
+ end
125
+ elsif !attributes[attribute_map[key]].nil?
126
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
127
+ end
128
+ end
129
+ new(transformed_hash)
130
+ end
131
+
132
+ # Deserializes the data based on type
133
+ # @param string type Data type
134
+ # @param string value Value to be deserialized
135
+ # @return [Object] Deserialized data
136
+ def self._deserialize(type, value)
137
+ case type.to_sym
138
+ when :Time
139
+ Time.parse(value)
140
+ when :Date
141
+ Date.parse(value)
142
+ when :String
143
+ value.to_s
144
+ when :Integer
145
+ value.to_i
146
+ when :Float
147
+ value.to_f
148
+ when :Boolean
149
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
150
+ true
151
+ else
152
+ false
153
+ end
154
+ when :Object
155
+ # generic object (usually a Hash), return directly
156
+ value
157
+ when /\AArray<(?<inner_type>.+)>\z/
158
+ inner_type = Regexp.last_match[:inner_type]
159
+ value.map { |v| _deserialize(inner_type, v) }
160
+ when /\AHash<(?<k_type>.+?), (?<v_type>.+)>\z/
161
+ k_type = Regexp.last_match[:k_type]
162
+ v_type = Regexp.last_match[:v_type]
163
+ {}.tap do |hash|
164
+ value.each do |k, v|
165
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
166
+ end
167
+ end
168
+ else # model
169
+ # models (e.g. Pet) or oneOf
170
+ klass = PCPServerSDK::Models.const_get(type)
171
+ klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value)
172
+ end
173
+ end
174
+
175
+ # Returns the string representation of the object
176
+ # @return [String] String presentation of the object
177
+ def to_s
178
+ to_hash.to_s
179
+ end
180
+
181
+ # to_body is an alias to to_hash (backward compatibility)
182
+ # @return [Hash] Returns the object in the form of hash
183
+ def to_body
184
+ to_hash
185
+ end
186
+
187
+ # Returns the object in the form of hash
188
+ # @return [Hash] Returns the object in the form of hash
189
+ def to_hash
190
+ hash = {}
191
+ self.class.attribute_map.each_pair do |attr, param|
192
+ value = self.send(attr)
193
+ if value.nil?
194
+ is_nullable = self.class.openapi_nullable.include?(attr)
195
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
196
+ end
197
+
198
+ hash[param] = _to_hash(value)
199
+ end
200
+ hash
201
+ end
202
+
203
+ # Outputs non-array value in the form of hash
204
+ # For object, use to_hash. Otherwise, just return the value
205
+ # @param [Object] value Any valid value
206
+ # @return [Hash] Returns the value in the form of hash
207
+ def _to_hash(value)
208
+ if value.is_a?(Array)
209
+ value.compact.map { |v| _to_hash(v) }
210
+ elsif value.is_a?(Hash)
211
+ {}.tap do |hash|
212
+ value.each { |k, v| hash[k] = _to_hash(v) }
213
+ end
214
+ elsif value.respond_to? :to_hash
215
+ value.to_hash
216
+ else
217
+ value
218
+ end
219
+ end
220
+
221
+ # Custom attribute writer method checking allowed values (enum).
222
+ # @param [Object] action Object to be assigned
223
+ def action=(action)
224
+ validator = EnumAttributeValidator.new('String', ['CONFIRM_ORDER_STATUS'])
225
+ unless validator.valid?(action)
226
+ fail ArgumentError, "invalid value for \"action\", must be one of #{validator.allowable_values}."
227
+ end
228
+ @action = action
229
+ end
230
+ end
231
+ end
232
+ end
@@ -7,6 +7,8 @@ module PCPServerSDK
7
7
  class CompletePaymentRequest
8
8
  attr_accessor :financing_payment_method_specific_input
9
9
 
10
+ attr_accessor :redirect_payment_method_specific_input
11
+
10
12
  attr_accessor :order
11
13
 
12
14
  attr_accessor :device
@@ -15,6 +17,7 @@ module PCPServerSDK
15
17
  def self.attribute_map
16
18
  {
17
19
  :'financing_payment_method_specific_input' => :'financingPaymentMethodSpecificInput',
20
+ :'redirect_payment_method_specific_input' => :'redirectPaymentMethodSpecificInput',
18
21
  :'order' => :'order',
19
22
  :'device' => :'device'
20
23
  }
@@ -29,6 +32,7 @@ module PCPServerSDK
29
32
  def self.openapi_types
30
33
  {
31
34
  :'financing_payment_method_specific_input' => :'CompleteFinancingPaymentMethodSpecificInput',
35
+ :'redirect_payment_method_specific_input' => :'CompleteRedirectPaymentMethodSpecificInput',
32
36
  :'order' => :'Order',
33
37
  :'device' => :'CustomerDevice'
34
38
  }
@@ -59,6 +63,10 @@ module PCPServerSDK
59
63
  self.financing_payment_method_specific_input = attributes[:'financing_payment_method_specific_input']
60
64
  end
61
65
 
66
+ if attributes.key?(:'redirect_payment_method_specific_input')
67
+ self.redirect_payment_method_specific_input = attributes[:'redirect_payment_method_specific_input']
68
+ end
69
+
62
70
  if attributes.key?(:'order')
63
71
  self.order = attributes[:'order']
64
72
  end
@@ -74,6 +82,7 @@ module PCPServerSDK
74
82
  return true if self.equal?(o)
75
83
  self.class == o.class &&
76
84
  financing_payment_method_specific_input == o.financing_payment_method_specific_input &&
85
+ redirect_payment_method_specific_input == o.redirect_payment_method_specific_input &&
77
86
  order == o.order &&
78
87
  device == o.device
79
88
  end
@@ -87,7 +96,7 @@ module PCPServerSDK
87
96
  # Calculates hash code according to all attributes.
88
97
  # @return [Integer] Hash code
89
98
  def hash
90
- [financing_payment_method_specific_input, order, device].hash
99
+ [financing_payment_method_specific_input, redirect_payment_method_specific_input, order, device].hash
91
100
  end
92
101
 
93
102
  # Builds the object from hash
@@ -0,0 +1,198 @@
1
+
2
+ require 'date'
3
+ require 'time'
4
+
5
+ # Object containing the redirect payment product details for completion calls.
6
+ module PCPServerSDK
7
+ module Models
8
+ class CompleteRedirectPaymentMethodSpecificInput
9
+ attr_accessor :payment_product_id
10
+
11
+ attr_accessor :payment_product840_specific_input
12
+
13
+ # Attribute mapping from ruby-style variable name to JSON key.
14
+ def self.attribute_map
15
+ {
16
+ :'payment_product_id' => :'paymentProductId',
17
+ :'payment_product840_specific_input' => :'paymentProduct840SpecificInput'
18
+ }
19
+ end
20
+
21
+ # Returns all the JSON keys this model knows about
22
+ def self.acceptable_attributes
23
+ attribute_map.values
24
+ end
25
+
26
+ # Attribute type mapping.
27
+ def self.openapi_types
28
+ {
29
+ :'payment_product_id' => :'Integer',
30
+ :'payment_product840_specific_input' => :'CompletePaymentProduct840SpecificInput'
31
+ }
32
+ end
33
+
34
+ # List of attributes with nullable: true
35
+ def self.openapi_nullable
36
+ Set.new([
37
+ ])
38
+ end
39
+
40
+ # Initializes the object
41
+ # @param [Hash] attributes Model attributes in the form of hash
42
+ def initialize(attributes = {})
43
+ if (!attributes.is_a?(Hash))
44
+ fail ArgumentError, "The input argument (attributes) must be a hash in `CompleteRedirectPaymentMethodSpecificInput` initialize method"
45
+ end
46
+
47
+ # check to see if the attribute exists and convert string to symbol for hash key
48
+ attributes = attributes.each_with_object({}) { |(k, v), h|
49
+ if (!self.class.attribute_map.key?(k.to_sym))
50
+ fail ArgumentError, "`#{k}` is not a valid attribute in `CompleteRedirectPaymentMethodSpecificInput`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect
51
+ end
52
+ h[k.to_sym] = v
53
+ }
54
+
55
+ if attributes.key?(:'payment_product_id')
56
+ self.payment_product_id = attributes[:'payment_product_id']
57
+ end
58
+
59
+ if attributes.key?(:'payment_product840_specific_input')
60
+ self.payment_product840_specific_input = attributes[:'payment_product840_specific_input']
61
+ end
62
+ end
63
+
64
+ # Checks equality by comparing each attribute.
65
+ # @param [Object] Object to be compared
66
+ def ==(o)
67
+ return true if self.equal?(o)
68
+ self.class == o.class &&
69
+ payment_product_id == o.payment_product_id &&
70
+ payment_product840_specific_input == o.payment_product840_specific_input
71
+ end
72
+
73
+ # @see the `==` method
74
+ # @param [Object] Object to be compared
75
+ def eql?(o)
76
+ self == o
77
+ end
78
+
79
+ # Calculates hash code according to all attributes.
80
+ # @return [Integer] Hash code
81
+ def hash
82
+ [payment_product_id, payment_product840_specific_input].hash
83
+ end
84
+
85
+ # Builds the object from hash
86
+ # @param [Hash] attributes Model attributes in the form of hash
87
+ # @return [Object] Returns the model itself
88
+ def self.build_from_hash(attributes)
89
+ return nil unless attributes.is_a?(Hash)
90
+ attributes = attributes.transform_keys(&:to_sym)
91
+ transformed_hash = {}
92
+ openapi_types.each_pair do |key, type|
93
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
94
+ transformed_hash["#{key}"] = nil
95
+ elsif type =~ /\AArray<(.*)>/i
96
+ # check to ensure the input is an array given that the attribute
97
+ # is documented as an array but the input is not
98
+ if attributes[attribute_map[key]].is_a?(Array)
99
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
100
+ end
101
+ elsif !attributes[attribute_map[key]].nil?
102
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
103
+ end
104
+ end
105
+ new(transformed_hash)
106
+ end
107
+
108
+ # Deserializes the data based on type
109
+ # @param string type Data type
110
+ # @param string value Value to be deserialized
111
+ # @return [Object] Deserialized data
112
+ def self._deserialize(type, value)
113
+ case type.to_sym
114
+ when :Time
115
+ Time.parse(value)
116
+ when :Date
117
+ Date.parse(value)
118
+ when :String
119
+ value.to_s
120
+ when :Integer
121
+ value.to_i
122
+ when :Float
123
+ value.to_f
124
+ when :Boolean
125
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
126
+ true
127
+ else
128
+ false
129
+ end
130
+ when :Object
131
+ # generic object (usually a Hash), return directly
132
+ value
133
+ when /\AArray<(?<inner_type>.+)>\z/
134
+ inner_type = Regexp.last_match[:inner_type]
135
+ value.map { |v| _deserialize(inner_type, v) }
136
+ when /\AHash<(?<k_type>.+?), (?<v_type>.+)>\z/
137
+ k_type = Regexp.last_match[:k_type]
138
+ v_type = Regexp.last_match[:v_type]
139
+ {}.tap do |hash|
140
+ value.each do |k, v|
141
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
142
+ end
143
+ end
144
+ else # model
145
+ # models (e.g. Pet) or oneOf
146
+ klass = PCPServerSDK::Models.const_get(type)
147
+ klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value)
148
+ end
149
+ end
150
+
151
+ # Returns the string representation of the object
152
+ # @return [String] String presentation of the object
153
+ def to_s
154
+ to_hash.to_s
155
+ end
156
+
157
+ # to_body is an alias to to_hash (backward compatibility)
158
+ # @return [Hash] Returns the object in the form of hash
159
+ def to_body
160
+ to_hash
161
+ end
162
+
163
+ # Returns the object in the form of hash
164
+ # @return [Hash] Returns the object in the form of hash
165
+ def to_hash
166
+ hash = {}
167
+ self.class.attribute_map.each_pair do |attr, param|
168
+ value = self.send(attr)
169
+ if value.nil?
170
+ is_nullable = self.class.openapi_nullable.include?(attr)
171
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
172
+ end
173
+
174
+ hash[param] = _to_hash(value)
175
+ end
176
+ hash
177
+ end
178
+
179
+ # Outputs non-array value in the form of hash
180
+ # For object, use to_hash. Otherwise, just return the value
181
+ # @param [Object] value Any valid value
182
+ # @return [Hash] Returns the value in the form of hash
183
+ def _to_hash(value)
184
+ if value.is_a?(Array)
185
+ value.compact.map { |v| _to_hash(v) }
186
+ elsif value.is_a?(Hash)
187
+ {}.tap do |hash|
188
+ value.each { |k, v| hash[k] = _to_hash(v) }
189
+ end
190
+ elsif value.respond_to? :to_hash
191
+ value.to_hash
192
+ else
193
+ value
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end