简体   繁体   English

在类定义期间添加实例方法

[英]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: 具体来说,我创建了此模块,您应该将其extend到ActiveRecord模型中,如下所示:

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

Here is the source for the UnitedAttribues::Model module. 这是UnitedAttribues::Model模块的源代码。 https://github.com/nielsbuus/united_attributes/blob/master/lib/united_attributes/model.rb 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? class_eval是在此处使用的正确方法吗?
  2. Is define_method the correct method to use here? define_method是在此处使用的正确方法吗?
  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. 如果您可以使用ActiveSupport :: Concern ,那将是一种标准化的方式。

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. 在这种情况下,对options哈希的修改会无意中影响到两者。 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. 解决此问题的办法是dupclone传入的选项,或更好,挑出你想要的值,如果接收到未知的争论引发异常。 The options hash should not be considered the property of the unite method. options哈希不应该视为unite方法的属性。

You'll also run in to trouble if a caller passes in a frozen set of options. 如果呼叫者传入一组frozen的选项,您还将遇到麻烦。 Your call to merge! 您的merge!电话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. 通常,除非将方法专门用于执行此类功能,否则将操作传递给方法的参数视为无效形式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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