2011-01-16 2 views
1

나는 rails-settings 보석을 사용하고의 사용을 이해하려고 노력하고, 나는 당신이 (나는 카드 게임에 대한 내 자신의 라이브러리를 짓고 있어요) 액티브 클래스에 기능을 추가하는 방법을 이해하기 위해 노력하고있어, 나는 그이를 발견 보석은 액티브 :: 기본 클래스에 기능을 추가하기 위해 메타 프로그래밍 기술 중 하나를 사용합니다 (I 루비에서 마스터 메타는 프로그래밍에서 멀리 해요,하지만 난 그것을 배우려고 노력하고있어)는 class_eval

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 

무엇 왜 그가 ActiveRecord :: Base 클래스를 열고 함수를 정의한다면 ActiveRecord :: Base에 class_eval을 사용하는 것이 이해가 안된다. 전과 (

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 

내가 두 번째 class_eval을 이해 :이 같은

뭔가 특별히 블록의 동적 아무 것도 없다는 것을 (당신이 변수를 포함하는 문자열에 class_eval 또는 instance_eval 할 때 내가 동적 의미하는 것은) def 설정)은 'has_settings'가 맞는 모든 클래스에서 즉석에서 함수를 정의하는 것입니다. 같은 질문을 던지면 "class_eval .... def settings"대신 "def self.settings"를 사용할 수 있다고 생각합니다.

답변

0

무엇을 레일스 설정 코드는 우수 사례로 간주됩니다. 제 3 자 모듈이 명시 적으로 그렇게 요청할 때만 코드가 엉망입니다. 이렇게하면 네임 스페이스를 간결하게 유지할 수 있으며 모든 코드가 모듈에 남아있게됩니다.

+0

당신은 내가, 그것이 좋은 연습을 알고 내 질문을 asnwer하지 않았고 즉, 두 번째 class_eval에 의해 그냥 "데프 설정"전에 하나를 볼 벌 수 있지만, 내 질문은 나 개방을 사용하여 첫 번째 class_eval에 대해이었다 그 수업에는 같은 효과가 없다고? – kalbasit

+1

@eMxyzptlk : 메서드 내에서 "클래스 xyz"를 수행한다는 의미입니까? – tokland

+0

@eMxyzptlk : 루비는 ("메소드 본문에서 클래스 정의"오류) : 허용하지 않습니다 나는 그냥 온 디맨드 방식 정의의 또 다른 레벨을 추가 생각합니다. 대신 액티브 자체의 Railtie에 이러는함으로써, 명시 적으로 다시 명시 적으로 요청하는 경우'settings'을 정의하는 옵션을 제공하는 요청 될 때까지 심지어 액티브에'has_settings'를 추가하지 않고이 라이브러리를 필요로하는 것이 가능하다. –