简体   繁体   中英

Adding instance methods during class definition

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:

  1. Is class_eval the correct method to use here?
  2. Is define_method the correct method to use here?
  3. An options hash is passed into the class method, and used inside the instance method body. Is this safe? Any memory concerns?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM