Terminé mi carrera…o mi caminata

Saturday, 10 May , 2008

La semana pasada aprobé la última materia de la carrera Analista en Informática Aplicada, después de muuuucho tiempo al fin me recibí, todavía recuerdo cuando recién comenzaba a estudiar, tenía muchas energías y ganas de aprender más y más acerca de todo lo que tenga que ver con computadoras y debo reconocer que aprendí varias cosas en esa casa estudios pero también tengo que decir que las cosas que considero más importantes las aprendí afuera. En mi caso particular hace bastante tiempo que me vengo dedicando al desarrollo de software más que nada al desarrollo web, he trabajado en varios lugares/empresas y también hice algunos proyectos personales que publiqué con licencia GPL. En la facultad tuve materias como: Fundamentos de Programación, Programación I, Programación II, Ingeniería de Software, Bases de datos y Optativa y Proyecto final, los lenguajes que conocí en esas materias fueron: Pascal, Delphi, Java, C++ y Visual Basic, sin embargo los lenguajes en con los cuales yo he venido trabajando son: PHP, Perl, Ruby y algo de Shell Scripting… es cierto que en este último tiempo en mi trabajo me están obligando a usar java (uno de los motivos que hace que este lugar se torne bastante aburrido para mí). Debo decir que la mayoría de estas materias (de programación) estaban centradas en enseñar la sintaxis del lenguaje que se daba o en cuales botones había que hacer “click” para compilar con netbeans o como generar un reporte con el asistente de Visual Basic xx, otro detalle importante eran los exámenes, a excepción de proyecto final todos los exámenes se hacían en papel y para aprobar bastaba con que el programa “funcione” sin importar la forma de resolverlo.
Acá les dejo el último exámen que rendí, el de Optativa y proyecto final:
Este es el enunciado:
Examen proyectofina 1/2
Exámen proyecto fina 2/2

El título dice “Recuperatorio 2do parcial” se ve que fué reutilizado :), bueno acá les dejo mi solución:

