I'm currently working on my first gem and making my first experiences in meta programming.
Therefore, I would like some feedback on how to correctly define an instance method during a class definition.
Specifically, I created this module that you are supposed to extend
in your ActiveRecord models like this:
class Duck < ActiveRecord::Base
extend UnitedAttributes::Model
attr_accessible :name, :weight
unite :weight, :kilogram
end
Here is the source for the UnitedAttribues::Model
module. https://github.com/nielsbuus/united_attributes/blob/master/lib/united_attributes/model.rb
And here is a shortened version without superfluous code:
module UnitedAttributes
module Model
def unite(accessor, unit, options = {})
class_eval do
define_method "united_#{accessor}" do
Attribute.new(self.send(accessor), options)
end
end
end
end
end
It appears to work, but I have some concerns:
class_eval
the correct method to use here? define_method
the correct method to use here? If you can use ActiveSupport::Concern , that would be a standardized way of doing this.
If not, you could always do something similar.
I wouldn't be worried about memory concerns. A hash is small, generally speaking. What I would be worried about is if the caller that passes in these options is unaware you'll be persisting them. For example:
options = { :foo => 'var', :bar => 'example' }
unite :name_1, :unit_a, options
options.delete(:example)
unite :name_2, :unit_b, options
In this case, the modification of the options
hash would impact both inadvertently. One way around this is to dup
or clone
the incoming options, or better, to pick out the values you want and raise an exception if an unknown argument is received. The options
hash should not be considered the property of the unite
method.
You'll also run in to trouble if a caller passes in a frozen
set of options. Your call to merge!
will produce an exception. In general, manipulating an argument passed in to a method is considered bad form unless the method is specifically intended to perform that kind of function.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.