Essayer de comprendre l'utilisation de class_eval
-
11-10-2019 - |
Question
J'utilise les petit bijou , et je suis en train de comprendre comment vous ajoutez des fonctions aux classes ActiveRecord (je construis ma propre bibliothèque pour les jeux de cartes), et je remarqué que ce petit bijou utilise l'une des techniques de programmation Meta pour ajouter la fonction à la ActiveRecord :: la classe de base (je suis loin de maître-programmation Meta en ruby, mais je suis en train de l'apprendre)
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
Ce que je ne comprends pas pourquoi il utilise class_eval sur ActiveRecord :: Base, n'a pas été plus facile s'il suffit d'ouvrir la ActiveRecord :: La classe de base et définir les fonctions? Spécialement qu'il n'y a rien de dynamique dans le bloc (Ce que je veux dire par dynamique est quand vous faites class_eval ou instance_eval sur une chaîne contenant des variables)
quelque chose comme ceci:
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
Je comprends la deuxième class_eval (avant que les paramètres def) est de définir des fonctions à la volée sur toutes les classes que de droite « has_settings »? Même question ici, je pense qu'il pourrait utiliser "def self.settings" au lieu de "class_eval .... paramètres def", non?
La solution
Qu'est-ce que rails paramètres code n'est considéré comme une bonne pratique: il ne salit avec des modules tiers quand il est demandé de le faire explicitement ainsi. De cette façon, vous gardez aussi les espaces de noms et tous tidily Séparées vos restes de code dans vos modules.