Barcode4J en JRuby y Rails

Agosto 13th, 2010

En el post anterior había explicado el uso de Gbarcode, una librería para generación de códigos de barras con Ruby. El problema es que esta librería no se puede utilizar en Jruby ya que tiene extensiones nativas en C, cosa que Jruby aún no soporta.
Después de investigar alternativas de generación de codigos de barras para java como Zxing y Barbecue. Me quedé con Barcode4j por facilidad de implementación, documentación (la cual es muy completa) y sobre todo estabilidad.
A continuación paso a comentarles como utilizar esta librería en JRuby.

1) Lo primero es descargarse en paquete binario del sitio o bien de este enlace directo.
2) Al descomprimir el Zip, copiamos el contenido del directorio Build al directorio /lib de nuestra instalación de JRuby

3) Ahora vamos al código:


require 'java'

#Importamos algunas librerías que vamos a utilizar
import 'java.awt.image.BufferedImage'
import 'java.io.OutputStream'
import 'java.io.FileOutputStream'

#Importamos las librerías de los códigos de barras (Barcode4j) que necesitamos
import 'org.krysalis.barcode4j.impl.code39.Code39Bean'
import 'org.krysalis.barcode4j.impl.code128.Code128Bean'
import 'org.krysalis.barcode4j.impl.int2of5.Interleaved2Of5Bean'
import 'org.krysalis.barcode4j.impl.codabar.CodabarBean'
import 'org.krysalis.barcode4j.impl.code128.EAN128Bean'
import 'org.krysalis.barcode4j.impl.pdf417.PDF417Bean'
import 'org.krysalis.barcode4j.impl.upcean.EAN13Bean'
import 'org.krysalis.barcode4j.impl.upcean.EAN8Bean'
import 'org.krysalis.barcode4j.impl.upcean.UPCABean'
import 'org.krysalis.barcode4j.impl.datamatrix.DataMatrixBean'
import 'org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider'
import 'org.krysalis.barcode4j.tools.UnitConv'

#Creamos el Bean y establecemos los dpi y wide_factor
bean = Interleaved2Of5Bean.new()
dpi = 150
bean.wide_factor = 3

#Creamos la imagen
ofile = java.io.File.new('/home/laptop/barcodes/barcode.png')
out = FileOutputStream.new(ofile)
canvas = BitmapCanvasProvider.new(out,"image/x-png", dpi, BufferedImage::TYPE_BYTE_BINARY, false, 0)

#Generamos el código de barras
#El segundo parámetro que pasamos es el número del que deseamos generar el codigo de barras
bean.generate_barcode(canvas, '1234567890');
canvas.finish
out.close

Con esto, generamos una imagen con nuestro codigo de barras en /home/laptop/barcodes/barcode.png la cual se puede incluir en cualquier pdf/html/odf, etc.

Espero les sea útil. Cualquier duda, no duden en comentar.

Hay veces que el usuario necesita subir archivos, pero de una manera “masiva”, no guardando de a uno. Un claro ejemplo de esto es GoogleDocs,
que te deja subir varios documentos a la vez, antes de empezar a verlos.
Utilizando un plugin de jquery, en rails esto se hace de una manera muy transparente.
El plugin en cuestión se llama MultiFileUpload, en su página encontraremos una buena documentación de como usarlo correctamente
Lo que nos interesa es como implementarlo en rails y que todos estos archivos que seleccionamos se almacenen en nuestra base de datos.

Para comenzar tenemos que incluir las librerias del plugin en el aplication.html.erb

 <% javascript_include_tag :default, 'multiple-file-upload/jquery.MultiFile.js', 'multiple-file-upload/jquery.MetaData.js' %>

En nuestra vista creamos el formulario, para subir los archivos

<% form_for(:archivo_digital, :html => {:multipart => true },:url => create_archivo_digital_path) do |f| %>
      <ul id="form">
	    <%= file_field_tag :files, :class => 'multi file', :name => 'pdf_files[]'%>
          <li>
            <%= f.submit 'Subir' %>
            <%= f.submit 'Cancelar' %>
          </li>
      </ul>
<% end %>

Expliquemos un poco el código:

