bcn_ni 0.1.6 → 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: a678080d77772ee8a800974da131c7e329f74162dd0054fa55e3e741fd5688ae
4
- data.tar.gz: 7ebf4ff1bc693aec7c34e4fc10a6b80b69d4b3aea659fa968684ce8af2056759
3
+ metadata.gz: 4f096b5bf6ea7fa64c15436453d3f13259a916b383f305066f50989eaab85dfc
4
+ data.tar.gz: 6466f3159fb88a11248a532a6bb626c24b69c67aa25f0ff9cf644c7796d01116
5
5
  SHA512:
6
- metadata.gz: 4ff4b144e27a5fae7b3c3d99e67b58060c7b6cac5ae052269eea7f1f189da59a55b5f6d5122dca4f89bdd182484791f628f432b2ab334db9072780617e0e5668
7
- data.tar.gz: 6c61cafb9d37780f08cc29e5f97cb9c64cc110236665776a1f249a6401ef8140b1798d9064cf6307d65f96864f2b195e478e23a9e15a118255a9c5fe7d9cda24
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.5'
73
+ gem 'bcn_ni', '~> 0.1.8'
74
74
 
75
75
  # Using gem install
76
76
  gem install bcn_ni
@@ -85,6 +85,8 @@ $ bundle
85
85
  ## Changelog
86
86
 
87
87
  ```
88
+ 2026.05.31 - SOAP request fallback for modern OpenSSL, XML parsing fixes, and test updates
89
+ 2022.04.06 - Rails 6.x 7.x compatibility
88
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
89
91
  ```
90
92
 
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
@@ -3,8 +3,14 @@ require 'net/http'
3
3
  require 'net/https'
4
4
  require 'nokogiri'
5
5
  require 'open-uri'
6
- require 'active_support/core_ext/hash'
7
6
  require 'json'
7
+ require 'open3'
8
+ require 'active_support/core_ext/hash'
9
+ begin
10
+ require 'active_support/time'
11
+ rescue LoadError
12
+ end
13
+
8
14
 
9
15
  module BcnNi
10
16
  class Request
@@ -88,7 +94,7 @@ module BcnNi
88
94
 
89
95
  # Generate the full url
90
96
  full_url = request_url + '?' + args.to_param
91
-
97
+
92
98
  # This loop prevents a random EOFError (main cause is not known yet)
93
99
  retries = 0
94
100
  response = nil
@@ -97,10 +103,10 @@ module BcnNi
97
103
  raise StopIteration if retries >= 5
98
104
 
99
105
  begin
100
- response = open(full_url, { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE })
106
+ response = URI.open(full_url, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
101
107
  # Exit loop if response has been assigned
102
108
  break
103
- rescue EOFError => e
109
+ rescue EOFError
104
110
  # Sum retry and sleep the thread for a while
105
111
  retries += 1
106
112
  sleep(2.seconds)
@@ -140,90 +146,113 @@ module BcnNi
140
146
 
141
147
  def soap__exchange_day(year, month, day)
142
148
  # Build body through a XML envelope
143
- body = soap__envelope(soap__letter_exchange_day(year, month, day))
144
- 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)
145
152
 
146
- # Get the result value
147
- value_result = json_response['Envelope']['Body']['RecuperaTC_DiaResponse']['RecuperaTC_DiaResult']
148
153
  # Parse the result value and finally return it
154
+ value_result = doc.at_xpath("//*[local-name()='RecuperaTC_DiaResult']")&.text
149
155
  return value_result.to_f
150
156
  end
151
157
 
152
158
  def soap__exchange_month(year, month)
153
159
  # Build body through a XML envelope
154
- body = soap__envelope(soap__letter_exchange_month(year, month))
155
- json_response = soap__request(body)
156
-
157
- # Get the result array
158
- exchange_table = json_response['Envelope']['Body']['RecuperaTC_MesResponse']['RecuperaTC_MesResult']['Detalle_TC']['Tc']
159
-
160
- if exchange_table.present?
161
- # Parse the table to a custom and better JSON
162
- # The format example will be: {date: as Date, value: as Float}
163
- parsed_table = exchange_table.map{ |x| { date: Date.parse(x['Fecha']), value: x['Valor'].to_f } }
164
- # Sort the parsed table and finally return it
165
- return parsed_table.sort_by { |x| x[:date] }
166
- else
167
- 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
+ }
168
172
  end
173
+
174
+ # Sort the parsed table and finally return it
175
+ return parsed_table.sort_by { |x| x[:date] }
169
176
  end
170
177
 
171
178
  def soap__request(body)
172
- # 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)
173
193
  uri = URI.parse(request_url)
174
- # Create protocol to the URI
175
194
  request_engine = Net::HTTP.new(uri.host, uri.port)
176
195
  request_engine.use_ssl = true
177
196
  request_engine.verify_mode = OpenSSL::SSL::VERIFY_NONE
178
197
  request_engine.open_timeout = 15.seconds
198
+ request_engine.read_timeout = 15.seconds
179
199
 
180
- # Create a new POST request as XML content type
181
200
  req = Net::HTTP::Post.new(uri.path)
182
201
  req['Content-Type'] = 'text/xml'
202
+ req.body = body
183
203
 
