2011-01-16 24 views
1

私はrails-settingsの宝石を使用していますが、私はActiveRecordクラスに関数を追加する方法を理解しようとしています(私はカードゲーム用の独自のライブラリを構築しています)宝石は、ActiveRecordのに機能を追加するためのメタプログラミングテクニック::基本クラスの1(私は遠くルビーにおけるメタプログラミングマスターからだけど、私はそれを学ぶためにしようとしている)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を使用する理由はわかりません。特別ダイナミック何もブロック内にありませんことを(あなたは、変数を含む文字列にclass_evalメソッドやinstance_evalを行うときに私は、ダイナミックで意味がある)このような

何か:私は前に(第2 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 

def設定)は、 'has_settings'という権利を持つすべてのクラスでその関数をオンザフライで定義することですか?私は彼が "class_eval .... def settings"の代わりに "def self.settings"を使うことができると思います。

答えて

0

コードは良い習慣と見なされない何レール-の設定:明示的にそうするように頼まだとき、それは唯一のサードパーティのモジュールで台無し。この方法でも、名前空間を細かく区切っておき、すべてのコードをモジュールに残します。

+0

あなたは私の質問を非難しなかった、私はそれが良い習慣であることを知っていて、それは2番目のclass_eval、 "def settings"の直前のもので見ることができるが、私の質問は最初のclass_evalクラスは同じ効果がない? – kalbasit

+1

@eMxyzptlk:方法の中で「クラスxyz」をやっているのですか? Rubyはそれを許可していません(エラー: "メソッド本体のクラス定義") – tokland

+0

@eMxyzptlk:私はそれだけで別のレベルのオンデマンドメソッド定義を追加すると思います。これをActiveRecordの代わりにRailtieに置くことで、明示的に要求されるまでActiveRecordに 'has_settings'を追加しなくてもこのライブラリを要求することができます。明示的に要求された場合は' settings'を定義するオプションが与えられます。 –

関連する問題