En necesario establecer :multipart => true, para que el formulario admita la carga de archivos.
file_field_tag nos crea el tag para poder abrir el cuadro de diálogo de carga de archivos de un navegador:
:class => ‘multi file’, esta clase es la que utiliza MultiFileUpload para hacer la magia de subir varios archivos
:name => ‘pdf_files[]‘ esto es muy necesario, porque el plugin crea un arreglo con todos los archivos, pero para que ruby sepa
que nos referimos a un arreglo tenemos que poner [].
Por último tenemos dos botones, el de Subir, que va a subir todos los archivos de una sola vez y el de Cancelar, que hará lo propio.

En nuestro controller vamos a tener

#Renderiza el formulario para subir los archivos
  def new
    @archivo_digital = ArchivoDigital.new
    respond_to do |format|
      format.html
    end
  end
 
  def create
    respond_to do |format|
      if params[:commit] == "Subir"
        unless params[:pdf_files].blank?
          params[:pdf_files].each do |archivo|
            params[:archivo_digital][:nombre_archivo] = archivo
            params[:archivo_digital][:archivo] = archivo.read
            @archivo_digital = ArchivoDigital.new(params[:archivo_digital])
            if @archivo_digital.save
              flash[:notice] = 'Archivo agregado'
            end
          end
          format.html{redirect_to archivos_digitales_path}
        else
          flash[:error] = 'Debe seleccionar al menos un archivo'
        end
      else
           format.html{redirect_to archivos_digitales_path}
      end
    end
  end

Expliquemos un poco el código:
Sobre el primer método no hay mucho que decir, solo nos renderiza el formulario que creamos en el paso anterior
El método create es el que hace todo, para empezar tenemos una condición donde pregunta si params[:commit] == “Subir”
esto es para que diferencie entre el botón subir y el cancelar. Cuando presionamos un botón, rails inmediatamente manda un parámetro, llamado
commit con el nombre del botón. Con está condición lo que hacemos es darle tareas diferentes a cada botón.
Si no se cumple la condición, es porque se presionó el botón “Cancelar” y nos redirigirá al listado de archivos.
En caso de que la condición se cumpla, tenemos otro condicional: unless params[:pdf_files].blank?, esto es para saber si se seleccionó algun archivo_digital
y caso contrario muestra un flash[:error]. Si se cumple la condición, recorremos el arreglo y vamos guardando en nuestra base de datos el nombre del
archivo y el archivo en sí.

Bueno, esto es una manera sencilla de subir archivos de forma “masiva” con Jquery y Rails, cualquier cosa no duden en preguntar

Uno de los grandes problemas en el desarrollo con Ruby on Rails son los reportes multipágina. Debido a que el HTML (inclusive HTML 5) no soporta multipágina, si utilizamos Jruby tenemos la posibilidad de usar cualquier librería Java en nuestro desarrollo.
Afortunadamente en Java tenemos JasperReports (http://jasperforge.org/), una excelente solución al problema antes mencionado.

Para poder incluir un reporte realizado con JasperReports en nuestra aplicación Jruby necesitamos:

1) Descargar I-Report, la herramienta de administracion de reportes de JasperReports. http://jasperforge.org/projects/ireport y descomprimirlo.

2) Dentro del directorio del i-report, ir a modules/ext/ y copiar todos los archivos .jar (si, todos :D ) al directorio lib de la instalación de JRuby. De esta manera, ya incluimos las librerías necesarias y tenemos preparado nuestro JRuby para utilizar JasperReports.

3) Nos resta crear un reporte para prueba, si nunca hiciste un reporte con i-report: http://jasperforge.org//website/ireportwebsite/IR%20Website/ir_design_a_report.html?header=project&target=ireport

4) Finalmente el código para correr nuestro reporte es el siguiente:

require 'java'
import 'oracle.jdbc.OracleDriver' #Aqui necesitas Utilizar el Driver de la Base de datos que estas usando, en mi caso es oracle
import 'net.sf.jasperreports.engine.JasperCompileManager'
import 'org.apache.commons.dbcp.BasicDataSource'
import'java.util.HashMap'
import'net.sf.jasperreports.engine.JasperFillManager'
import'net.sf.jasperreports.engine.JasperExportManager'                                                                             

#Creo el datasource
basicdatasource = BasicDataSource.new
basicdatasource.driver_class_name = 'oracle.jdbc.OracleDriver'
basicdatasource.username = 'usuario'
basicdatasource.password = 'password'
basicdatasource.url = 'jdbc:oracle:thin:@localhost:1521:XE'
basicdatasource.connection
conexion = basicdatasource.connection

