我创建了一个包含在类中的模块。在模块中,我试图定义一个方法,它是没有Filter的类名的下层版本。所以ShowFilter会有一个名为show的方法返回Show类。我得到“NoMethodError: showFilter的未定义方法`show':Class“
module Filters
module Base
module ClassMethods
@@filters = {}
def filter name, &block
@@filters[name] = block
end
def run query = {}
query.each do |name, value|
@@filters[name.to_sym].call(value) unless @@filters[name.to_sym].nil?
end
self
end
def self.extended(base)
name = base.class.name.gsub(/filter/i, '')
define_method(name.downcase.to_sym) { Kernel.const_get name }
end
end
def self.included base
base.extend ClassMethods
end
end
end
class ShowFilter
include Filters::Base
filter :name do |name|
self.show.where(:name => name)
end
end
编辑:使用示例
class ShowController < ApplicationController
def index
ShowFilter.run params[:query]
end
end
答案 0 :(得分:3)
当您定义Filters::Base::ClassMethods
时,它会在该上下文中评估self,因此您最终定义的方法是ClassMethods.classmethods
(因为gsub不会执行任何操作)。
就像你在Base中使用的包含钩子一样,你想在ClassMethods中使用扩展:
module Filters
module Base
module ClassMethods
@@filters = {}
def filter name, &block
@@filters[name] = block
end
def run query = {}
query.each do |name, value|
@@filters[name.to_sym].call(value) unless @@filters[name.to_sym].nil?
end
Object.const_get(self.to_s.gsub('Filter', ''))
end
def self.extended(base)
define_method(base.to_s.downcase.gsub('filter', '').to_sym) do
Object.const_get(self.to_s.gsub('Filter', ''))
end
end
end
def self.included base
base.extend ClassMethods
end
end
end
class ShowFilter
include Filters::Base
filter :title do |title|
self.show.where(:title => title)
end
end