184
- # Set the request body as a RAW SOAP XML request
185
- req.body = body
186
- # Process the request
187
204
  res = request_engine.request(req)
188
- # Get the XML response
189
- xml_response = res.body
205
+ return res.body
206
+ end
190
207
 
191
- # Parse to a JSON hash
192
- 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
193
223
  end
194
224
 
195
225
  def soap__envelope(letter)
196
- envelope = <<EOF
197
- <?xml version="1.0" encoding="utf-8"?>
226
+ envelope = <<~XML
198
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/">
199
228
  <soap:Body>
200
229
  #{letter}
201
230
  </soap:Body>
202
231
  </soap:Envelope>
203
- EOF
232
+ XML
204
233
  return envelope
205
234
  end
206
235
 
207
236
  def soap__letter_exchange_day(year, month, day)
208
- letter = <<EOF
237
+ letter = <<-XML
209
238
  <RecuperaTC_Dia xmlns="http://servicios.bcn.gob.ni/">
210
239
  <Ano>#{year}</Ano>
211
240
  <Mes>#{month}</Mes>
212
241
  <Dia>#{day}</Dia>
213
242
  </RecuperaTC_Dia>
214
- EOF
243
+ XML
215
244
  return letter
216
245
  end
217
246
 
218
247
  def soap__letter_exchange_month(year, month)
219
- letter = <<EOF
248
+ letter = <<-XML
220
249
  <RecuperaTC_Mes xmlns="http://servicios.bcn.gob.ni/">
221
250
  <Ano>#{year}</Ano>
222
251
  <Mes>#{month}</Mes>
223
252
  </RecuperaTC_Mes>
224
- EOF
253
+ XML
225
254
  return letter
226
255
  end
227
256
 
228
257
  end
229
- end
258
+ end
@@ -1,3 +1,3 @@
1
1
  module BcnNi
2
- VERSION = '0.1.6'
2
+ VERSION = '0.1.8'
3
3
  end
metadata CHANGED
@@ -1,71 +1,114 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bcn_ni
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
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: 2021-06-28 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
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
- - - "~>"
16
+ - - ">="
18
17
  - !ruby/object:Gem::Version
19
18
  version: '5.2'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '8.0'
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
23
25
  requirements:
24
- - - "~>"
26
+ - - ">="
25
27
  - !ruby/object:Gem::Version
26
28
  version: '5.2'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '8.0'
27
32
  - !ruby/object:Gem::Dependency
28
33
  name: nokogiri
29
34
  requirement: !ruby/object:Gem::Requirement
30
35
  requirements:
31
- - - "~>"
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '1.14'
39
+ - - "<"
32
40
  - !ruby/object:Gem::Version
33
- version: '1.6'
41
+ version: '2.0'
34
42
  type: :runtime
35
43
  prerelease: false
36
44
  version_requirements: !ruby/object:Gem::Requirement
37
45
  requirements:
38
- - - "~>"
46
+ - - ">="
39
47
  - !ruby/object:Gem::Version
40
- version: '1.6'
48
+ version: '1.14'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '2.0'
41
52
  - !ruby/object:Gem::Dependency
42
53
  name: rake
43
54
  requirement: !ruby/object:Gem::Requirement
44
55
  requirements:
45
- - - "~>"
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '13.0'
59
+ - - "<"
46
60
  - !ruby/object:Gem::Version
47
- version: '12.3'
61
+ version: '14.0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - "~>"
66
+ - - ">="
53
67
  - !ruby/object:Gem::Version
54
- version: '12.3'
68
+ version: '13.0'
69
+ - - "<"
70
+ - !ruby/object:Gem::Version
71
+ version: '14.0'
55
72
  - !ruby/object:Gem::Dependency
56
73
  name: rspec
57
74
  requirement: !ruby/object:Gem::Requirement
58
75
  requirements:
59
- - - "~>"
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '3.12'
79
+ - - "<"
60
80
  - !ruby/object:Gem::Version
61
- version: '3.8'
81
+ version: '4.0'
62
82
  type: :development
63
83
  prerelease: false
64
84
  version_requirements: !ruby/object:Gem::Requirement
65
85
  requirements:
66
- - - "~>"
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
+ - - "<"
67
110
  - !ruby/object:Gem::Version
68
- version: '3.8'
111
+ version: '12.0'
69
112
  description: This gem provides NIO (Córdoba Oro Nicaragüense) against USD (United
70
113
  States Dollar) money exchange rates consuming the official Central Bank of Nicaragüa
71
114
  (BCN) SOAP Service or HTML page
@@ -88,7 +131,6 @@ homepage: https://github.com/mldoscar/bcn_ni
88
131
  licenses:
89
132
  - MIT
90
133
  metadata: {}
91
- post_install_message:
92
134
  rdoc_options: []
93
135
  require_paths:
94
136
  - lib
@@ -103,8 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
145
  - !ruby/object:Gem::Version
104
146
  version: '0'
105
147
  requirements: []
106
- rubygems_version: 3.0.6
107
- signing_key:
148
+ rubygems_version: 3.6.3
108
149
  specification_version: 4
109
150
  summary: This tool pretends to be helpful for developers who can request exchange
110
151
  rates from Nicaragua in a easier way