class Plancuenta  :Plc_id

  def self.calcular_nro_siguiente cuenta
    Plancuenta.find(:all).select{|p| p.Plc_IdPadre == cuenta}.
      sort{|x,y| x.Plc_NroAux  y.Plc_NroAux}.last.Plc_NroAux + 1
  end

  def self.agrega_plan plc_idpadre, plc_desc
    plc_nroaux = self.calcular_nro_siguiente(plc_idpadre)
    @plan_nuevo = Plancuenta.new( :Plc_IdPadre =>  plc_idpadre,
                                   :Plc_NroAux => plc_nroaux,
                                   :Plc_Desc => plc_desc)
    @plan_nuevo.save
  end

  def self.pone_puntos_intermedios nro
    str = ''
    nro.to_s.each_byte{|b| str += b.chr + "."}
    str
  end

  def self.cuentas_imputables
    ci = Plancuenta.find_by_sql("select * from plancuenta where id NOT IN
                      (select Plc_IdPadre from plancuenta)")
  end

  def before_save
    self.Plc_id = (self.Plc_IdPadre.to_s + self.Plc_NroAux.to_s).to_i
    self.Plc_Cod =  (Plancuenta.pone_puntos_intermedios(self.Plc_id) +
                               self.Plc_NroAux.to_s)
  end

end
class Asientos  :Plc_Id

  def self.hacer_caja
    str = ''
    Plancuenta.cuentas_imputables.each{|c|
      str += "Cuenta: #{c.Plc_id} Saldo: #{Asientos.saldo(c.Plc_id)}\n"
    }
    puts str
  end

  def self.saldo cuenta
     Asientos.find_all_by_Plc_Id(cuenta).collect{|a| a.Asi_Debe}.sum - \
      Asientos.find_all_by_Plc_Id(cuenta).collect{|a| a.Asi_Haber}.sum
  end

end

Esos son los dos modelos que hice para la solución que me llevó 2hs, el código se podría mejorar bastante pero me quedé bastante conforme, recuerden que estaba bajo la presión de rendir un exámen y no tenía mucho tiempo, además el prosefor me entregó la estructura de la base de datos en un archivo .mdb (de MS Access) y como yo uso Linux me la tuve que rebuscar para leer ese archivo y meterlo dentro de una db en Mysql.
Bueno la nota que me saqué fué 9 (sobresaliente).
Que experiencia tuvieron uds. en sus facultades? espero comentarios….

Snakes and rubies

Saturday, 19 April , 2008

Hace unos días que con Manuel Kaufmann (humitos) venimos comparando algunas cosas entre python y ruby, por simple curiosidad dado que son 2 lenguajes muy parecidos y que nos gustan mucho. Entonces se nos ocurrió escribir algunos problemas puntuales y sencillos para ver como los resuelve cada lenguaje, quiero aclarar que de ninguna manera queremos generar una guerra santa entre lenguajes ni mucho menos simplemente queremos divertirnos comparándolos. Entonces sin más vamos al grano, aquí va mi versión ruby de los ejercicios:

  1. Dado un array con nombres de persona eliminar los nombre que comienzan con “Pe”:
    irb(main):005:0> ["Pablo", "Raul",
    "Pedro", "Pepe", "Ariel", "TerePe"].delete_if{|n| n =~ /^Pe/}
    
    =>["Pablo", "Raul", "Ariel", "TerePe"]
  2. Verificar si el mismo array contiene el nombre “Raul”
     irb(main):006:0> ["Pablo", "Raul",
    "Pedro", "Pepe", "Ariel", "TerePe"].include?(”Raul”)
    
    => true
  3. Generar un string con todos los nombres unidos por “-”
    irb(main):009:0> ["Pablo", "Raul",
    "Pedro", "Pepe", "Ariel", "TerePe"].join(”-”)
    
    => “Pablo-Raul-Pedro-Pepe-Ariel-TerePe”
  4. Generar un segundo array con los nombres todos en minúsculas ordenado alfabéticamente
    irb(main):012:0> (["Pablo", "Raul",
    "Pedro", "Pepe", "Ariel", "TerePe"].collect{|n| n.downcase}).sort
    
    => ["ariel", "pablo", "pedro", "pepe", "raul", "terepe"]
  5. Desordenar el array:
    irb(main):016:0> ["Pablo", "Raul",
    "Pedro", "Pepe", "Ariel", "TerePe"].sort_by{ rand }
    
    => ["TerePe", "Pedro", "Raul", "Pablo", "Pepe", "Ariel"]
  6. Averiguar si la lista siguiente tiene números pares:
    irb(main):017:0> [1, 2, 3, 4, 5].any?{|x| x % 2 == 0 }
    
    => true
  7. Averiguar si toda la lista son números pares:
    irb(main):018:0> [1, 2, 3, 4, 5].all?{|x| x % 2 == 0 }
    
    => false
  8. Obtener el producto de una lista de números:
    irb(main):023:0> [1, 2, 3, 4, 5].inject{|x,n| x * n }
    
    => 120
  9. Obtener el factorial de 9999:
    irb(main):025:0> (1..9999).inject{|x,n| x * n }

    No voy a poner la salida del factorial por que es un número muuuuy….. largo pero lo pueden probar por uds mismos en el intérprete interactivo de ruby.

  10. Y por último averiguar si dos arrays son iguales:
    irb(main):002:0> [1, 2, 3, 4, 5].eql? [1, 2, 3, 4, 5]
    
    => true
  11. Todos los ejemplos se probaron con la versión 1.9 de ruby. Ahora para ver las versión python vamos a tener que estar atentos al blog de humitos

Autotest desde linux como en una Mac

Sunday, 17 February , 2008

Mirando algunos videos de rspec y autotest, noté que al correr los tests, en la pantalla de la notebook del video salían unos hermosos mensajes con transparencias, investigando un poco encontré que esto se hace con un programa llamado growl que sólo viene para usuarios de Mac OS X :( luego de tal desilusión comencé a buscar una alternativa en GNU/Linux … sí! hay un programa llamado aosd_cat que sirve para mostrar mensajes de texto UTF8 en la pantalla, vamos al grano:

apt-get install aosd_cat

Para probarlo podemos abrir una consola y ejecutar:

 echo "Probando..." | aosd_cat   --back-color=black  \
          --fore-color=red \
          --back-opacity=135  --padding=50

Ahora vamos a configurar autotest para que use aosd_cat

editamos el archivo ~/.autotest y ponemos lo siguiente:

module Autotest::Growl
  def self.aosd_cat title, msg, color
    params = "--back-color=black --fade-in=20 --fade-out=100 \
                   --fore-color=#{color} --back-opacity=200 \
                   --padding=30 \  --shadow-offset=0 \
                   --x-offset=0 --y-offset=0"

    system "echo \"#{title} #{msg} \" | aosd_cat #{params}"

  end

  Autotest.add_hook :run do  |at|

    aosd_cat "Autotest running", "Started", "Orange"

  end

  Autotest.add_hook :ran_command do |at|
    results = [at.results].flatten.join(”\n”)
    output  = results\
    .slice(/(\d+)\s+examples?,\s*(\d+)\s+failures?(,\s*(\d+)\s+pending)?/)
    if output
      if $~[2].to_i > 0
        aosd_cat “FAIL !!!”, “#{output}”, “red”
      else
        color = output =~ /[1-9]\spending?/ ? “yellow” : “green”
        aosd_cat “Pass”, “#{output}”, “#{color}”
      end

  end
end

Listo, ya podemos usar autotest y ver los mensajes como en una mac ;)

autotest path-al-proyecto/

Les dejo un screencast para que vean como quedó.

acts_as_menu_role plugin

Tuesday, 15 January , 2008

Hace poco tuve que hacer un desarrollo y uno de los requerimientos era hacer un menu (por controller) de acuerdo al rol del usuario, busqué sí ya había un plugin que haga este trabajo pero no encontré nada así me decidí a escribir uno y salió acts_as_menu_role, es algo muy simple, permite “armar” menúes basados en roles.
Aquí les dejo la url del sitio:
http://actsasmenurole.googlecode.com/
y el svn es:
http://actsasmenurole.googlecode.com/svn/tags/acts_as_menu_role
pruébenlo y cualquier cosa acepto sugerencias.

Módulos parte IV - Callbacks

Thursday, 13 December , 2007

Callbacks y hooks

Para continuar, vamos a ver el tema “callbacks” relacionado con los módulos, los callbacks y los hooks son una técnica de metaprogramación bastante común. Estos métodos son invocados cada vez que ocurre un evento particular durante la ejecución del programa, por ejemplo:

  • Un método inexistente es llamado en un objeto
  • Una clase es “mixineada” en un módulo
  • El “subclaseado” de una clase
  • Un método de instancia es agregado a una clase

Atrapando las operaciones de include con Module#included

Cuando un módulo es incluido (Mixed in) dentro de una clase, si se define un método llamado included para ese módulo, entonces este método se ejecuta. El método recibe el nombre de la clase como argumento.

module A
  def self.included(clase)
    puts "He sido incluido en #{clase}."
  end
end

class B
  include A
end

salida:

=> He sido incluido en la clase B.

Usando el callback included para agregar métodos de clase

Podemos atrapar la operación de include para agregar métodos de clase a la clase que estamos incluyendo el módulo:

module A
  def self.included(clase)
    def clase.metodo_de_clase
      puts "Agrego un metodo de clase."
    end
  end

  def metodo_de_instancia
    puts "Agrego un metodo de instancia."
  end

end

class B
  include A
end
b = B.new
b.metodo_de_instancia
B.metodo_de_clase

salida:

=> Agrego un metodo de instancia.
=> Agrego un metodo de clase

Bueno como vemos Module#included es una manera muy útil para agregar cosas a las clases/módulos de nuestros programas.
Esto fue todo, hasta el próximo post.

Modulos parte III

Wednesday, 12 December , 2007

Nuevamente amigos seguimos con el tema de los módulos en ruby, para continuar comenzaremos con un ejmeplo del uso de “super” entre módulos y clases:

module A
  def imprimir
    puts "Imprimo desde el --modulo-- A"
  end
end

class B
  include A
  def imprimir
    puts "Imprimo desde la --clase-- B"
    puts "Trigger para ejecutar el inmediato mas alto 'imprimir'"
    super
    puts "Vuelvo de la llamada a super."
  end
end
b = B.new
b.imprimir

salida:

=> Imprimo desde la --clase-- B
=> Trigger para ejecutar el inmediato mas alto 'imprimir'
=> Imprimo desde el --modulo-- A
=> Vuelvo de la llamada a super.

La instancia de B (b) recibe el mensaje “imprimir”, como vimos anteriormente comienza mirando la propia clase y encuentra el método “imprimir” , por otro lado dentro del método hay una llamada a super, esto significa que cuando encuentre un método “imprimir” debe continuar buscando hacia arriba al siguiente, la siguiente “ocurrencia” en este caso es la del módulo “A”. Hasta acá todo genial, pero que pasa si el método en cuestión tiene argumentos?
super maneja los argumentos de la siguiente forma:

  • Invocado sólo, super automáticamente redirige los argumentos pasado al método desde dónde se invocó.
  • Invocado con una lista vacía de argumentos –super()– no envía ningún argumento al método de arriba
  • Invocado con una lista de argumentos –super(a,b,c)– este envía exactamente estos argumentos

Cómo siempre cortito y simple, nos vemos en el próximo capítulo :)

