Acts as date Module
Thursday, 26 June , 2008
Esta es una solución que se me ocurrió para hacerme más cómodo el trabajo con
el atributo created_at de un modelo, por ej:
Para saber el año de creación de un post, haríamos lo siguiente:
>> p = Post.find(1) >> p.created_at.month => 6
como podemos observar retorna 6, pero resulta que yo lo necesito necesito con el siguiente formato: “06″. Lo mismo pasa con el día:
>> p = Post.find(1) >> p.created_at.day => 4
module ActsAsDate
def year
created_at.strftime("%Y")
end
def month
created_at.strftime("%m")
end
def day
created_at.strftime("%d")
end
def year_month
[year, month]
end
# Armo un string para usarlo en un find
# ej:
# params = {:year => "2008", :month => "06"}
# Post.all(:conditions => Post.created_at_conditions(params))
#
def self.included(klass)
klass.class_eval do
def self.created_at_conditions(params)
return nil if params[:year].blank? or params[:month].blank?
"created_at like '#{params[:year]}-#{params[:month]}%'"
end
end
end
end
Entonces tenemos que incluir este módulo en modelo que lo queremos usar:
class Post < ActiveRecord::Base include ActsAsDate end
Ahora con esto directamente hago p.month, p.day, p.year y obtengo el mes, día y año de creación del post con el formato que necesito y escribiendo menos código :). Además agregué un método que me arma el param conditions, que se podría un usar así por ej:
class PostsController < ApplicationController
def list
@posts = Post.paginate(
:page => params[:page],
:order => 'created_at DESC',
:conditions => Post.created_at_conditions(params)
)
respond_to do |format|
format.html
format.xml { render :xml => @posts }
end
end
end
De esta manera no tengo que estar preguntando en el controller si vienen (year y month) como parámetros, por ahora este modulo sólo funciona con el atributo created_at por que está hardcodeado, pero con pocas modificaciones se podría hacer que funciona para cualquier atributo.
Ahora lo que me pregunto es si Rails ya tiene alguna solución mejor para este problema, si alguien la conoce que me lo haga saber por favor (yo no la encontré), además se aceptan modificaciones, sugerencias y comentarios.
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.