#Compilamos el reporte
jasperReport = JasperCompileManager.compile_report('/url_de_tu_archivo_jrxml/reporte.jrxml')
#Para pasar los parámetros, definimos un objeto HashMap
m = HashMap.new
m.put('parametro_1','valor_parametro_1')
m.put('parametro_2','valor_parametro_2')
m.put('parametro_n','valor_parametro_n')

#Genero el reporte
jasperPrint = JasperFillManager.fill_report(jasperReport, m,conexion)                           

#Exporto el PDF
JasperExportManager.export_report_to_pdf_file(jasperprint, 'path_al_archivo_PDF.pdf')

Si deseamos generar reportes en Rails, podemos por ejemplo ubicar los reportes en el directorio public/reportes y utilizar send_file para enviarlos, por ejemplo:

JasperExportManager.export_report_to_pdf_file(jasperprint, RAILS_ROOT+"/public/reportes/reporte.pdf")
send_file RAILS_ROOT+"/public/reportes/reporte.pdf"

Espero les sea de utilidad, cualquier cosa comenten y trataré de despejar dudas :)

Gbarcode es una librería de generación de códigos de barra para Ruby. Es una extensión de C que envuelve el proyecto  GNU Barcode. Se distribuye en formato GEM

Link: http://gbarcode.rubyforge.org/

Ejemplo de uso:

require 'rubygems'
require 'gbarcode'

# Incluir el módulo

include Gbarcode

# Existen tres pasos para generar un codigo de barras
# 1) preparar el espacio para el string
# 2) codificar el string como un codigo de barras
# 3) imprimir el codigo de barras

# preparar el codigo de barras para el string "TEST1234"

bc = barcode_create("TEST1234")

# codificar el codigo de barras usando code 39,
# desde que code 39 no usa dígito de verificacion (checksum),
# lo podemos pasar en un flag

barcode_encode(bc, BARCODE_NO_CHECKSUM | BARCODE_39)

#imprimir el codigo de barras usando postcript

barcode_print(bc, File.new("testout.ps", "w"), BARCODE_OUT_PS)

# ó

barcode_print(bc, File.new("testout.eps", "w"), BARCODE_OUT_EPS)

Si bien hace bastante tiempo que soy usuario de GNU/Linux, no suelo crear tareas en cron con frecuencia por lo que necesito investigar su poderosa sintáxis cada vez que debo crear trabajos que deben ejecutarse a intervalos regulares.

Hace poco por casualidad me topé con Whenever, una gema de Ruby que nos permite crear tareas en cron de manera muy sencilla. A través de un DSL nos abstrae de la complejidad de la sintáxis de cron. Whenever está muy integrado al framework de desarrollo web Ruby on Rails, aunque puede utilizarse en un programa independiente que genera salidas de tareas para cron y hasta actualiza el archivo crontab.  En este post vamos a ver la manera de crear tareas con Whenever desde el punto de vista de un Administrador de Sistemas.

Read the rest of this entry »

REST con Rails

Diciembre 29th, 2009

El uso de REST con Ruby on Rails es extremadamente relajante, una vez que comienzas a utilizar REST y te acostumbras a trabajar de esa forma, no quieres volver a la forma tradicional. Esta es una guía de conceptos básicos de REST y su aplicación en Rails.

REST son las siglas de Representational State Transfer (Transferencia de Estado Representacional), es una técnica de arquitectura software para sistemas hipermedia distribuidos como la World Wide Web. El término se originó en el año 2000, en una tesis doctoral sobre la web escrita por Roy Fielding, uno de los principales autores de la especificación del protocolo HTTP y ha pasado a ser ampliamente utilizado por la comunidad de desarrollo.

Read the rest of this entry »

Muchas veces necesitamos calcular y mostrar en una forma legible el tiempo transcurrido desde una fecha hasta el día de hoy. Por ejemplo en twitter podemos ver el tiempo transcurrido de un tweet hasta el momento.
twitter_time_ago

En Rails este proceso es muy sencillo utilizando el helper time_ago_in_words(), enviando como parámetro la fecha en la que ocurrió el evento. Es importante que el parámetro que le enviamos sea una fecha, en caso contrario nos dará una excepción de error de tipo de datos.
Por ejemplo si queremos saber cuanto tiempo pasó desde que se creó un ticket en nuestra base de datos, en la vista colocamos :