Modulos parte II

Wednesday, 12 December , 2007

Bueno el post anterior vimos como usar módulo con métodos de instancia, métodos de módulo y variables de instancia de forma simple, ahora vamos a ver que pasa con la herencia.
Vamos a refrescar algunos conceptos. Algunas diferencias entre módulos y clases:
Cuando escribimos una clase, podemos tener instancias de esa clase (objetos) estas instancias pueden ejecutar los métodos de instancia de esa clase, por otro lado los módulos no pueden tener instancias, los módulos son “Mixed In” en las clases. Cuando esto sucede la instancia de la clase tiene la habilidad de llamar métodos de instancia definidos en el módulo (esto lo vimos en los ejemplos anteriores). Se podría decir que cuando hacemos un Mixin, por ejmeplo dentro de la clase A hacemos un include del Módulo B, es como que A hereda de B, las instancias de A pueden llamar a los métodos de instancia del módulo B. La principal diferencia entre la herencia de clases y la de los Mixins es que una clase puede heredar de una sóla superclase pero en una clase puede “Mixinear” muchos módulos (esto vendría a ser algo así como herencia múltiple). Cuando estamos diseñando un programa y detectamos que un comportamiento o conjunto de comportamientos es aplicable a más de una entidad u objeto entonces es un claro candidato a Módulo. Vamos directo al ejemplo:

