Dagi3d v4

Plugin para generar captchas

Hace unos meses implementé un sistema para generar captchas para el formulario de comentarios del blog y así evitar el spam que me estaba llegando. El “problema” de la solución a la que llegué era que no hacía ningún uso de las facilidades que ofrece Rails para crear plugins, por lo que la reutilización de todas las librerías se hacía un tanto ortopédica ya que obligaba a estar repitiendo código por todos lados. Por eso y para seguir trasteando con ruby, convertí todo el sistema en un plugin para RoR.

Para instalarlo basta con ejecutar el siguiente comando en nuestra aplicación Rails:
ruby script/plugin install http://svn.dagi3d.net/rails/rcaptcha/tags/rcaptcha-0.1.2

A continuación hay que llamar al método de clase ‘acts_as_captchable’ dentro de nuestro controlador. También se le pueden pasar parámetros para modificar la apariencia del captcha(son todos opcionales):

app/controllers/foo_controller.rb:

class FooController < ApplicationController

  acts_as_captchable :length => 5,  #número de caracteres del captcha
    :width => 300,  #ancho de la imagen generada
    :height => 30,  #altura de la imagen generada
    :step => 10, #ancho de las celdas de la rejilla de la imagen
    :font_color => 'black',  #color del texto. también admite valores hexadecimales
    :font_size => 25 #tamaño de la fuente

  def index
  end

  def validate_form
    render_text(valid_captcha_value?(params[:captcha_value]))
  end
end

Con el plugin también se crea automágicamente el helper ‘image_captcha_tag’ para pintar la imagen con el captcha. Hay que indicarle en el primer parámetro el nombre del controlador que se encargará de generar el captcha(al que hemos marcado como ‘captchable’). Opcionalmente se le puede pasar los atributos que queramos para el tag ‘img’ que se renderizará en la vista:

app/views/foo/index.rhtml:
<html>
  <body>
    <%= form_tag(:action => "validate_form") %>
      <%= image_captcha_tag("foo", :class => "captcha") %>
      <%= text_field_tag(:captcha_value) %>
      <%= submit_tag('enviar') %>
    </form>
  </body>
</html>

Finalmente, para comprobar si el valor enviado en el formulario coincide con el generado por el captcha, basta con llamar al método ‘valid_captcha_value?’ pasándole como parámetro el valor introducido en el textfield, tal como se indica en la clase FooController.
El resultado final con los valores por defecto sería algo así:

Mostrar el tamaño de un fichero de una manera más legible

Estaba haciendo una aplicación en rails donde necesitaba mostrar el tamaño del fichero que el usuario podía descargar. Ruby cuenta con el método File.size pero devuelve el tamaño en bytes y claro, que un archivo pese 3670016 bytes por ejemplo, no es que sea muy esclarecedor, así que añadí una función a la clase File que muestra el tamaño en la unidad más grande posible:

file_util.rb:

class File

  @@units = ['bytes', 'kb', 'mb', 'gb', 'tb']

  def File.readable_size(file_name)

    size = File.size(file_name).to_f

    pos = 0
    while size / 1024 >= 1
      size = size / 1024
      pos += 1
    end

    size = format("%.1f", size)

    return size.to_s + " " + @@units[pos] 
  end
end

Ejemplo de uso:
require 'file_util'

file_name = "foo" 
size = (1.5 * 1024 * 1024).to_i # 1.5 mb

#creamos un fichero de prueba con el tamaño indicado
File.open(file_name, "w") do 
  |file|
  size.times do
    file << 'x'
  end
end

puts File.size(file_name) # 1572864
puts File.readable_size(file_name) # 1.5 mb

Una de videos

Stop Motion Ilustration

Impresionante trabajo de animación 2d usando la artesana técnica del stop motion.

Vía Motion Graphics Canarias

Documental “Google, tras la pantalla”

Interesante documental sobre Google: qué hacen, quiénes trabajan ahí, cómo lo hacen y cuales son sus planes de futuro. Tampoco falta el toque conspiranoico.

Vía Alt1040

Plugin para aplicaciones multilenguaje en Rails

En breve me pondré con el desarrollo de un site que necesitará estar disponible en varios idiomas, así que como me apetecía investigar el tema del desarrollo de plugins en RoR, decidí hacerme uno que me solucionase la papeleta siendo totalmente consciente de estar reinventando la rueda, ya que ya existen soluciones más que probadas como Globalize o Gettext, pero el caso era cacharrear, y la verdad es que he aprendido unas cuantas cosillas sobre la programación dinámica en Ruby, así que creo que a veces vale la pena repetir cosas, al menos cuando se está aprendiendo.

De momento ya trabaja con textos estáticos(en formato yaml) y con los modelos, aunque esta parte es algo rudimentaria. He subido el código a un repositorio de subversion y para instalarlo en la aplicación basta con teclear
script/plugin install http://svn.dagi3d.net/rails/wahrig/tags/wahrig-0.1.0/

Para que el plugin funcione con un modelo, tan sólo hay que llamar al método ‘acts_as_translatable’ junto con los nombres de los campos que queremos que sean ‘traducibles’ mientras que cada uno de estos campos deberá tener su correspondiente texto traducido para las ‘locales’ que queramos tener. Y para cambiar de locale, hay que llamar a ResourceBundle.set_locale():

app/models/foo.rb

class Foo < ActiveRecord::Base

  acts_as_translatable :bar

end

test/fixtures/foos.yml

foo1:
  id: 1
  bar: ejemplo
  bar_en_US: example
  bar_de_DE: Beispiel

vendor/plugins/wahrig/test/wahrig_test.rb

require File.dirname(__FILE__) + '/../../../../test/test_helper'

class WahrigTest < Test::Unit::TestCase

  fixtures :foos

  def test_model
    foo = Foo.find(1)

    assert_equal foo.bar, 'ejemplo'

    ResourceBundle.set_locale('en_US')
    assert_equal @foo.bar, 'example'

    ResourceBundle.set_locale('de_DE')
    assert_equal @foo.bar, 'Beispiel'

  end
end

Para utilizarlo en el controlador para usar textos estáticos basta con llamar al método ‘act_as_translator’, y luego llamar a ‘load_bundle’ en el método que queramos dentro del controlador, indicando el nombre del fichero yaml, la variable a la que queremos asignar el contenido y la locale que queremos utilizar:

app/controllers/foo_controller.rb

class FooController < ApplicationController

  acts_as_translator

  def index
    load_bundle("test", :foo, 'es_ES')
  end

end

config/test.es_ES.yml

foo: foo - español
bar: bar - español

config/test.en_US.yml

foo: foo - english
bar: bar - english

Esto lo que haría sería cargar el fichero RAILS_ROOT/config/test.es_ES.yml y asignarle el contenido a la variable @foo, pudiendo acceder desde la vista a todos los campos definidos en el fichero:

app/views/foo/index.rhtml

<%= @foo['foo'] %>
<%= @foo['bar'] %>

Eudora será de código abierto

Llevo usando Eudora como cliente de correo para Windows desde hace bastantes años y me he llevado una grata sorpresa al entrar en la página de Qualcom para descargarlo de nuevo tras la reinstalación de Windows (creo que es de los pocos programas por los que he pagado aparte de Silo) y ver la noticia de que a lo largo del año que viene liberarán el código de Eudora, aunque todavía habrá que ver bajo qué licencia lo hacen.

La verdad es que creo que es lo mejor que podían hacer, ya que daba la sensación de que siempre iban un paso atrás respecto a otras programas, y espero que así puedan hacerle un lavado de cara y que salgan nuevos plugins (y si ya sacan una versión para Linux sería la repera).