bcn_ni 0.1.7 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d17fe676aa77facf97c9cf4355d7de85a4ff7f3f0f047324b56201992264092
4
- data.tar.gz: 65cb53118d9f3086d96d29c41fd5c5745f1ca789f91b8e04b9da2a6545cf25f7
3
+ metadata.gz: 4f096b5bf6ea7fa64c15436453d3f13259a916b383f305066f50989eaab85dfc
4
+ data.tar.gz: 6466f3159fb88a11248a532a6bb626c24b69c67aa25f0ff9cf644c7796d01116
5
5
  SHA512:
6
- metadata.gz: 7312305624a80c519b8956faad2c1faecaa3cc93f2e59dbc194b6b991c9958deb91f27686df5cbbb07648115066833935e37d7aa164f62e2cdbb08ba8c80974a
7
- data.tar.gz: 99f45ec56e4e64b7382853c8fa0abeff6839f9a65a2bfbb3c626fa262a445f6a795bcf6f00a4424b4b833fc04fcad55f2111e76f662fc94de62c00202e9eba87
6
+ metadata.gz: 9d79136f6bcd9d1838cdea7baea3da138e76ce727bff4afb2bb1290ca5efb0dca0f4b298cc6493de97ac3c1a858b9db5afa951c93b6679b883a3fea485d7040e
7
+ data.tar.gz: 34587ba34e542d02ae192e48b795af3090b229b2d0a47a8e96024d44303d8ffe3cac725aa714e9c18093e500e9033f6d6dd9ba7200631dc9e1492faf2cb41d49
data/README.md CHANGED
@@ -70,7 +70,7 @@ Add this line to your application's Gemfile:
70
70
  gem 'bcn_ni', git: 'https://github.com/mldoscar/bcn_ni', branch: 'master'
71
71
 
72
72
  # From ruby gems
73
- gem 'bcn_ni', '~> 0.1.7'
73
+ gem 'bcn_ni', '~> 0.1.8'
74
74
 
75
75
  # Using gem install
76
76
  gem install bcn_ni
@@ -85,6 +85,7 @@ $ bundle
85
85
  ## Changelog
86
86
 
87
87
  ```
88
+ 2026.05.31 - SOAP request fallback for modern OpenSSL, XML parsing fixes, and test updates
88
89
  2022.04.06 - Rails 6.x 7.x compatibility
89
90
  2021.06.28 - Bugfix: Cambio en el URI para el request de scrapping, el BCN cambió de parámetros y ubicación de URL
90
91
  ```
data/lib/bcn_ni/core.rb CHANGED
@@ -24,4 +24,4 @@ module BcnNi
24
24
  def self.exceptions
25
25
  return @@exceptions
26
26
  end
27
- end
27
+ end
@@ -4,6 +4,7 @@ require 'net/https'
4
4
  require 'nokogiri'
5
5
  require 'open-uri'
6
6
  require 'json'
7
+ require 'open3'
7
8
  require 'active_support/core_ext/hash'
8
9
  begin
9
10
  require 'active_support/time'
@@ -93,7 +94,7 @@ module BcnNi
93
94
 
94
95
  # Generate the full url
95
96
  full_url = request_url + '?' + args.to_param
96
-
97
+
97
98
  # This loop prevents a random EOFError (main cause is not known yet)
98
99
  retries = 0
99
100
  response = nil
@@ -102,10 +103,10 @@ module BcnNi
102
103
  raise StopIteration if retries >= 5
103
104
 
104
105
  begin