Module A
  def imprimir
    puts "Imprimo desde el Modulo A"
  end
end
class B
  include A
end
class C < B
end
obj = C.new
obj.imprimir

Salida:

=> Imprimo desde el Modulo A

El método de instancia “imprimir” está definido en el Módulo A que luego es “Mixed In” en la clase B , y la clase C es una subclase de B. obj es una instancia de C. A través de esta “cascada’ el objeto (ibj) tiene acceso al método “imprimir”, veamos como es esto un poco más en detalle:
1- El objeto recibe el mensaje “imprimir”
2- La clase C define un método de clase llamado “impirmir” ?
3- NO
4- C tiene algún módulo Mixed in?
5- NO
6- La superclase de C es decir (B) define un método de instancia llamado “imprimir”
7- NO
8- B tiene algún módulo Mixed In?
9- SI: A
10- A define un método de instancia llamado “imprimir” ?
11- SI, entonces lo ejecuta

Esto es todo por este post, nos vemos en el próximo :)

Modulos

Tuesday, 11 December , 2007

Bueno en este post voy a mostrar un ejemplo sencillo con módulos de ruby, muy básicamente un módulo es una colección de métodos y constanstes, los métodos en un módulo pueden ser métodos de instancia o métodos de módulo. Los métodos de instancia aparecen como métodos en una clase cuando el módulo es incluido, los métodos de módulo no. Al contrario los métodos de módulo pueden ser llamados sin crear un objeto encapsulado, mientras que los métodos de instanacia no. (ref: http://www.ruby-doc.org/core/classes/Module.html)

Veamos un ejemplo dónde tenemos algunos métodos de instancia:

module Saludo
  attr_accessor :saludo

  def agregar_nombre
    @saludo << " Pepe"
  end
end

class SaludoNuevo
  include Saludo

  def saludo= value
    @saludo = value
  end
end

s =  SaludoNuevo.new
s.saludo = 'Hola'
puts s.saludo
s.agregar_nombre
puts s.saludo

La salida de este programa es la siguiente:

=> Hola
=> Hola Pepe

Cómo podemos ver los métodos declarados dentro del Módulo Saludo aparecen cómo métodos de instancia de la clase SaludoNuevo, dado que Saludable “Mixed in” en SaludadorNuevo. Los Mixins son la manera en que ruby resuelve la Herencia Múltiple (Ya veremos algunos ejemplos más adelante).

Ahora agregamos un método de Módulo:

module Saludo
  attr_accessor :saludo

  def agregar_nombre
    @saludo << " Pepe"
  end

  def Saludo::general
    "Hola a todos"
  end
end

class SaludoNuevo
  include Saludo

  def saludo= value
    @saludo = value
  end
end

puts Saludo::general

s =  SaludoNuevo.new
s.saludo = 'Hola'
puts s.saludo
s.agregar_nombre
puts s.saludo

Y la salida es:

=> Hola a todos
=> Hola
=> Hola Pepe

Ahora vamos a agregar una variable de instancia en el módulo Y la vamos a usar y modificar desde la clase cliente:

module Saludo
  attr_accessor :saludo, :nombres

  def initialize
    @nombres = ["Pepe", "Gaston", "David"]
  end

  def agregar_nombre
    @saludo << ” Pepe”
  end

  def Saludo::general
    “Hola a todos”
  end

end

class SaludoNuevo
  include Saludo

  def saludo= value
    @saludo = value
  end

  def saludo_general_con_nombres
    “Hola ” + @nombres.join(’, ‘)
  end

end

s = SaludoNuevo.new
puts s.saludo_general_con_nombres

# Modifico la variable de instancia @nombres Heredada del módulo “Saludo”
s.nombres << “Dave”
puts s.saludo_general_con_nombres

# Creo un nuevo objeto de Saludo Nuevo y modifico @nombres para
# ver que es una variable de instancia
s2 = SaludoNuevo.new
s2.nombres = ["Matz", "Kent", "Bruce"]
puts s2.saludo_general_con_nombres

puts s.saludo_general_con_nombres

la salida es:

=> Hola Pepe, Gaston, David
=> Hola Pepe, Gaston, David, Dave
=> Hola Matz, Kent, Bruce
=> Hola Pepe, Gaston, David, Dave

Bueno esto fue todo por ahora, cortito y sencilllo.

Monit y Mongrel

Monday, 19 November , 2007

Hace un tiempo escuché hablar de monit una herramienta que sirve para monitorear los mongrels (eso había escuchado yo…) pero en realidad es mucho más que eso! con monit podemos:

  • Monitorear servicios y reiniciarlos o matarlos si están consumiendo mucha memoria o procesador.
  • Iniciar un servicio que no está corriendo (y debería estarlo)
  • Monitorear archivos, directorios, dispositivos
  • Y mucho más…

Esta herramienta me viene al pelo dado que he estado experimentando algunos problemas con el mongrel (se cae o comienza a consumir mucha memoria). Para instalarlo en debian:

apt-get install monit

el archivo de configuracion está en /etc/monit/monitrc googleando un poco encontré este sitio
http://monitr.atmos.org/ el cual genera la configuracion para monit a partir de
los archivos de configuracion de mongrel_cluster.
Una vez que ya tenemos listo nuestro archivo de configuración tenemos que “activar” el monit y lo hacemos editando
el archivo /etc/default/monit cambiamos startup=0 por startup=1
Una de las cosas buenas de monit es que trae un sistema de monitoreo por web que por defecto está en el puerto 2812 (esto se especifica en el archivo de configuración) entonces lo podemos ver en http://localhost:2812/
Actualemente estoy monitoreando 4 mongrels y el nginx y funciona bárbaro, para los mongrels cuando detecta que consumen más de 100mb RAM los reinicia y cuando detecta que no responden (via http) también .
Acá les dejo un screenshot:

monit web

RubyGems bastante lento

Thursday, 15 November , 2007

Tengo un server con un micro AMD-K6(tm) 3D processor y 128 MB de RAM con un Debian GNU/Linux con ruby 1.8 RubyGems 0.9.4 mogrel y nginx 0.4.13-2, intentando hacer un gem update noté que se tomaba su tiempo, Updating installed gems…, luego de unas cuantas horas seguía en el mismo lugar, al parecer el problema está cuando cuando arma las lista de dependencias de las gemas, googleando un poco encontré esto: http://blog.segment7.net/articles/2007/10/13/rubygems-beta-0-9-4-5 una versión beta de rubygems que soluciona este problema, entonces pasé a instalarla:

gem update --system --source http://segment7.net/

Ahora funciona bastante mejor!!! al menos demora minutos y no horas como antes, como dice en el sitio este release mejora el manejo de memoria.