为方法名动态生成前缀
Dynamically generate prefixes for method names
假设我们有一堆带有典型前缀的方法。
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."
试试这个,
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
这是如何工作的?
- 我们在所有 classes
的 superclass 上定义了一个新函数 with_prefix
- 这个函数需要一个名字和一个块
- 在匿名模块的上下文中评估块。
- 这会在匿名模块上执行
def
语句而不是 class
- 枚举该模块的所有函数
- 为每个函数创建前缀方法
您可以使用回调方法Module#included and the class methods Method#instance_methods, Method#alias_method, Module#remove_method and Object#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_method
和 remove_method
是私有的 class 方法。语句 include Bar
显然必须遵循 Foo
.
中实例方法的定义
由于问题是(原文如此),"I want to automatically prepend a prefix to my instance method names...",前缀必须是硬连线的。
假设我们有一堆带有典型前缀的方法。
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."
试试这个,
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
这是如何工作的?
- 我们在所有 classes 的 superclass 上定义了一个新函数
- 这个函数需要一个名字和一个块
- 在匿名模块的上下文中评估块。
- 这会在匿名模块上执行
def
语句而不是 class - 枚举该模块的所有函数
- 为每个函数创建前缀方法
with_prefix
您可以使用回调方法Module#included and the class methods Method#instance_methods, Method#alias_method, Module#remove_method and Object#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_method
和 remove_method
是私有的 class 方法。语句 include Bar
显然必须遵循 Foo
.
由于问题是(原文如此),"I want to automatically prepend a prefix to my instance method names...",前缀必须是硬连线的。