Sfida: miglior modo per generare metodi dinamicamente!

Ciao a tutti,
Ho appena fatto un banalissimo plugin per rails, e mi ha scatenato il
dubbio
che io non stia facendo nel modo migliore la generazione automatica di
metodi in ruby… ok, mi spiego meglio (non è necessaria la conoscenza di
rails per godersi il post)
Per questo vi sfido (per gioco ovvio, visto che so di perdere:-)) a
trovare
una soluzione migliore…

Ho un oggetto che mi rappresenta un record di stima di un preventivo,
nel
quale devo salvare un campo discount che è un Float (lo sconto deve avere
2
decimali).
Io NON voglio salvare il float a DB ma voglio moltiplicarlo e dividerlo
per
100 ogni volta che lo salvo/leggo da db, in pratica lo salvo in
centesimi.
La cosa si fa così, da documentazione di rails:

class Estimate < ActiveRecord::Base
def discount=(value)
write_attribute(:discount, value * 100)
end

def discount
read_attribute(:discount) / 100
end
end

(soprassediamo sul fatto che non converte a float, ma non è quello il
punto)
Il problema è che io potrei avere 200 campi che voglio salvare in questo
modo, quindi con il sopracitato plugin voglio convertire il codice in:

class Estimate < ActiveRecord::Base
store_as_cents :discount
end

A questo punto parte la sfida: devo definire il metodo store_as_cents in
modo che mi crei in modo dinamico i getter e i setter.
Ho implementato il plugin come modulo in modo da mixare
store_as_centsinvece che ‘aprire’ la classe
ActiveRecord::Base, mi pare una soluzione più pulita e meno invasiva, ma per
qualche motivo ho la sensazione che si possa fare di meglio.

Di seguito la mia soluzione:

require ‘active_record’
module StoreAsCents
def self.included(mod)
mod.extend(ClassMethods)
end

module ClassMethods
# dinamically creates
# getters and setter that divide or multiply by 100
def store_as_cents(field_sym)
methods = <<-EOF
def #{field_sym}=(value)
write_attribute(:#{field_sym}, value * 100)
end

    def #{field_sym}
      read_attribute(:#{field_sym}) / 100
    end
  EOF
  class_eval methods
end

end
end

includes new methods

ActiveRecord::Base.class_eval do
include StoreAsCents
end

Mi pare contorto il fatto di dovere includere il modulo e poi dire al
modulo
che quando è incluso la classe deve estendere un’altro modulo interno e
bla
bla… ma così viene fatto nei plugins di rails che ho visto in giro…
Gabriele ormai mi ha convinto che rails fa schifo, quindi ora dobbiamo
trovare un modo migliore di fare sta cosa for god’s sake!!

Il per sempre vostro kamikaze,
Paolo

Ciao
premesso che non so nulla di ruby
dal punto di design , l’attributo discount non dovrebbe essere un tipo
“semplice” (ho scritto una cosa sbagliata ma si dovrebbe capire il
senso) ma
di una classe di tipo currency
e questa potrebbe avere i setter e i getter.

Ci sono un paio di aspetti da considerare funzionalmente

  • le logiche amministrative/fiscali per la gestione degli arrotondamenti
  • la somma di n prezzi arrotondati è diversa dalla somma arrontondata
    trovo strano delegare le logiche di arrotondamento al db

ma probabilmente il senso della domanda era tutt’altro
non appena imparerò qualcosa di puù di Ruby potrò essere più d’aiuto.
Ciao Paolo

2006/6/19, Paolo Donà [email protected]:

Per questo vi sfido (per gioco ovvio, visto che so di perdere:-)) a trovare
una soluzione migliore…

Manca un’informazione fondamentale: la posta
:stuck_out_tongue:

Michele

— Paolo Donà [email protected] ha scritto:

Ho un oggetto che mi rappresenta un record di stima
di un preventivo, nel
quale devo salvare un campo discount che è un Float
(lo sconto deve avere 2
decimali).

Non sarebbe meglio avere comunque un campo decimal ?
Mia mamma mi ha detto di non mettere insieme float e
soldi :slight_smile:

Io NON voglio salvare il float a DB ma voglio
moltiplicarlo e dividerlo per
100 ogni volta che lo salvo/leggo da db, in pratica
lo salvo in centesimi.

ok

end
io avrei usato una coppia di accessor da ruby (con
attr) e poi inserito una regola before_save, ma così è
effettivamente più consistente :slight_smile:

> # getters and setter that divide or multiply by > end > > Mi pare contorto il fatto di dovere includere il > modulo e poi dire al modulo > che quando è incluso la classe deve estendere > un'altro modulo interno e bla > bla...

concordo, è contorto, l’approccio di abusare
included è utile se devi mixare delle funzionalità sia
a livello di istanza che di classe, credo.
Nel tuo caso sarebbe più semplice mettere il modulo
direttamente nella classe tramite #extend, penso.

D’altronde penso che potresti levare la stringa ed il
class_eval e mettere semplicemente

define_method field_sym {code}
define_method “#{field_sym}=” {code2}

ma così viene fatto nei plugins di rails che
ho visto in giro…

dicevo l’altro giono a giovanni corriga che rails ha
effetti deleteri sulla comunità degli sviluppatori per
quel che riguarda l’abuso di
*eval/extend/include/singleton class.

Gabriele ormai mi ha convinto che rails fa schifo,
quindi ora dobbiamo
trovare un modo migliore di fare sta cosa for god’s
sake!!

oh mio dio cosa ho fatto! [cit]


icq: #69488917
blog it: http://riffraff.blogsome.com
blog en: http://www.riffraff.info

Chiacchiera con i tuoi amici in tempo reale!
Yahoo Search - Ricerca nel Web | Motore di Ricerca