Der Versuch, die Verwendung von class_eval zu verstehen
-
11-10-2019 - |
Frage
Ich verwende die Schienen-Einstellungen Juwel, und ich versuche zu verstehen, wie Sie Funktionen Active Klassen hinzufügen (ich bin meine eigene Bibliothek für Kartenspiele Gebäude), und ich bemerkte, dass dieses Juwel einer der Meta-Programmiertechniken verwendet die Funktion der Activerecord :: Base-Klasse (ich bin weit davon hinzufügen aus Meta-Programmierung Master in ruby, aber ich versuche, es zu lernen)
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
Was ich nicht verstehe ist, warum er verwendet class_eval auf Activerecord :: Base, wurde es nicht leichter, wenn er nur die Active öffnen :: Basisklasse und die Funktionen definieren? Speziell, dass es dynamische nichts im Block (Was ich damit meine ist dynamisch, wenn Sie tun class_eval oder instance_eval auf einem String-Variablen enthält)
so etwas wie folgt aus:
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
verstehe ich die zweite class_eval (vor den def Einstellungen) ist Funktionen im laufenden Betrieb auf jeder Klasse zu definieren, dass ‚has_settings‘ richtig? Gleiche Frage hier, glaube ich, dass er „def self.settings“ statt „class_eval .... def Einstellungen“ verwenden könnte, nicht wahr?
Lösung
Was Schienen-Einstellungen Code hat sich als gute Praxis: es nur Verwirrungen mit Module von Drittanbietern, wenn es ausdrücklich darum gebeten. Auf diese Weise können auch die Namensräume halten säuberlich getrennt und alle Ihren Code bleibt in Ihrer Module.