Ruby 动态生成方法名称的前缀

Ruby 动态生成方法名称的前缀,ruby,metaprogramming,dsl,Ruby,Metaprogramming,Dsl,假设我们有一组带有典型前缀的方法 def pref_foo # code end def pref_bar # code end 我想学习如何将这些前缀自动添加到我的方法名之前,就像在Rails中一样:Model.find\u by_smth 换句话说,我想创建一些作用域pref_,它将方法和pref_前置到它们的名称中,因此我的方法foo可以作为pref_foo使用 试试这个 class Module def with_prefix(prefix, &block)

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

def pref_foo
  # code
end

def pref_bar
  # code
end
我想学习如何将这些前缀自动添加到我的方法名之前,就像在Rails中一样:Model.find\u by_smth

换句话说,我想创建一些作用域pref_,它将方法和pref_前置到它们的名称中,因此我的方法foo可以作为pref_foo使用

试试这个

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
这是怎么回事

我们在所有类的超类上定义了一个带有前缀的新函数 此函数采用名称和块 在匿名模块的上下文中计算块。 这将在匿名模块而不是类上执行def语句 枚举该模块的所有函数 为每个函数创建带前缀的方法 试试这个

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
这是怎么回事

我们在所有类的超类上定义了一个带有前缀的新函数 此函数采用名称和块 在匿名模块的上下文中计算块。 这将在匿名模块而不是类上执行def语句 枚举该模块的所有函数 为每个函数创建带前缀的方法
您可以使用回调方法和类方法,如下所示

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_方法和remove_方法是私有类方法。语句include Bar显然必须遵循Foo中实例方法的定义


由于问题是这样的,我想自动在我的实例方法名称前面加一个前缀…,前缀必须是硬连接的。

您可以使用回调方法和类方法,如下所示

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_方法和remove_方法是私有类方法。语句include Bar显然必须遵循Foo中实例方法的定义


问题是,我想自动在实例方法名称前面加一个前缀…,前缀必须是硬连接的。

签出:签出:太棒了!还有一个问题:我如何使用_前缀嵌套?这个答案完全值得赏金。很高兴听到你发现它很有用!令人惊叹的还有一个问题:我如何使用_前缀嵌套?这个答案完全值得赏金。很高兴听到你发现它很有用!