mar*_*cgg 2 ruby metaprogramming
使用Ruby我知道你可以通过命名方法获得相当的创意.例如,你有铁轨.find_by_this_and_that.
我怎样才能做到这一点?
例:
def get_persons_with_5_things
res = []
persons.each do |person|
if person.number_of_things == %MAGICALLY GET THE NUMBER 5 FROM FUNCTION NAME%
res << person
end
end
return res
end
Run Code Online (Sandbox Code Playgroud)
我甚至不确定你怎么称呼这类东西所以任何指针都会受到赞赏.
ott*_*bar 10
你的例子我有点困惑.如果在方法名称中使用硬编码5定义方法,则不需要在方法体内进行神奇地计算.如果你想用方法缺失做一些动态的东西,它将是这样的:
def method_missing(name, *args)
if name.to_s =~ /get_persons_with_(\d+)_things/
number_of_things = $1.to_i
res = []
persons.each do |person|
if person.number_of_things == number_of_things
res << person
end
end
return res
else
return super(name, *args)
end
end
Run Code Online (Sandbox Code Playgroud)
[编辑(JörgWMittag)]:这是一种更为Rubyish的方法来实现相同的方法:
def method_missing(name, *args)
return super unless name.to_s =~ /get_persons_with_(\d+)_things/
number_of_things = $1.to_i
return persons.select {|person| person.number_of_things == number_of_things }
end
Run Code Online (Sandbox Code Playgroud)
super 没有任何参数只传递原始参数,不需要显式传递它们return由尾随if或unless表达保护的早期大大清除了控制流程each迭代器都是根据谓词选择项目; 但是,已经有一个用于选择项目的迭代器:selectRuby有不同的元编程技术来做这种事情.
首先,我们需要变量方法
class DB
def get_persons_with_x_things(x)
res = []
persons.each do |person|
if person.number_of_things == x
res << person
end
end
return res
end
end
Run Code Online (Sandbox Code Playgroud)
如果有一定数量的x.我们可以define_method用来创建所有这些方法.define_method创建一个方法.第一个参数是方法的名称,seccond参数或给定的块是东西,它在调用方法时执行.
这样,你不会真正创建这样的方法,但如果用户调用它,它会查找用户,就像它存在一样.但是如果用户依赖Object#methods等等,他将永远不会看到你无数的假方法.
class DB
99.times do |i|
define_method("get_persons_with_#{i}_things") do
get_persons_with_x_things(i)
end
end
end
Run Code Online (Sandbox Code Playgroud)
如果有一个无限的x's numbor method_missing将更适合这个任务.如果有人试图调用不存在的方法,method_missing则执行.第一个参数method_missing是方法名称作为符号,以下参数是原始参数.
class DB
def method_missing(name, *args)
case name.to_s
when /^get_persons_with_(\d+)_things$/
get_persons_with_x_things($1.to_i)
else
super(name, *args)
end
end
end
Run Code Online (Sandbox Code Playgroud)
不使用静态regexe会更酷.但这可能会带来一些安全隐患.该方法send我在这里使用,调用由它的名称的方法.
class DB
def method_missing(name, *args)
name.to_s=~ /\d+/
# always be carefull with $ variables, they are global for this thread, so save everything as fast as you can
new_name= "#{$`}x#{$'}"
number= $1.to_i
if method_defined?(new_name)
send(new_name, number)
else
super(name, *args)
end
end
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
192 次 |
| 最近记录: |