I''ve clearly go a lot of repetition in the following methods: def name=(value) write_attribute(:name, if [0,"0",""," "].include? value then nil else value end) end def address=(value) write_attribute(:address, if [0,"0",""," "].include? value then nil else value end) end def city=(value) write_attribute(:city, if [0,"0",""," "].include? value then nil else value end) end Can someone tell me the convention to DRY this code? I''m wondering if I use a lambda but am not quite sure that''s the right path or how to do that. Thanks, Bill -- Posted via http://www.ruby-forum.com/.
Hi -- On Sat, 17 Oct 2009, Bill Devaul wrote:> > I''ve clearly go a lot of repetition in the following methods: > > def name=(value) > write_attribute(:name, if [0,"0",""," "].include? value then nil > else value end) > end > def address=(value) > write_attribute(:address, if [0,"0",""," "].include? value then nil > else value end) > end > def city=(value) > write_attribute(:city, if [0,"0",""," "].include? value then nil > else value end) > end > > Can someone tell me the convention to DRY this code? I''m wondering if I > use a lambda but am not quite sure that''s the right path or how to do > that.One idea is simply to parameterize the process: def generic_writer(attr, value) @blanks ||= [0, "0", "", " "] write_attribute(attr, @blanks.include?(value) ? nil : value) end def name=(value) generic_writer(:name, value) end etc. If you want, you can automate the creation of the methods instead: %w{ name address city }.each do |attr| define_method("#{attr}=") do |value| @blanks ||= [0, "0", "", " "] write_attribute(attr, @blanks.include?(value) ? nil : value) end end David -- The Ruby training with D. Black, G. Brown, J.McAnally Compleat Jan 22-23, 2010, Tampa, FL Rubyist http://www.thecompleatrubyist.com David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)
Thanks for the help. I used the latter to come up with: @fields_to_normalize = %w{ address city country_id email_general fax name phone phone_local state_id vacation_end_on vacation_notice vacation_start_on zip_code } @fields_to_normalize.each do |attr| define_method("#{attr}=") do |value| @blanks ||= [0, "0", "", " "] write_attribute(attr, @blanks.include?(value) ? nil : value) end end Is it possible to do something more Rails-ish so it reads: normalize_fields :address, :city, :country_id This additional re-factoring would allow re-use across models. Bill -- Posted via http://www.ruby-forum.com/.
Hi -- On Sat, 17 Oct 2009, Bill Devaul wrote:> > Thanks for the help. I used the latter to come up with: > > @fields_to_normalize = %w{ address city country_id email_general fax > name phone phone_local state_id vacation_end_on vacation_notice > vacation_start_on zip_code } > > @fields_to_normalize.each do |attr| > define_method("#{attr}=") do |value| > @blanks ||= [0, "0", "", " "] > write_attribute(attr, @blanks.include?(value) ? nil : value) > end > end > > Is it possible to do something more Rails-ish so it reads: > > normalize_fields :address, :city, :country_idSure -- just write the method :-) I would consider putting the blanks in a constant. class Whatever BLANKS = [0, "0", "", " "] def self.normalize_fields(*syms) syms.each do |attr| define_method("#{attr}=") do |value| write_attribute(attr, BLANKS.include?(value) ? nil : value) end end end normalize_fields :address, :city, :country_id end David -- The Ruby training with D. Black, G. Brown, J.McAnally Compleat Jan 22-23, 2010, Tampa, FL Rubyist http://www.thecompleatrubyist.com David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)
Thanks to your help David I now have: # lib/normalizer.rb module Normalizer BLANKS = [0, "0", "", " "] def self.included(base) base.class_eval do def self.normalize(*syms) syms.each do |attr| define_method("#{attr}=") do |value| write_attribute(attr, BLANKS.include?(value) ? nil : value) end end end end end end (I struggled with the above until I read that class_eval is needed to make the inclusion happen. I wonder if a change to class_eval to yield the included module would feel more natural.) and # models/model.rb include Normalizer normalize :name, :address, :city, :country_id Looks great and tests pass! Thanks, Bill -- Posted via http://www.ruby-forum.com/.
Hi -- On Sun, 18 Oct 2009, Bill Devaul wrote:> > Thanks to your help David I now have: > > # lib/normalizer.rb > module Normalizer > > BLANKS = [0, "0", "", " "] > > def self.included(base) > base.class_eval do > def self.normalize(*syms) > syms.each do |attr| > define_method("#{attr}=") do |value| > write_attribute(attr, BLANKS.include?(value) ? nil : value) > end > end > end > end > end >end> > (I struggled with the above until I read that class_eval is needed to > make the inclusion happen. I wonder if a change to class_eval to yield > the included module would feel more natural.)You should be able to do: def self.included(base) def base.normalize(*syms) ... end end I might be inclined to do: module Normalizer def normalize(*syms) ... end end class Whatever extend Normalizer ... end i.e., extend the class object directly rather than grabbing it indirectly and operating on it. It seems a little more streamlined. David -- The Ruby training with D. Black, G. Brown, J.McAnally Compleat Jan 22-23, 2010, Tampa, FL Rubyist http://www.thecompleatrubyist.com David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)