0

私は現在、最初の gem に取り組んでおり、メタ プログラミングで初めての経験をしています。

したがって、クラス定義中にインスタンス メソッドを正しく定義する方法について、フィードバックをお願いします。

具体的には、次extendのように ActiveRecord モデルで使用することになっているこのモジュールを作成しました。

class Duck < ActiveRecord::Base
  extend UnitedAttributes::Model
  attr_accessible :name, :weight
  unite :weight, :kilogram
end

UnitedAttribues::Modelモジュールのソースはこちら。https://github.com/nielsbuus/united_attributes/blob/master/lib/united_attributes/model.rb

そして、これは余分なコードを除いた短縮版です:

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

動作しているように見えますが、いくつかの懸念があります。

  1. class_evalここで使用する正しい方法はありますか?
  2. define_methodここで使用する正しい方法はありますか?
  3. オプション ハッシュはクラス メソッドに渡され、インスタンス メソッド本体内で使用されます。これは安全ですか?メモリに関する懸念はありますか?
4

1 に答える 1

0

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.

于 2013-05-18T00:42:40.347 に答える