MX-Banxico 1.0.2

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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +12 -0
  5. data/.yardopts +9 -0
  6. data/CHANGELOG.md +5 -0
  7. data/Gemfile +36 -0
  8. data/Guardfile +26 -0
  9. data/LICENSE.txt +22 -0
  10. data/MX-Banxico.gemspec +29 -0
  11. data/README.md +140 -0
  12. data/REFERENCIAS.md +6 -0
  13. data/Rakefile +26 -0
  14. data/lib/MX/Banxico.rb +12 -0
  15. data/lib/MX/Banxico/historico.rb +4 -0
  16. data/lib/MX/Banxico/historico/tipo_de_cambio.rb +296 -0
  17. data/lib/MX/Banxico/series.rb +346 -0
  18. data/lib/MX/Banxico/tipo_de_cambio.rb +159 -0
  19. data/lib/MX/Banxico/version.rb +14 -0
  20. data/lib/MX/Banxico/web_services.rb +4 -0
  21. data/lib/MX/Banxico/web_services/tipo_de_cambio.rb +83 -0
  22. data/lib/MX/Banxico/web_services/web_service.rb +99 -0
  23. data/spec/MX/Banxico/historico/tipo_de_cambio_spec.rb +525 -0
  24. data/spec/MX/Banxico/series_spec.rb +475 -0
  25. data/spec/MX/Banxico/tipo_de_cambio_spec.rb +688 -0
  26. data/spec/MX/Banxico/web_services/tipo_de_cambio_spec.rb +152 -0
  27. data/spec/MX/Banxico/web_services/web_service_spec.rb +108 -0
  28. data/spec/fixtures/MX/Banxico/historico/respuestas_correctas/tipo_de_cambio.xml +2228 -0
  29. data/spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/mal_formado.xml +1 -0
  30. data/spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/serie_sin_valores.xml +28 -0
  31. data/spec/fixtures/MX/Banxico/historico/respuestas_incorrectas/sin_series.xml +26 -0
  32. data/spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/respuesta_correcta.xml +393 -0
  33. data/spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/serie_sin_valores.xml +28 -0
  34. data/spec/fixtures/MX/Banxico/historico/tipo_de_cambio/dolar_fix/sin_serie.xml +26 -0
  35. data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/reservas_internacionales_banxico.xml +41 -0
  36. data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/tasas_de_interes_banxico.xml +50 -0
  37. data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/tipos_de_cambio_banxico.xml +56 -0
  38. data/spec/fixtures/MX/Banxico/web_services/respuestas_correctas/udis_banxico.xml +41 -0
  39. data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/error_fecha_tipo_de_cambio.xml +41 -0
  40. data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/error_nodo_obs.xml +40 -0
  41. data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/error_valor_tipo_de_cambio.xml +41 -0
  42. data/spec/fixtures/MX/Banxico/web_services/tipo_de_cambio/dolar_fix/respuesta_correcta.xml +41 -0
  43. data/spec/spec_helper.rb +31 -0
  44. metadata +152 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1137c2b18fed5bb10d083f917faaaf2dd3e0f428
