Ruby 试图理解class_eval的用法

Ruby 试图理解class_eval的用法,ruby,ruby-on-rails-3,class-eval,Ruby,Ruby On Rails 3,Class Eval,我正在使用gem,我试图了解如何将函数添加到ActiveRecord类(我正在为纸牌游戏构建自己的库),我注意到这个gem使用一种元编程技术将函数添加到ActiveRecord::基类(我在ruby中远不是元编程大师,但我正在尝试学习它) 我知道第二个类的评估(在def设置之前)是在每个“有”设置的类上动态定义函数,对吗?同样的问题,我认为他可以使用“def self.settings”而不是“class_eval….def settings”,不?rails设置代码所做的被认为是良好的实践:它

我正在使用gem,我试图了解如何将函数添加到ActiveRecord类(我正在为纸牌游戏构建自己的库),我注意到这个gem使用一种元编程技术将函数添加到ActiveRecord::基类(我在ruby中远不是元编程大师,但我正在尝试学习它)


我知道第二个类的评估(在def设置之前)是在每个“有”设置的类上动态定义函数,对吗?同样的问题,我认为他可以使用“def self.settings”而不是“class_eval….def settings”,不?

rails设置代码所做的被认为是良好的实践:它只会在明确要求第三方模块这样做时才会弄乱。通过这种方式,您还可以将名称空间整齐地分隔开来,所有代码都保留在模块中。

您没有问我的问题,我知道这是一种很好的做法,第二个类的评估可以看到这一点,即“def设置”之前的一个类,但我的问题是关于第一个类的评估,使用它或打开类具有相同的效果否?@eMxyzptlk:您的意思是在方法内部执行“类xyz”吗?Ruby不允许它(错误:“方法体中的类定义”)@eMxyzptlk:我认为它只是添加了另一个级别的按需方法定义。通过将其放在Railtie上而不是ActiveRecord本身,可以要求此库,而无需向ActiveRecord添加
has\u设置
,直到明确请求为止,如果明确要求,它反过来提供定义
设置的选项。我知道,如果在函数定义中打开类定义,会出现错误,这是有道理的,但是如果查看代码,整个代码等待Rails调用Railtie.extend\u active\u record,这将打开ActiveRecord::基类和extend id,但是在我看来,用第二个版本替换整个代码(我问题中的第一个版本)很简单,你同意吗?两个版本都扩展了ActiveRecord::基类,都将设置和作用域添加到显式调用has\u设置的类中,但第二个版本更简单..我没有阅读所有内容。然而,也许这对你有帮助
Foo.class_eval{…}
class Foo。。。end
基本上是等效的。
module RailsSettings
  class Railtie < Rails::Railtie

    initializer 'rails_settings.initialize', :after => :after_initialize do
      Railtie.extend_active_record
    end

  end

  class Railtie
    def self.extend_active_record
      ActiveRecord::Base.class_eval do
        def self.has_settings
          class_eval do
            def settings
              RailsSettings::ScopedSettings.for_thing(self)
            end

            scope :with_settings, :joins => "JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
                                                               settings.thing_type = '#{self.base_class.name}')",
                                  :select => "DISTINCT #{self.table_name}.*"

            scope :with_settings_for, lambda { |var| { :joins => "JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
                                                                                    settings.thing_type = '#{self.base_class.name}') AND
                                                                                    settings.var = '#{var}'" } }

            scope :without_settings, :joins => "LEFT JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
                                                                       settings.thing_type = '#{self.base_class.name}')",
                                     :conditions => 'settings.id IS NULL'

            scope :without_settings_for, lambda { |var| { :joins => "LEFT JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
                                                                                            settings.thing_type = '#{self.base_class.name}') AND
                                                                                            settings.var = '#{var}'",
                                                          :conditions => 'settings.id IS NULL' } }
          end
        end
      end
    end

  end
end
module ActiveRecord
  class Base
    def self.has_settings
      class_eval do
        def settings
          RailsSettings::ScopedSettings.for_thing(self)
        end

        scope :with_settings, :joins => "JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
                                                           settings.thing_type = '#{self.base_class.name}')",
                              :select => "DISTINCT #{self.table_name}.*"

        scope :with_settings_for, lambda { |var| { :joins => "JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
                                                                                settings.thing_type = '#{self.base_class.name}') AND
                                                                                settings.var = '#{var}'" } }

        scope :without_settings, :joins => "LEFT JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
                                                                   settings.thing_type = '#{self.base_class.name}')",
                                 :conditions => 'settings.id IS NULL'

        scope :without_settings_for, lambda { |var| { :joins => "LEFT JOIN settings ON (settings.thing_id = #{self.table_name}.#{self.primary_key} AND
                                                                                        settings.thing_type = '#{self.base_class.name}') AND
                                                                                        settings.var = '#{var}'",
                                                      :conditions => 'settings.id IS NULL' } }
      end
    end
  end
end