105
- response = open(full_url, { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE })
106
+ response = URI.open(full_url, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
106
107
  # Exit loop if response has been assigned
107
108
  break
108
- rescue EOFError => e
109
+ rescue EOFError
109
110
  # Sum retry and sleep the thread for a while
110
111
  retries += 1
111
112
  sleep(2.seconds)
@@ -145,67 +146,90 @@ module BcnNi
145
146
 
146
147
  def soap__exchange_day(year, month, day)
147
148
  # Build body through a XML envelope
148
- body = soap__envelope(soap__letter_exchange_day(year, month, day))
149
- json_response = soap__request(body)
149
+ body = soap__envelope(soap__letter_exchange_day(year, month, day))
150
+ xml_response = soap__request(body)
151
+ doc = Nokogiri::XML(xml_response)
150
152
 
151
- # Get the result value
152
- value_result = json_response['Envelope']['Body']['RecuperaTC_DiaResponse']['RecuperaTC_DiaResult']
153
153
  # Parse the result value and finally return it
154
+ value_result = doc.at_xpath("//*[local-name()='RecuperaTC_DiaResult']")&.text
154
155
  return value_result.to_f
155
156
  end
156
157
 
157
158
  def soap__exchange_month(year, month)
158
159
  # Build body through a XML envelope
159
- body = soap__envelope(soap__letter_exchange_month(year, month))
160
- json_response = soap__request(body)
161
-
162
- # Get the result array
163
- exchange_table = json_response['Envelope']['Body']['RecuperaTC_MesResponse']['RecuperaTC_MesResult']['Detalle_TC']['Tc']
164
-
165
- if exchange_table.present?
166
- # Parse the table to a custom and better JSON
167
- # The format example will be: {date: as Date, value: as Float}
168
- parsed_table = exchange_table.map{ |x| { date: Date.parse(x['Fecha']), value: x['Valor'].to_f } }
169
- # Sort the parsed table and finally return it
170
- return parsed_table.sort_by { |x| x[:date] }
171
- else
172
- return []
160
+ body = soap__envelope(soap__letter_exchange_month(year, month))
161
+ xml_response = soap__request(body)
162
+ doc = Nokogiri::XML(xml_response)
163
+
164
+ # Parse the table to a custom and better JSON
165
+ # The format example will be: {date: as Date, value: as Float}
166
+ exchange_rows = doc.xpath("//*[local-name()='Detalle_TC']/*[local-name()='Tc']")
167
+ parsed_table = exchange_rows.map do |row|
168
+ {
169
+ date: Date.parse(row.at_xpath("*[local-name()='Fecha']")&.text.to_s),
170
+ value: row.at_xpath("*[local-name()='Valor']")&.text.to_f
171
+ }
173
172
  end
173
+
174
+ # Sort the parsed table and finally return it
175
+ return parsed_table.sort_by { |x| x[:date] }
174
176
  end
175
177
 
176
178
  def soap__request(body)
177
- # Parse the URI
179
+ xml_response = begin
180
+ soap__request_with_net_http(body)
181
+ rescue OpenSSL::SSL::SSLError => e
182
+ # BCN SOAP endpoint currently negotiates TLS in a way OpenSSL 3 may reject.
183
+ # Fallback to curl keeps compatibility in modern Ruby runtimes.
184
+ raise unless e.message.to_s.downcase.include?('unsupported protocol')
185
+
186
+ soap__request_with_curl(body)
187
+ end
188
+
189
+ return xml_response
190
+ end
191
+
192
+ def soap__request_with_net_http(body)
178
193
  uri = URI.parse(request_url)
179
- # Create protocol to the URI
180
194
  request_engine = Net::HTTP.new(uri.host, uri.port)
181
195
  request_engine.use_ssl = true
182
196
  request_engine.verify_mode = OpenSSL::SSL::VERIFY_NONE
183
197
  request_engine.open_timeout = 15.seconds
198
+ request_engine.read_timeout = 15.seconds
184
199
 
185
- # Create a new POST request as XML content type
186
200
  req = Net::HTTP::Post.new(uri.path)
187
201
  req['Content-Type'] = 'text/xml'
202
+ req.body = body
188
203
 
189
- # Set the request body as a RAW SOAP XML request
190
- req.body = body
191
- # Process the request
192
204
  res = request_engine.request(req)
193
- # Get the XML response
194
- xml_response = res.body
205
+ return res.body
206
+ end
195
207
 
196
- # Parse to a JSON hash
197
- return Hash.from_xml(xml_response)
208
+ def soap__request_with_curl(body)
209
+ stdout, stderr, status = Open3.capture3(
210
+ 'curl',
211
+ '--silent',
212
+ '--show-error',
213
+ '--insecure',
214
+ '--header', 'Content-Type: text/xml',
215
+ '--data-binary', '@-',
216
+ request_url,
217
+ stdin_data: body
218
+ )
219
+
220
+ raise StandardError, "curl SOAP request failed: #{stderr.strip}" unless status.success?
221
+
222
+ return stdout
198
223
  end
199
224
 
200
225
  def soap__envelope(letter)
201
- envelope = <<-XML
202
- <?xml version="1.0" encoding="utf-8"?>
226
+ envelope = <<~XML
203
227
  <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
204
228
  <soap:Body>
205
229
  #{letter}
206
230
  </soap:Body>
207
231
  </soap:Envelope>
208
- XML
232
+ XML
209
233
  return envelope
210
234
  end
211
235
 
@@ -231,4 +255,4 @@ XML
231
255
  end
232
256
 
233
257
  end
234
- end
258
+ end
@@ -1,3 +1,3 @@
1
1
  module BcnNi
2
- VERSION = '0.1.7'
2
+ VERSION = '0.1.8'
3
3
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bcn_ni
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Rodriguez
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2022-04-07 00:00:00.000000000 Z
10
+ date: 2026-06-01 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -34,44 +33,82 @@ dependencies:
34
33
  name: nokogiri
35
34
  requirement: !ruby/object:Gem::Requirement
36
35
  requirements:
37
- - - "~>"
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '1.14'
39
+ - - "<"
38
40
  - !ruby/object:Gem::Version
39
- version: '1.6'
41
+ version: '2.0'
40
42
  type: :runtime
41
43
  prerelease: false
42
44
  version_requirements: !ruby/object:Gem::Requirement
43
45
  requirements:
44
- - - "~>"
46
+ - - ">="
45
47
  - !ruby/object:Gem::Version
46
- version: '1.6'
48
+ version: '1.14'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '2.0'
47
52
  - !ruby/object:Gem::Dependency
48
53
  name: rake
49
54
  requirement: !ruby/object:Gem::Requirement
50
55
  requirements:
51
- - - "~>"
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '13.0'
59
+ - - "<"
52
60
  - !ruby/object:Gem::Version
53
- version: '12.3'
61
+ version: '14.0'
54
62
  type: :development
55
63
  prerelease: false
56
64
  version_requirements: !ruby/object:Gem::Requirement
57
65
  requirements:
58
- - - "~>"
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '13.0'
69
+ - - "<"
59
70
  - !ruby/object:Gem::Version
60
- version: '12.3'
71
+ version: '14.0'
61
72
  - !ruby/object:Gem::Dependency
62
73
  name: rspec
63
74
  requirement: !ruby/object:Gem::Requirement
64
75
  requirements:
65
- - - "~>"
76
+ - - ">="
66
77
  - !ruby/object:Gem::Version
67
- version: '3.8'
78
+ version: '3.12'
79
+ - - "<"
80
+ - !ruby/object:Gem::Version
81
+ version: '4.0'
68
82
  type: :development
69
83
  prerelease: false
70
84
  version_requirements: !ruby/object:Gem::Requirement
71
85
  requirements:
72
- - - "~>"
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '3.12'
89
+ - - "<"
90
+ - !ruby/object:Gem::Version
91
+ version: '4.0'
92
+ - !ruby/object:Gem::Dependency
93
+ name: byebug
94
+ requirement: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '11.0'
99
+ - - "<"
100
+ - !ruby/object:Gem::Version
101
+ version: '12.0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '11.0'
109
+ - - "<"
73
110
  - !ruby/object:Gem::Version
74
- version: '3.8'
111
+ version: '12.0'
75
112
  description: This gem provides NIO (Córdoba Oro Nicaragüense) against USD (United
76
113
  States Dollar) money exchange rates consuming the official Central Bank of Nicaragüa
77
114
  (BCN) SOAP Service or HTML page
@@ -94,7 +131,6 @@ homepage: https://github.com/mldoscar/bcn_ni
94
131
  licenses:
95
132
  - MIT
96
133
  metadata: {}
97
- post_install_message:
98
134
  rdoc_options: []
99
135
  require_paths:
100
136
  - lib
@@ -109,8 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
145
  - !ruby/object:Gem::Version
110
146
  version: '0'
111
147
  requirements: []
112
- rubygems_version: 3.0.6
113
- signing_key:
148
+ rubygems_version: 3.6.3
114
149
  specification_version: 4
115
150
  summary: This tool pretends to be helpful for developers who can request exchange
116
151
  rates from Nicaragua in a easier way