Dagi3d v4

Programa de facturación en Ruby On Rails

Hace poco para optar a un trabajo tuve que realizar como prueba una aplicación en Rails que gestionase un listado de facturas junto a sus clientes. El caso es que decidí añadirle alguna cosilla más y hacerle una interfaz más aceptable y liberar el código por si a alguien le podía interesar.
La aplicación puede exportar a pdf(aunque hace falta java para esto) y el diseño del pdf es totalmente personalizable a partir de un documento xhtml y css.
De momento no tiene mucha cosa, pero la idea es utilizarlo e irlo ampliando conforme lo vaya necesitando ahora que empiezo con el tema del freelanceo.

Se puede ver en funcionamiento en http://facturails.dagi3d.net/ y se puede descargar directamente desde el repositorio subversion en http://svn.dagi3d.net/rails/facturails/trunk (bajo licencia MIT)

Sumando varios elementos de un array

Realizando una aplicación en Rails necesitaba sumar varios atributos de los objetos almacenados en un array. El problema es que cuando se trata de sumar un único atributo, se suele utilizar el método inject:

total = mi_array.inject { |sum, obj| sum + obj.value }

pero en este caso no me terminaba de convecer estar llamando al método inject tantas veces como atributos quisiera sumar, así que en teoría la solución pasaría por iterar sobre el array e ir sumando:

var1 = 0
var2 = 0
var3 = 0
...
mi_array.each do |obj|
  var1 += obj.value1
  var2 += obj.value2
  var3 += obj.value3
  ...
end

Funcionar, funcionaba, pero digamos que el código quedaba algo feo, así que para seguir trasteando, intenté encontrar una solución más 'ruby' y esto fue lo que hice:

class Array
  
  def accumulate(fields)
    
    results = fields.dup
    
    self.each do |obj|
      fields.each_key do |key|
        results[key] += obj.send(key) if obj.respond_to?(key)
      end
    end
    
    results
  end
end

Ahora bastaba con llamar al método accumulate sobre el array de objetos e indicar qué atributos quería sumar para obtener un hash con los resultados:

# la lista de objetos
foos = [
  OpenStruct.new(:foo => 1, :bar => 2, :foobar => 3),
  OpenStruct.new(:foo => 3, :bar => 4, :foobar => 5),
  OpenStruct.new(:foo => 5, :bar => 6, :foobar => 7)
]

foos.accumulate(:foo =>­; 0, :bar => 0, :foobar => 0) 
# {:foo=>9, :bar=>12, :foobar=>15}­