我有两个班级:
class Activity < ActiveRecord::Base
belongs_to :activity_type
def belongs_to_cat_a?
self.activity_category == ActivityCategory.category_a
end
def belongs_to_cat_b?
self.activity_category == ActivityCategory.category_b
end
end
class ActivityCategory < ActiveRecord::Base
has_many :activities
def self.cat_a
ActivityCategory.find_by_name("CatA")
end
def self.cat_b
ActivityCategory.find_by_name("CatB")
end
end
使用元编程,我将ActivityCategory更改为以下内容:
class ActivityCategory < ActiveRecord::Base
has_many :activities
CATEGORIES = ['CatA', 'CatB']
class << self
CATEGORIES.each do |c|
define_method "#{c.underscore.downcase}" do # for ex: cat_a
find_by_name(c)
end
end
end
end
确定。现在想象在类Activity中我有大约12种方法来检查它属于哪个类别 似乎是使用MP进行干燥的完美候选者。
我该怎么办?
答案 0 :(得分:7)
我不确定这是MP的好候选人。首先,您正在对类别进行硬编码,它们正在编写代码,而不是生成代码。如果要在被询问是否属于某个类别时返回true / false语句,您可以执行以下操作:
class Activity < ActiveRecord::Base
...
def belongs_to? activity
activity_type.name == activity
end
end
并按原样执行...
a = Activity.save(:activity_category => ActivityCategory.new(:name => "CatA")
a.belongs_to? "CatA" #=> true
还是我错过了这一点?
答案 1 :(得分:0)
这不是一种推荐的方式,因为这段代码往往有点难以维护(Jed的解决方案更好),但你可以应用你已经拥有的相同风格的MP:
class Activity < ActiveRecord::Base
belongs_to :activity_type
CATEGORIES = ['CatA', 'CatB']
class << self
CATEGORIES.each do |c|
define_method "belongs_to_#{c.underscore.downcase}?" do # for ex: cat_a
self.activity_category == ActivityCategory.send( "category_#{c[-1]}".to_sym )
end
end
end
end
答案 2 :(得分:0)
首先,我会改变你已有的东西。
如果使用method_missing拦截它,则可以避免对类别列表进行硬编码。
class ActivityCategory < ActiveRecord::Base
has_many :activities
alias_method :old_method_missing, :method_missing
def self.method_missing(method, *args, &block)
if cat = self.class.find_by_name(method.to_s)
return cat
else
old_method_missing(method, *args, &block)
end
end
end
这是有效的,因为如果未检测到调用的方法,它将把它传递给缺少的旧方法。如果你想提出任何类似的技巧,请不要将任何类别命名为“发现”或类似的任何类别!
以同样的方式,在活动中,你可以做到
class Activity < ActiveRecord::Base
belongs_to :activity_type
alias_method :old_method_missing, :method_missing
def method_missing(method, *args, &block)
if matchdata = /\Abelongs_to_category_(\w)\?/.match(method.to_s)
return ActivityCategory.find_by_name(matchdata[1]) == ActivityCategory.send(matchdata[1].to_sym)
else
old_method_missing(method, *args, &block)
end
end
end
我不确定语法是否完全正确,但您可以调查一般方法