私は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"を使うことができると思います。
あなたは私の質問を非難しなかった、私はそれが良い習慣であることを知っていて、それは2番目のclass_eval、 "def settings"の直前のもので見ることができるが、私の質問は最初のclass_evalクラスは同じ効果がない? – kalbasit
@eMxyzptlk:方法の中で「クラスxyz」をやっているのですか? Rubyはそれを許可していません(エラー: "メソッド本体のクラス定義") – tokland
@eMxyzptlk:私はそれだけで別のレベルのオンデマンドメソッド定義を追加すると思います。これをActiveRecordの代わりにRailtieに置くことで、明示的に要求されるまでActiveRecordに 'has_settings'を追加しなくてもこのライブラリを要求することができます。明示的に要求された場合は' settings'を定義するオプションが与えられます。 –