Esto nos dará un resultado como el ejemplo de la imagen, supongamos que pasaron 7 días:

# => 7 days

Hasta alli todo perfecto, pero que pasa si queremos nuestro resultado en castellano?, tenemos que redefinir en nuestro application_helper el método distance_of_time_in_words, simplemente copiamos y pegamos el siguiente código en nuestro application_helper.rb (o en cualquier helper, si solo lo queremos usar en un lugar específico)

def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
     from_time = from_time.to_time if from_time.respond_to?(:to_time)
     to_time = to_time.to_time if to_time.respond_to?(:to_time)
     distance_in_minutes = (((to_time - from_time).abs)/60).round
     distance_in_seconds = ((to_time - from_time).abs).round

     case distance_in_minutes
       when 0..1
         return (distance_in_minutes == 0) ? 'menos de um minuto' : '1 minuto' unless include_seconds
         case distance_in_seconds
           when 0..4   then 'menos de 5 segundos'
           when 5..9   then 'menos de 10 segundos'
           when 10..19 then 'menos de 20 segundos'
           when 20..59 then 'menos de um minuto'
         else             '1 minuto'
         end

        when 2..44           then "#{distance_in_minutes} minutos"
        when 45..89          then 'aproximadamente 1 hora'
        when 90..1439        then "aproximadamente #{(distance_in_minutes.to_f / 60.0).round} horas"
        when 1440..2879      then '1 dia'
        when 2880..43199     then "#{(distance_in_minutes / 1440).round} dias"
        when 43200..86399    then 'aproximadamente 1 mes'
        when 86400..525959   then "#{(distance_in_minutes / 43200).round} meses"
        when 525960..1051919 then 'aproximadamente 1 año'
     else                      "mas de #{(distance_in_minutes / 525960).round} años"

   end
end

Luego probamos nustra aplicación nuevamente y veremos que el resultado cambio a:

# => 7 dias

Rake doc, salvation

Junio 17th, 2009

A quién no le ha pasado que justo a la hora que necesitamos echar un vistazo a la documentación online de algún framework/lenguaje, nos encontramos con el gran problema que no tenemos conexión? Personalmente estoy tan (mal!) acostumbrado a ver la documentación online que muchas veces me he quedado sin avanzar culpa (mía primero) de la conexión.

Si estamos trabajando con rails, obtener la  documentación de la api del framework es una cosa muy sencilla. En la consola nos situamos sobre el raiz de nuestra aplicación rails y ejecutamos:

carlos@gray-shadow:~/rails_apps/ciclope$ rake rails:freeze:gems

Esta tarea copia todos los gems (inclusive rails) en el directorio /vendor de nuestra aplicación, para que la aplicación en la que estamos ejecute los gems y rails en la versión “freezada”, el siguiente paso:

carlos@gray-shadow:~/rails_apps/ciclope$ rake doc:rails

Aqui Rake nos crea toda la documentación del api del framework tal cual lo tienes online (si! en formato html!). Solo debes ir al directorio doc/api (en el raiz de tu aplicación) y alli abrir con tu browser favorito el archivo “index.html”

Recuerda que tu aplicación ha quedado freezada, por lo que si instalas nuevos gems en el rails de tu sistema, no seran accesibles desde esta aplicación, pero no te asustes :-) para deshacer el freeze solo debes ejecutar:

carlos@gray-shadow:~/rails_apps/ciclope$ rake rails:unfreeze

Y ya tienes el api completo de rails en doc/api. Facil no? Y sobre todo muy útil

Post movido a: http://www.ipcorp.com.ar/cbarbiero?p=11

Uno de los problemas que tenemos cuando usamos aplicaciones web es que al mandar un comando HTTP al servidor a través del navegador, el servidor convierte los datos con los que debemos trabajar en gran cantidad de código HTML. Si necesitamos que nuestro programa pueda trabajar con esos resultados es necesario “desconvertir” el HTML en los tipos de datos que queremos como arrays, strings y otros objetos.

En este tutorial vamos a construir un script en Ruby que nos permita utlizar las sugerencias que nos da el buscador de Google cuando cree que escribimos mal lo que buscamos, el popular “Quizás quiso decir”, gracias a una librería poderosa, rápida y fácil de usar: Hpricot para la tarea de parsear HTML, todo esto utilizando una metodología de desarrollo evolutiva.

