2016-12-27 56 views
1

假设我们有一堆带有典型前缀的方法。动态生成方法名称的前缀

def pref_foo 
    # code 
end 

def pref_bar 
    # code 
end 

我想学习如何自动前面加上前缀那些我的方法的名字(例如它是如何在Rails中完成的:Model.find_by_smth)。

换句话说,我想创造一些范围pref_,这需要方法,并预置pref_他们的名字,所以我的方法foo变得可作为pref_foo


module Bar 
    # definition of some wrapper `pref_` 
end 

class Foo 
    include Bar 

    <some wrapper from Bar> do 
    def foo 
     puts 'What does a computer scientist wear on Halloween?' 
    end 

    def bar 
     puts 'A bit-mask.' 
    end 
    end 
end 

foo = Foo.new 

foo.pref_foo # => "What does a computer scientist wear on Halloween?" 
foo.pref_bar # => "A bit-mask." 
+0

检出['method_missing'](https://ruby-doc.org/core-2.3.3/BasicObject.html#method-i-method_missing):) –

回答

5

试试这个,

class Module 
    def with_prefix(prefix, &block) 
    m = Module.new 
    m.instance_eval(&block) 
    m.methods(false).each do |name| 
     define_method "#{prefix}_#{name}", &m.method(name) 
     module_function "#{prefix}_#{name}" unless self.is_a?(Class) 
    end 
    end 
end 

class A 
    with_prefix :pref do 
    with_prefix :and do 
     def foo 
     puts "foo called" 
     end 

     def bar 
     puts "bar called" 
     end 
    end 
    end 
end 

A.new.pref_and_foo 
A.new.pref_and_bar 

这是如何工作的?

  • 我们对所有类
  • 此功能需要一个名称和块
  • 评估在一个匿名模块的上下文块的超类定义了一个新的功能with_prefix
  • 此执行匿名模块上的def语句,而不是在该模块的所有功能类
  • 枚举
  • 为每个这样的功能,并创建前缀的方法
+0

太棒了!还有一个问题:我如何使'with_prefix'嵌套? – Viktor

+1

@viktordanilov更新! – akuhn

+0

这个答案完全值得奖励 – Viktor

1

你可以使用回调方法Module#included以及类别方法Method#instance_methods,Method#alias_method,Module#remove_methodObject#send如下。

module Bar 
    def self.included(klass) 
    klass.instance_methods(false).each do |m| 
     klass.send :alias_method, "pref_#{m.to_s}".to_sym, m 
     klass.send :remove_method, m 
    end 
    end 
end 

class Foo 
    def foo 
    puts 'hi' 
    end 

    def bar 
    puts 'ho' 
    end 

    include Bar 
end 

Foo.instance_methods.select { |m| [:foo, :bar, :pref_foo, :pref_bar].include?(m) } 
    #=> [:pref_foo, :pref_bar] 

Foo.new.pref_foo 
    #=> "hi" 

Foo.new.foo 
    #=> NoMethodError: undefined method `foo' for #<Foo:0x007fdecb0633d8> 

send必须被使用,因为alias_methodremove_method是私有的类方法。语句include Bar显然必须遵循Foo中实例方法的定义。

由于问题是(原文如此),“我想自动添加前缀到我的实例方法名称...”,前缀必须是硬连线的。