class MX::Banxico::Historico::TipoDeCambio
Clase para recuperar series históricas del tipo de cambio.
La información se obtiene de la página de {www.banxico.org.mx/SieInternet/consultarDirectorioInternetAction.do?accion=consultarSeries Banxico}, haciendo una petición POST que simula una consulta realizada por un usuario desde un navegador web.
Constants
- POST_PATH
Ruta para realizar la petición POST para obtener la información.
- TIPOS_DE_CAMBIO
Tipos de cambio soportados.
- URL
URL
de la página del Banco de México (Banxico).
Attributes
!@attribute [r] errores.
@return [String] la descripción de los errores sucedidos al recuperar el histórico.
Public Class Methods
Inicializador de la instancia.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 62 def initialize @errores = nil end
Public Instance Methods
Recupera todos los históricos de las series de tipo de cambio en {MX::Banxico::Series.tipos_de_cambio}.
@param año_inicio_consulta [Integer] año de inicio de la consulta. @param año_termino_consulta [Integer] año de término de la consulta.
@return [Array<MX::Banxico::TipoDeCambio>] si se recuperó la información, un arreglo con los tipos de cambio de la serie. @return [nil] si hubo un error al recuperar la información.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 104 def completo(año_inicio_consulta = nil, año_termino_consulta = nil) opts = { ids_series: MX::Banxico::Series.identificadores(:tipos_de_cambio) } body_str = hash_a_query_string(body_hash(opts[:ids_series], año_inicio_consulta, año_termino_consulta)) return peticion_post(body_str, opts) end
Recupera el histórico de una serie de tipo de cambio de acuerdo al identificador o nombre de la serie dada.
@param serie [Symbol] el nombre de la serie de la que se desea recuperar el histórico. @param año_inicio_consulta [Integer] año de inicio de la consulta. @param año_termino_consulta [Integer] año de término de la consulta.
@return [Array<MX::Banxico::TipoDeCambio>] si se recuperó la información, un arreglo con los tipos de cambio de la serie. @return [nil] si hubo un error al recuperar la información.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 84 def de_serie(serie, año_inicio_consulta = nil, año_termino_consulta = nil) begin id_serie = MX::Banxico::Series.identificador(:tipos_de_cambio, serie) opts = { id_serie: id_serie, serie: serie } return peticion_post(body_hash(id_serie, año_inicio_consulta, año_termino_consulta), opts) rescue ArgumentError => e registrar_error(e.message) end nil end
Indica si hay algún errror.
@return [Boolean] `true` si hay errores, `false` de lo contrario.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 70 def errores? !@errores.nil? end
Private Instance Methods
Crea el cuerpo para la petición POST para recuperar el histórico de las series.
@param serie [String, Array<String>] el identificador o arreglo de identificadores de la serie o series
de la que se desea recuperar el histórico.
@param año_inicio_consulta [Integer] año de inicio de la consulta. @param año_termino_consulta [Integer] año de término de la consulta.
@return [Hash] con los valores para el cuerpo de la petición POST.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 247 def body_hash(serie, año_inicio_consulta = nil, año_termino_consulta = nil) { # Información recuparada de la petición POST al descargar desde la página web idCuadro: "CF102", sector: "6", version: "2", locale: "es", "formatoSDMX.x" => "41", "formatoSDMX.y" => "8", formatoHorizontal: false, metadatosWeb: true, tipoInformacion: nil, # años de consulta anoInicial: año_inicio_consulta || AÑO_INICIO_CONSULTA, anoFinal: año_termino_consulta || AÑO_FINAL_CONSULTA, # las series a descargar en la consulta series: serie } end
Convierte un `Hash` a una cadena de petición HTTP.
@example Conversión del `Hash`
hsh = { un_param: "foo", otro_param: "bar", param_arreglo: ["a", "b"] } hash_a_query_string(hsh) #=> "un_param=foo&otro_param=bar¶m_arreglo=a¶m_arreglo=b"
@param hsh [Hash] el `Hash` a convertir a cadena.
@return [String] la cadena de petición.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 277 def hash_a_query_string(hsh) pares = [] hsh.each_pair do |k,v| v.is_a?(Array) ? v.each{ |val| pares << par_query_string(k, val) } : pares << par_query_string(k, v) end pares.join("&") end
Encabezado para la petición POST para recuperar el histórico de las series.
@return [Hash] con los valores para el encabezado de la petición POST.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 233 def header_hash { "Content-Type" => "application/x-www-form-urlencoded" } end
Crea un par de llave y valor escapado para URIs.
@param llave [String, Symbol] la llave del par. @param valor [String, Symbol] el valor del par.
@return [String] el par escapado para URI.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 293 def par_query_string(llave, valor) "#{URI.escape llave.to_s}=#{URI.escape valor.to_s}" end
Realiza la petición POST de acuerdo al cuerpo dado.
@param body [Hash, String] el cuerpo de la petición. Usamos una cadena
cuando algún parámetro tiene como valor un arreglo, de lo contrario se usa un `Hash`.
@param opts [Hash] información adicional para procesar la respuesta.
@return [Array<MX::Banxico::TipoDeCambio>] si se recuperó la información, un arreglo con los tipos de cambio de la serie. @return [nil] si hubo un error al recuperar la información.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 123 def peticion_post(body, opts = {}) respuesta = self.class.post(POST_PATH, headers: header_hash, body: body) return procesar_respuesta(respuesta.body, opts) if respuesta.code == 200 registrar_error("código de error #{respuesta.code}.") nil end
Procesa los nodos XML de la respuesta de la petición que contiene la información del tipo de cambio.
@param nodos_obs [Nokogiri::XML::Nodes] nodos de la serie con el valor y fecha del tipo de cambio (bm:Obs). @param nombre_serie [Symbol] el nombre tipo de cambio solicitado. Ver {TIPOS_DE_CAMBIO}.
@return [Array<MX::Banxico::TipoDeCambio>] los valores del tipo de cambio.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 203 def procesar_nodos_obs(nodos_obs, nombre_serie) historico = [] nodos_obs.each do |nodo_obs| begin tdc = MX::Banxico::TipoDeCambio.new(nombre_serie, nodo_obs[:TIME_PERIOD], nodo_obs[:OBS_VALUE]) historico << tdc rescue ArgumentError end end historico end
Procesa la respuesta de la petición, que es un `Hash` generado por {github.com/jnunemaker/httparty HTTParty}.
@param respuesta [String] la respuesta de la petición realizada. @param opts [Hash] información adicional para procesar la respuesta.
@return [Array<MX::Banxico::TipoDeCambio>] si no hubo errores, un arreglo con los tipos de cambio encontrados en la respuesta. @return [nil] si hubo un error al recuperar la información.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 139 def procesar_respuesta(respuesta, opts = {}) xml_doc = Nokogiri::XML(respuesta, nil, 'UTF-8') if xml_doc.root.respond_to?(:xpath) if opts[:id_serie] && opts[:serie] return procesar_serie(xml_doc, opts[:id_serie], opts[:serie]) else return procesar_series(xml_doc, opts[:ids_series]) end else registrar_error("La respuesta de la petición no tiene el formato correcto.") end nil end
Procesa el XML, buscando la serie del identificador dado.
@param xml_doc [Nokogiri::XML::Document] el XML con la respuesta de la petición realizada. @param id_serie [String] el identificador de la serie. @param serie [Symbol] el nombre de la serie.
@return [Array<MX::Banxico::TipoDeCambio>] si no hubo errores, un arreglo con los tipos de cambio encontrados en la respuesta. @return [nil] si hubo un error al recuperar la información.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 163 def procesar_serie(xml_doc, id_serie, serie) historico = procesar_nodos_obs(xml_doc.root.xpath(%Q{bm:DataSet/bm:Series[@IDSERIE="#{id_serie}"]/bm:Obs}), serie) return historico unless historico.empty? registrar_error("No se encontró información de la serie #{serie} dentro de la respuesta de la petición.") nil end
Procesa el XML de las series encontradas.
@param xml_doc [Nokogiri::XML::Document] el XML con la respuesta de la petición realizada.
@return [Array<MX::Banxico::TipoDeCambio>] si no hubo errores, un arreglo con los tipos de cambio encontrados en la respuesta. @return [nil] si hubo un error al recuperar la información.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 178 def procesar_series(xml_doc, ids_series) historico = [] xml_doc.root.xpath("bm:DataSet/bm:Series").each do |serie| if serie["IDSERIE"] && ids_series.include?(serie["IDSERIE"]) begin nombre_serie = MX::Banxico::Series.nombre(serie["IDSERIE"], :tipos_de_cambio) historico += procesar_nodos_obs(serie.xpath("bm:Obs"), nombre_serie) rescue ArgumentError # no se encontró el nombre de la serie rescue Nokogiri::XML::XPath::SyntaxError # no jaló el xpath end end end return historico.sort unless historico.empty? registrar_error("No se encontraron series en la respuesta.") nil end
Registra el mensaje de error en {#errores}.
@param error [String] el error que se agregará a {#errores} @param desc [String] descripción del error.
@return [String] la nueva cadena de error.
# File lib/MX/Banxico/historico/tipo_de_cambio.rb, line 223 def registrar_error(error, desc = nil) err = "Error#{(desc.nil? or desc.empty?) ? "" : " (#{desc})"}: #{error}" @errores = errores? ? "#{@errores} #{err}" : err end