Por estos lugares ruby no es aún un lenguaje muy popular, asi que primero les voy a explicar como tener todo lo necesario como para empezar a trabajar.

Estas instrucciones son para Ubuntu Linux pero pueden adaptarse para cualquier otra distribucion, y en MS Windows debería ser aún mas fácil.

Primero vamos a instalar los paquetes de desarrollo y compiladores básicos en Linux, más el interprete de Ruby y sus librerias de desarrollo

sudo aptitude install build-essential ruby ruby1.8-dev irb rdoc

Una vez que terminamos, seguimos con el gestor de paquetes de Ruby: RubyGems

wget http://rubyforge.org/frs/download.php/38646/rubygems-1.2.0.tgz
tar -xvf rubygems-1.2-0.tgz
cd rubygems-1.2-0.tgz
sudo ruby setup.rb

Por ultimo instalamos el parseador de html Hpricot

sudo gem install hpricot

Ahora si, esta todo listo y podemos empezar con el desarrollo, de nuestro simple corrector ortográfico basado en google. Creamos un nuevo archivo ud_quiso_decir.rb en donde vamos a obtener el codigo fuente de un sitio y mostrarlo en pantalla, y a partir de aca vamos a hacer evolucionar el script

#importamos las librerias necesarias
require 'open-uri'
 
#abrimos la pagina deseada y mostramos su contenido por pantalla
puts open('http://www.google.com.ar').read

Guardamos y ejecutamos.

ruby ud_quiso_decir.rb

Si todo salió bien en la pantalla debería aparecer un monton de código html, el siguiente paso es abrir esa url con Hpricot para poder manipular el código fuente.

#importamos las librerias necesarias
require 'open-uri'
require 'rubygems'
require 'hpricot'
 
#definimos en una variable la url
url = 'http://www.google.com.ar'
 
#creamos un objeto hpricot a partir de la url
doc = Hpricot(open(url))
 
#mostramos el contenido limpio de tags html por pantalla
puts doc.to_plain_text

Ahora tenemos que revisar el código que devuelve google cuando tipeamos mal una palabra, para eso en el sitio de google buscamos algo incorrecto como hinteligencia, revisando el código vamos a encontrar que lo que buscamos:

<span style="color: #cc0000">Quizás quiso decir: </span>
<a href="/search?hl=es&amp;sa=X&amp;oi=spell&amp;resnum=0&amp;ct=result&amp;cd=1&amp;q=inteligencia&amp;spell=1">
<strong>
<em>inteligencia</em>
</strong>
</a>

Ahora sigamos mejorando nuestro script:

#importamos las librerias necesarias
require 'open-uri'
require 'rubygems'
require 'hpricot'
 
#tomamos el termino a buscar a traves de la linea de comando
search_word = ARGV[0]
url = "http://www.google.com.ar/search?q=#{search_word}"
 
#creamos un objeto hpricot a partir de la url
doc = Hpricot(open(url))
 
#buscamos dentro de la estructura de arbol
#hasta el lugar que queremos y dado que la
#busqueda en un documento devuelve un array
#solo tomamos el primer elemento
 
suggestion = (doc/"div#res/p/a/b/i").first
 
#por ultimo pasamos la sugerencia a texto plano
# y la mostramos a menos que google no nos haya sugerido nada
 
puts "Quizás quiso decir: " + suggestion.to_plain_text unless suggestion.nil?

Para los fanáticos de realizar todo en una sola línea de código, les mostramos como hacer en dos lí­neas este programa (sin contar los “require”).

suggestion = (Hpricot(open("http://www.google.com.ar/search?q=#{ARGV[0]}"))/"div#res/p/a/b/i").first
puts "Quizás quiso decir: " + suggestion.to_plain_text unless suggestion.nil?

Ahora sólo nos resta probar

alfredo@alfredo-laptop:~/dev/ruby$ ruby ud_quiso_decir.rb ruvy
Quizás quiso decir: ruby
alfredo@alfredo-laptop:~/dev/ruby$ ruby ud_quiso_decir.rb ruby
alfredo@alfredo-laptop:~/dev/ruby$

Esta poderosa librería no sólo permite parsear HTML sino tambien archivos XML y lo que mostramos acá es sólo una pequeña parte de todas sus funcionalidades que vamos a seguir profundizando en futuros posts.

El código fuente del ejemplo puede bajarse desde aquí­