动态生成方法名称的前缀

时间:2016-12-27 07:49:41

标签: ruby metaprogramming dsl

假设我们有一堆带有典型前缀的方法。

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."

2 个答案:

答案 0 :(得分: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语句
  • 枚举该模块的所有功能
  • 为每个函数创建前缀方法

答案 1 :(得分:1)

您可以使用回调方法Module#included和类方法Method#instance_methodsMethod#alias_methodModule#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中的实例方法的定义。

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