【问题标题】:Adding instance methods during class definition在类定义期间添加实例方法
【发布时间】:2013-05-18 00:28:34
【问题描述】:

我目前正在开发我的第一个 gem,并在元编程方面进行了我的第一次体验。

因此,我想要一些关于如何在类定义期间正确定义实例方法的反馈。

具体来说,我在 ActiveRecord 模型中创建了这个你应该 extend 的模块,如下所示:

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. 选项哈希被传递到类方法中,并在实例方法主体内使用。这安全吗?有内存问题吗?

【问题讨论】:

    标签: ruby-on-rails ruby activerecord metaprogramming


    【解决方案1】:

    如果您可以使用ActiveSupport::Concern,那将是一种标准化的方式。

    如果没有,你总是可以做类似的事情。

    我不会担心内存问题。一般来说,散列很小。我会担心的是,如果传入这些选项的调用者不知道您将保留它们。例如:

    options = { :foo => 'var', :bar => 'example' }
    
    unite :name_1, :unit_a, options
    
    options.delete(:example)
    
    unite :name_2, :unit_b, options
    

    在这种情况下,options 哈希的修改会无意中影响两者。解决此问题的一种方法是 dupclone 传入选项,或者更好的是,选择您想要的值并在收到未知参数时引发异常。 options 哈希不应被视为 unite 方法的属性。

    如果调用者传入frozen 选项集,您也会遇到麻烦。您对merge! 的调用将产生异常。一般来说,操纵传入方法的参数被认为是错误的形式,除非该方法专门用于执行这种功能。

    【讨论】:

    • 调用者应该在类定义期间为这个方法显式地创建一个选项哈希,所以应该可以改变它。不过,异常建议很有趣,因为我确实想保护 gem,以便调用者尽快知道他做错了。
    • 明天我会调查 ActiveSupport::Concern,谢谢你的建议。
    猜你喜欢
    • 1970-01-01
    • 2012-12-14
    • 2011-11-15
    • 2020-10-24
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 2013-04-30
    • 1970-01-01
    相关资源
    最近更新 更多