4
+ data.tar.gz: ff012be3f2c8a839aea8136170c8f234116671e8
5
+ SHA512:
6
+ metadata.gz: 4c996b8f71622192ae061f31fe6dfceb3a9548f59cad6fbc2eae4721cb84748c015a7e46e36207dbcc686a5df0678ed5e183ffd4e37cee7a50441dfc3a398fdf
7
+ data.tar.gz: 9924eb9b7e1a6afbf3955b75f119e7e974063daa65785ff60cd56048f6f6a02d7992552edf3a3fb606ae87e8e0513c797a97f330c2dc36884deb7f1fa5fe8a2e
@@ -0,0 +1,18 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ *.gem
15
+ .ruby-version
16
+ .ruby-gemset
17
+ mkmf.log
18
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format progress
3
+ --require spec_helper
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+
3
+ before_install:
4
+ - gem install bundler -v '>= 1.12'
5
+
6
+ rvm:
7
+ - ruby-head
8
+
9
+ addons:
10
+ code_climate:
11
+ repo_token:
12
+ secure: "V+kAHFHYVxk3INQ92tjdHWzpkgpec6Hi3cZmI3kfirh12c8BuQsJy187ySjDuzyq6uPF4+WXUBUBoErZBi3SRI0u+qGavpjVEf6onlrykwfBHutYWMjkFybNZ03wKKNK+kSOLWrxOsdrjhFsnZ1SffliaIzxbT+DL2mWpiWkUBQmsBVwjKNpXBP5UowFnbwnaQpAdb7F9diGA83IcBpFueWx+q9ER+ekvNiGs30FmghJVsSveo7VVcWk+Tu8tPsXFwR2b9J3QZ1Ik4alldzVHWNv+O+a75WsJkpXV6eA+CojJ/S8HlhppN3yTUSIxd/fs05QEB+uM+1IsJ2I6IKJ1XsD9KG10kdUCUUL+tr8svfw5pdeqgouEiz4VbrN5wpt869OJznHsZIwQbMmJ3xtEcvD+v1ii260T3wfOFonjCBZOWNvru1xyFwDgoB4UJ2ucbFvKezwtnV5tPcGJqdEVfgM6NopwTKwcs95DRCkRDqB4prH3qGdu0ouu9i+b3c8JnUrny5pr+w/HTizL5lY5uiDIxJdQ5RiAoqMVGIdca4dWkWm+LvUiSCOam2Qf7loGnUcEtk+61BISzYQe7lBqyEMiKrU2b/Lp4mahvI/Q+UpPnsbVfCn5ecMMN4prnmKYVZDdrmgR0t1vEBC4+fy4pJClIOT51gLknYaiwz39dE="
@@ -0,0 +1,9 @@
1
+ --title 'MX-Banxico'
2
+ --output-dir ./doc
3
+ --markup-provider redcarpet
4
+ --markup markdown
5
+ --protected --private
6
+ --readme README.md
7
+ lib/**/*.rb - LICENSE.txt REFERENCIAS.md CHANGELOG.md
8
+
9
+
@@ -0,0 +1,5 @@
1
+ # Changelog / Bitácora de cambios
2
+
3
+ * **Versión 0.0.1.pre**
4
+ * Primera implementación de web service para obtención del tipo de cambio.
5
+ * Es posible recuperar seriee históricas, haciendo una petición POST al mismo lugar donde lo hace la página web de consultas históricas de BANXICO.
data/Gemfile ADDED
@@ -0,0 +1,36 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development, :ci_filter do
6
+ gem 'guard'
7
+ gem 'guard-bundler', require: false
8
+ gem 'guard-rspec', require: false
9
+ gem 'pry'
10
+ gem 'pry-remote'
11
+ gem 'pry-byebug', platform: [:mri_20, :mri_21, :mri_22]
12
+ gem 'pry-nav', platform: [:mri_19, :jruby]
13
+ gem 'terminal-notifier'
14
+ gem 'terminal-notifier-guard'
15
+ end
16
+
17
+ group :development, :test do
18
+ gem 'bundler'
19
+ gem 'rake'
20
+ gem 'rspec'
21
+ end
22
+
23
+ group :test do
24
+ gem 'codeclimate-test-reporter'
25
+ gem 'simplecov', require: false
26
+ gem 'coveralls', require: false
27
+ gem 'rspec-collection_matchers'
28
+ gem 'shoulda-matchers', require: false
29
+ gem 'webmock', require: false
30
+ end
31
+
32
+ group :doc do
33
+ gem 'yard'
34
+ gem 'redcarpet'
35
+ gem 'github-markup'
36
+ end
@@ -0,0 +1,26 @@
1
+ guard :rspec, cmd: "bundle exec rspec", cmd_additional_args: '-f progress', failed_mode: :focus do
2
+ require "guard/rspec/dsl"
3
+ dsl = Guard::RSpec::Dsl.new(self)
4
+
5
+ # RSpec files
6
+ rspec = dsl.rspec
7
+ watch(rspec.spec_helper) { rspec.spec_dir }
8
+ watch(rspec.spec_support) { rspec.spec_dir }
9
+ watch(rspec.spec_files)
10
+
11
+ # Ruby files
12
+ ruby = dsl.ruby
13
+ dsl.watch_spec_files_for(ruby.lib_files)
14
+ end
15
+
16
+ guard :bundler do
17
+ require 'guard/bundler'
18
+ require 'guard/bundler/verify'
19
+ helper = Guard::Bundler::Verify.new
20
+
21
+ files = ['Gemfile']
22
+ files += Dir['*.gemspec'] if files.any? { |f| helper.uses_gemspec?(f) }
23
+
24
+ # Assume files are symlinked from somewhere
25
+ files.each { |file| watch(helper.real_path(file)) }
26
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 Pablo Ruiz
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'MX/Banxico/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "MX-Banxico"
7
+ spec.version = MX::Banxico::VERSION
8
+ spec.platform = Gem::Platform::RUBY
9
+ spec.authors = ["Pablo Ruiz"]
10
+ spec.email = ["pjruiz@maquech.com.mx"]
11
+ spec.summary = %q{Banco de México web services utilities / Utilerías para usar los servicios web del Banco de México (Banxico)}
12
+ spec.description = %q{Banco de México web services utilities / Utilerías para usar los servicios web del Banco de México (Banxico)}
13
+ spec.homepage = "https://github.com/Maquech/MX-Banxico"
14
+ spec.license = "MIT"
15
+
16
+ spec.required_ruby_version = '>= 2.0'
17
+
18
+ spec.add_dependency 'nokogiri', '~> 1.6'
19
+ spec.add_dependency 'httparty', '~> 0.13'
20
+ spec.add_dependency 'savon', '~> 2.11'
21
+
22
+ spec.files = `git ls-files`.split("\n")
23
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.post_install_message = "¡Viva México!"
28
+
29
+ end
@@ -0,0 +1,140 @@
1
+ # MX::Banxico
2
+
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/MX-Banxico.png)](https://badge.fury.io/rb/MX-Banxico) [![Build Status](https://travis-ci.org/Maquech/MX-Banxico.svg?branch=master)](https://travis-ci.org/Maquech/MX-Banxico) [![Code Climate](https://codeclimate.com/github/Maquech/MX-Banxico/badges/gpa.svg)](https://codeclimate.com/github/Maquech/MX-Banxico) [![Test Coverage](https://codeclimate.com/github/Maquech/MX-Banxico/badges/coverage.svg)](https://codeclimate.com/github/Maquech/MX-Banxico/coverage)
5
+
6
+
7
+
8
+ ## Why and what for / Por qué y para qué
9
+
10
+ This gem was conceived as an aid in the automation of information extraction from the web site and web services provided by
11
+ the [Bank of Mexico](http://www.banxico.org.mx).
12
+
13
+
14
+ This project is not endorsed in any way by the Mexican government. It's an effort to contribute to the preservation of mental
15
+ health of the developers who have to deal with this things :)
16
+
17
+
18
+ ---
19
+
20
+ Esta gema se concibió como una ayuda para la automatización de extracción de información de la página y servicios web que provee
21
+ el [Banco de México](http://www.banxico.org.mx).
22
+
23
+
24
+ Este proyecto no está patrocinado de ninguna forma por el gobierno mexicano. Es un esfuerzo para contribuir a la sanidad mental de los programadores que tenemos que lidiar con estas cosas :)
25
+
26
+
27
+ ## Installation / Instalación
28
+
29
+ Add this line to your application's Gemfile:
30
+
31
+ ```ruby
32
+ gem 'mx-banxico'
33
+ ```
34
+
35
+ And then execute:
36
+
37
+ $ bundle
38
+
39
+ Or install it yourself as:
40
+
41
+ $ gem install mx-banxico
42
+
43
+ ---
44
+
45
+ Agrega esta línea al archivo Gemfile de tu aplicación:
46
+
47
+ ```ruby
48
+ gem 'mx-banxico'
49
+ ```
50
+
51
+ Luego ejecuta:
52
+
53
+ $ bundle
54
+
55
+ O instálalo tu mismo usando:
56
+
57
+ $ gem install mx-banxico
58
+
59
+
60
+ ## Dependencies / Dependencias
61
+
62
+ The only dependencies are:
63
+
64
+ * [Nokogiri](http://http://www.nokogiri.org/) for XML processing.
65
+ * [Savon](http://savonrb.com) for web services exploitation.
66
+ * [HTTParty](https://github.com/jnunemaker/httparty/tree/master/lib/httparty) for making a request to the Bank of Mexico's web site and download information.
67
+
68
+ ---
69
+
70
+ Las únicas dependencias son:
71
+
72
+ * [Nokogiri](http://http://www.nokogiri.org/) que es una gema (y una joya) para procesar XML.
73
+ * [Savon](http://savonrb.com) para explotar los servicios web.
74
+ * [HTTParty](https://github.com/jnunemaker/httparty/tree/master/lib/httparty) para hacer una petición al sitio web y descargar
75
+ información de ahí.
76
+
77
+
78
+
79
+ ## Usage / Uso
80
+
81
+ El Banco de México (también conocido como Banxico) maneja información de UDIS (Unidades de inversión), tipo de cambio, tasas de interés y reservas internacionales en uno de sus [servicios web] (http://www.banxico.org.mx/DgieWSWeb/DgieWS?WSDL). También, en su sitio web, tienen una [herramienta](http://www.banxico.org.mx/SieInternet/consultarDirectorioInternetAction.do?accion=consultarCuadro&idCuadro=CF102&sector=6&locale=es) para consultar la información histórica de diversos indicadores (o series como ellos les llaman).
82
+
83
+ Ahora, la biblioteca (sí: _library -> biblioteca_, _bookstore -> librería_) está dividida en tres partes, cada una separada por un espacio de nombres (_namespace_) para poder distinguir los elementos con los que se está trabajando: {MX::Banxico}, {MX::Banxico::Historico} y {MX::Banxico::WebServices}.
84
+
85
+ #### Ejemplos:
86
+
87
+ * Para trabajar con el tipo de cambio histórico, se utiliza una instancia de {MX::Banxico::Historico::TipoDeCambio}.
88
+ * Si deseas obtener el tipo de cambio al día de hoy, usa una instancia de {MX::Banxico::WebServices::TipoDeCambio}.
89
+
90
+
91
+ En la clase {MX::Banxico::Series} encontrarás métodos para listar las series con las que trabaja la biblioteca. Básicamente es un contenedor de la información de las series (o indicadores) que tiene Banxico. La información ahí contenida se extrajo principalmente del servicio web, aunque la herramienta de consulta web del Banco también la maneja de la misma forma (se agradece consistencia).
92
+
93
+ Tanto los servicios web como la página, devuelven XML. Para facilitar las cosas, todos los métodos de clases o instancias en {MX::Banxico::Historico::TipoDeCambio} o {MX::Banxico::WebServices::TipoDeCambio} devuelven arreglos de objetos (u objetos) del tipo {MX::Banxico::TipoDeCambio}. **¿Ves el patrón?** La idea es que si trabajarás con UDIS, uses {MX::Banxico::Historico::UDIS}, {MX::Banxico::WebServices::UDIS} y {MX::Banxico::UDIS}.
94
+
95
+ Por el momento, sólo están las clases para trabajar con el tipo de cambio :'( pero siempre puedes contribuir a esta biblioteca y hacer a más gente feliz :)
96
+
97
+
98
+ ## Docs
99
+
100
+ Check the [online documentation](http://http://www.rubydoc.info/gems/MX-Banxico/1.0) or generate it using YARD with:
101
+
102
+ $ bundle exec yard server --port 8828 --reload
103
+
104
+ Also, check the [references](REFERENCIAS.md).
105
+
106
+ ---
107
+
108
+ Consulta la [documentación en línea](http://http://www.rubydoc.info/gems/MX-Banxico/1.0) o genera la documentación con YARD:
109
+
110
+ $ bundle exec yard server --port 8828 --reload
111
+
112
+ También revisa las [referencias](REFERENCIAS.md).
113
+
114
+
115
+ ## Contributing / Contribuir
116
+
117
+ 1. Fork it ( https://github.com/Maquech/MX-Banxico/fork )
118
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
119
+ 3. Create your specs (100% coverage please!) and add code or make changes (TDD, right?)
120
+ 4. Commit your changes (`git commit -am 'Add some feature'`)
121
+ 5. Push to the branch (`git push origin my-new-feature`)
122
+ 6. Create a new Pull Request
123
+
124
+ You can also submit technical observations on the algorithms here implemented alongside with references to official documentation that supports it.
125
+
126
+ ---
127
+
128
+ Puedes contribuir mandándonos tus observaciones sobre la implementación de los algoritmos aquí implementados o referencias a documentos oficiales que las respalde.
129
+
130
+ Ahora, diviérte con esta traducción (si sabes el término correcto en español, háznoslo saber por favor):
131
+
132
+ 1. Crea tu copia del repositorio ( https://github.com/Maquech/MX-Banxico/fork )
133
+ 2. Crea tu rama con la funcionalidad propuesta (`git checkout -b mi-nueva-funcionalidad-shubiduby`)
134
+ 3. Crea tus pruebas (specs que tengan una covertura del 100% porfa) y realiza cambios o agrega código (estás haciendo TDD, ¿cierto?)
135
+ 4. Compromete tus cambios (`git commit -am 'Nueva funcionalidad shubiduby'`)
136
+ 5. Empuja la rama a tu repositorio (`git push origin mi-nueva-funcionalidad-shubiduby`)
137
+ 6. Crea una nueva petición de jalada|tirada|extracción|acarreo
138
+
139
+
140
+
@@ -0,0 +1,6 @@
1
+ ## Referencias oficiales
2
+
3
+ ### Oficiales
4
+
5
+ * [Banco de México, Estadísticas](http://www.banxico.org.mx/estadisticas/index.html)
6
+ * [Banco de México, web services](http://www.banxico.org.mx/DgieWSWeb/DgieWS?WSDL)
@@ -0,0 +1,26 @@
1
+ begin
2
+ require "MX/Banxico/version"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+ require 'yard'
6
+ YARD::Rake::YardocTask.new
7
+
8
+ RSpec::Core::RakeTask.new(:spec, :tag) do |t, task_args|
9
+ t.rspec_opts = ["--tag #{task_args[:tag]}", "--format", "--color"]
10
+ end
11
+
12
+ task default: :spec
13
+ task test: :spec
14
+
15
+
16
+ task :build do
17
+ system "gem build MX-Banxico.gemspec"
18
+ end
19
+
20
+ task :release => :build do
21
+ system "gem push mx-banxico-#{MX::Banxico::VERSION}"
22
+ end
23
+
24
+ rescue LoadError
25
+ end
26
+
@@ -0,0 +1,12 @@
1
+ require 'httparty'
2
+ require 'savon'
3
+ require 'nokogiri'
4
+
5
+ require "MX/Banxico/version"
6
+ require "MX/Banxico/historico"
7
+ require "MX/Banxico/web_services"
8
+ require "MX/Banxico/series"
9
+ require "MX/Banxico/tipo_de_cambio"
10
+ require "MX/Banxico/historico/tipo_de_cambio"
11
+ require "MX/Banxico/web_services/web_service"
12
+ require "MX/Banxico/web_services/tipo_de_cambio"
@@ -0,0 +1,4 @@
1
+ # Módulo para recuperar series históricas.
2
+ #
3
+ module MX::Banxico::Historico
4
+ end
@@ -0,0 +1,296 @@
1
+ # Clase para recuperar series históricas del tipo de cambio.
2
+ #
3
+ # La información se obtiene de la página de
4
+ # {http://www.banxico.org.mx/SieInternet/consultarDirectorioInternetAction.do?accion=consultarSeries Banxico},
5
+ # haciendo una petición POST que simula una consulta
6
+ # realizada por un usuario desde un navegador web.
7
+ #
8
+ class MX::Banxico::Historico::TipoDeCambio
9
+ include HTTParty
10
+
11
+
12
+ # URL de la página del Banco de México (Banxico).
13
+ #
14
+ URL = "www.banxico.org.mx"
15
+
16
+
17
+ # Ruta para realizar la petición POST para obtener la información.
18
+ #
19
+ POST_PATH = "/SieInternet/consultarDirectorioInternetAction.do?accion=consultarSeries"
20
+
21
+
22
+ # Año inicial de la consulta (por omisión).
23
+ #
24
+ AÑO_INICIO_CONSULTA = 2015
25
+
26
+
27
+ # Año final de la consulta (por omisión).
28
+ #
29
+ AÑO_FINAL_CONSULTA = 2015
30
+
31
+
32
+ # Tipos de cambio soportados.
33
+ #
34
+ TIPOS_DE_CAMBIO = MX::Banxico::Series.tipos_de_cambio.keys.dup.freeze
35
+
36
+
37
+ # !@method base_uri
38
+ # URI base para la clase que incluye a {https://github.com/jnunemaker/httparty HTTParty}.
39
+ #
40
+ base_uri URL
41
+
42
+
43
+ # !@method open_timeout
44
+ # tiempo de espera para abrir la conexión para clase que incluye a {https://github.com/jnunemaker/httparty HTTParty}.
45
+ #
46
+ open_timeout 10
47
+
48
+
49
+ # !@method format
50
+ # formato esperado de la respuesta {https://github.com/jnunemaker/httparty HTTParty}.
51
+ #
52
+ format :xml
53
+
54
+
55
+ # !@attribute [r] errores.
56
+ # @return [String] la descripción de los errores sucedidos al recuperar el histórico.
57
+ attr_reader :errores
58
+
59
+
60
+ # Inicializador de la instancia.
61
+ #
62
+ def initialize
63
+ @errores = nil
64
+ end
65
+
66
+ # Indica si hay algún errror.
67
+ #
68
+ # @return [Boolean] `true` si hay errores, `false` de lo contrario.
69
+ #
70
+ def errores?
71
+ !@errores.nil?
72
+ end
73
+
74
+
75
+ # Recupera el histórico de una serie de tipo de cambio de acuerdo al identificador o nombre de la serie dada.
76
+ #
77
+ # @param serie [Symbol] el nombre de la serie de la que se desea recuperar el histórico.
78
+ # @param año_inicio_consulta [Integer] año de inicio de la consulta.
79
+ # @param año_termino_consulta [Integer] año de término de la consulta.
80
+ #
81
+ # @return [Array<MX::Banxico::TipoDeCambio>] si se recuperó la información, un arreglo con los tipos de cambio de la serie.
82
+ # @return [nil] si hubo un error al recuperar la información.
83
+ #
84
+ def de_serie(serie, año_inicio_consulta = nil, año_termino_consulta = nil)
85
+ begin
86
+ id_serie = MX::Banxico::Series.identificador(:tipos_de_cambio, serie)
87
+ opts = { id_serie: id_serie, serie: serie }
88
+ return peticion_post(body_hash(id_serie, año_inicio_consulta, año_termino_consulta), opts)
89
+ rescue ArgumentError => e
90
+ registrar_error(e.message)
91
+ end
92
+ nil
93
+ end
94
+
95
+
96
+ # Recupera todos los históricos de las series de tipo de cambio en {MX::Banxico::Series.tipos_de_cambio}.
97
+ #
98
+ # @param año_inicio_consulta [Integer] año de inicio de la consulta.
99
+ # @param año_termino_consulta [Integer] año de término de la consulta.
100
+ #
101
+ # @return [Array<MX::Banxico::TipoDeCambio>] si se recuperó la información, un arreglo con los tipos de cambio de la serie.
102
+ # @return [nil] si hubo un error al recuperar la información.
103
+ #
104
+ def completo(año_inicio_consulta = nil, año_termino_consulta = nil)
105
+ opts = { ids_series: MX::Banxico::Series.identificadores(:tipos_de_cambio) }
106
+ body_str = hash_a_query_string(body_hash(opts[:ids_series], año_inicio_consulta, año_termino_consulta))
107
+ return peticion_post(body_str, opts)
108
+ end
109
+
110
+
111
+
112
+ private
113
+
114
+ # Realiza la petición POST de acuerdo al cuerpo dado.
115
+ #
116
+ # @param body [Hash, String] el cuerpo de la petición. Usamos una cadena
117
+ # cuando algún parámetro tiene como valor un arreglo, de lo contrario se usa un `Hash`.
118
+ # @param opts [Hash] información adicional para procesar la respuesta.
119
+ #
120
+ # @return [Array<MX::Banxico::TipoDeCambio>] si se recuperó la información, un arreglo con los tipos de cambio de la serie.
121
+ # @return [nil] si hubo un error al recuperar la información.
122
+ #
123
+ def peticion_post(body, opts = {})
124
+ respuesta = self.class.post(POST_PATH, headers: header_hash, body: body)
125
+ return procesar_respuesta(respuesta.body, opts) if respuesta.code == 200
126
+ registrar_error("código de error #{respuesta.code}.")
127
+ nil
128
+ end
129
+
130
+
131
+ # Procesa la respuesta de la petición, que es un `Hash` generado por {https://github.com/jnunemaker/httparty HTTParty}.
132
+ #
133
+ # @param respuesta [String] la respuesta de la petición realizada.
134
+ # @param opts [Hash] información adicional para procesar la respuesta.
135
+ #
136
+ # @return [Array<MX::Banxico::TipoDeCambio>] si no hubo errores, un arreglo con los tipos de cambio encontrados en la respuesta.
137
+ # @return [nil] si hubo un error al recuperar la información.
138
+ #
139
+ def procesar_respuesta(respuesta, opts = {})
140
+ xml_doc = Nokogiri::XML(respuesta, nil, 'UTF-8')
141
+ if xml_doc.root.respond_to?(:xpath)
142
+ if opts[:id_serie] && opts[:serie]
143
+ return procesar_serie(xml_doc, opts[:id_serie], opts[:serie])
144
+ else
145
+ return procesar_series(xml_doc, opts[:ids_series])
146
+ end
147
+ else
148
+ registrar_error("La respuesta de la petición no tiene el formato correcto.")
149
+ end
150
+ nil
151
+ end
152
+
153
+
154
+ # Procesa el XML, buscando la serie del identificador dado.
155
+ #
156
+ # @param xml_doc [Nokogiri::XML::Document] el XML con la respuesta de la petición realizada.
157
+ # @param id_serie [String] el identificador de la serie.
158
+ # @param serie [Symbol] el nombre de la serie.
159
+ #
160
+ # @return [Array<MX::Banxico::TipoDeCambio>] si no hubo errores, un arreglo con los tipos de cambio encontrados en la respuesta.
161
+ # @return [nil] si hubo un error al recuperar la información.
162
+ #
163
+ def procesar_serie(xml_doc, id_serie, serie)
164
+ historico = procesar_nodos_obs(xml_doc.root.xpath(%Q{bm:DataSet/bm:Series[@IDSERIE="#{id_serie}"]/bm:Obs}), serie)
165
+ return historico unless historico.empty?
166
+ registrar_error("No se encontró información de la serie #{serie} dentro de la respuesta de la petición.")
167
+ nil
168
+ end
169
+
170
+
171
+ # Procesa el XML de las series encontradas.
172
+ #
173
+ # @param xml_doc [Nokogiri::XML::Document] el XML con la respuesta de la petición realizada.
174
+ #
175
+ # @return [Array<MX::Banxico::TipoDeCambio>] si no hubo errores, un arreglo con los tipos de cambio encontrados en la respuesta.
176
+ # @return [nil] si hubo un error al recuperar la información.
177
+ #
178
+ def procesar_series(xml_doc, ids_series)
179
+ historico = []
180
+ xml_doc.root.xpath("bm:DataSet/bm:Series").each do |serie|
181
+ if serie["IDSERIE"] && ids_series.include?(serie["IDSERIE"])
182
+ begin
183
+ nombre_serie = MX::Banxico::Series.nombre(serie["IDSERIE"], :tipos_de_cambio)
184
+ historico += procesar_nodos_obs(serie.xpath("bm:Obs"), nombre_serie)
185
+ rescue ArgumentError # no se encontró el nombre de la serie
186
+ rescue Nokogiri::XML::XPath::SyntaxError # no jaló el xpath
187
+ end
188
+ end
189
+ end
190
+ return historico.sort unless historico.empty?
191
+ registrar_error("No se encontraron series en la respuesta.")
192
+ nil
193
+ end
194
+
195
+
196
+ # Procesa los nodos XML de la respuesta de la petición que contiene la información del tipo de cambio.
197
+ #
198
+ # @param nodos_obs [Nokogiri::XML::Nodes] nodos de la serie con el valor y fecha del tipo de cambio (bm:Obs).
199
+ # @param nombre_serie [Symbol] el nombre tipo de cambio solicitado. Ver {TIPOS_DE_CAMBIO}.
200
+ #
201
+ # @return [Array<MX::Banxico::TipoDeCambio>] los valores del tipo de cambio.
202
+ #
203
+ def procesar_nodos_obs(nodos_obs, nombre_serie)
204
+ historico = []
205
+ nodos_obs.each do |nodo_obs|
206
+ begin
207
+ tdc = MX::Banxico::TipoDeCambio.new(nombre_serie, nodo_obs[:TIME_PERIOD], nodo_obs[:OBS_VALUE])
208
+ historico << tdc
209
+ rescue ArgumentError
210
+ end
211
+ end
212
+ historico
213
+ end
214
+
215
+
216
+ # Registra el mensaje de error en {#errores}.
217
+ #
218
+ # @param error [String] el error que se agregará a {#errores}
219
+ # @param desc [String] descripción del error.
220
+ #
221
+ # @return [String] la nueva cadena de error.
222
+ #
223
+ def registrar_error(error, desc = nil)
224
+ err = "Error#{(desc.nil? or desc.empty?) ? "" : " (#{desc})"}: #{error}"
225
+ @errores = errores? ? "#{@errores} #{err}" : err
226
+ end
227
+
228
+
229
+ # Encabezado para la petición POST para recuperar el histórico de las series.
230
+ #
231
+ # @return [Hash] con los valores para el encabezado de la petición POST.
232
+ #
233
+ def header_hash
234
+ { "Content-Type" => "application/x-www-form-urlencoded" }
235
+ end
236
+
237
+
238
+ # Crea el cuerpo para la petición POST para recuperar el histórico de las series.
239
+ #
240
+ # @param serie [String, Array<String>] el identificador o arreglo de identificadores de la serie o series
241
+ # de la que se desea recuperar el histórico.
242
+ # @param año_inicio_consulta [Integer] año de inicio de la consulta.
243
+ # @param año_termino_consulta [Integer] año de término de la consulta.
244
+ #
245
+ # @return [Hash] con los valores para el cuerpo de la petición POST.
246
+ #
247
+ def body_hash(serie, año_inicio_consulta = nil, año_termino_consulta = nil)
248
+ { # Información recuparada de la petición POST al descargar desde la página web
249
+ idCuadro: "CF102",
250
+ sector: "6",
251
+ version: "2",
252
+ locale: "es",
253
+ "formatoSDMX.x" => "41",
254
+ "formatoSDMX.y" => "8",
255
+ formatoHorizontal: false,
256
+ metadatosWeb: true,
257
+ tipoInformacion: nil,
258
+ # años de consulta
259
+ anoInicial: año_inicio_consulta || AÑO_INICIO_CONSULTA,
260
+ anoFinal: año_termino_consulta || AÑO_FINAL_CONSULTA,
261
+ # las series a descargar en la consulta
262
+ series: serie
263
+ }
264
+ end
265
+
266
+
267
+ # Convierte un `Hash` a una cadena de petición HTTP.
268
+ #
269
+ # @example Conversión del `Hash`
270
+ # hsh = { un_param: "foo", otro_param: "bar", param_arreglo: ["a", "b"] }
271
+ # hash_a_query_string(hsh) #=> "un_param=foo&otro_param=bar&param_arreglo=a&param_arreglo=b"
272
+ #
273
+ #
274
+ # @param hsh [Hash] el `Hash` a convertir a cadena.
275
+ #
276
+ # @return [String] la cadena de petición.
277
+ def hash_a_query_string(hsh)
278
+ pares = []
279
+ hsh.each_pair do |k,v|
280
+ v.is_a?(Array) ? v.each{ |val| pares << par_query_string(k, val) } : pares << par_query_string(k, v)
281
+ end
282
+ pares.join("&")
283
+ end
284
+
285
+
286
+ # Crea un par de llave y valor escapado para URIs.
287
+ #
288
+ # @param llave [String, Symbol] la llave del par.
289
+ # @param valor [String, Symbol] el valor del par.
290
+ #
291
+ # @return [String] el par escapado para URI.
292
+ #
293
+ def par_query_string(llave, valor)
294
+ "#{URI.escape llave.to_s}=#{URI.escape valor.to_s}"
295
+ end
296
+ end