有几种方法可以给这只猫剥皮。一种是使用 lambda:
MATCHERS = [
[/^gnome|dwarf|hobbit$/, lambda { |a| 'dwarf' }],
['dragon', lambda { |a| puts 'run away!' }],
[/^centaur|unicorn$/, lambda { |a| magical_equine_function(a) }],
[//, lambda { |a| false }],
]
这将模式(可以是字符串或正则表达式)与 lambda 相关联。最后一个匹配器很特别:它是一个可以匹配任何东西的哨兵。它代表您示例中的else子句。
这是进行匹配的代码:
def match(a)
MATCHERS.each do |pattern, f|
return f[a] if pattern === a
end
end
我们使用===
以便可以使用字符串或正则表达式。
以下是它的使用方法:
p match('gnome')
# => "dwarf"
p match('dragon')
# => "run away!"
# => nil
p match('unicorn')
# => "equine unicorn"
p match('oddball')
# => false
您也可以使用方法来做到这一点:
class Matcher
def match(a)
MATCHERS.each do |pattern, method|
return send(method, a) if pattern === a
end
end
private
MATCHERS = [
[/^gnome|dwarf|hobbit$/, :dwarf],
['dragon', :dragon],
[/^centaur|unicorn$/, :equine],
[//, :default],
]
def dwarf(a)
"dwarf"
end
def dragon(a)
puts "run away!"
end
def equine(a)
magical_equine_function(a)
end
def default(a)
false
end
def magical_equine_function(a)
"equine #{a}"
end
end
并在使用中:
matcher = Matcher.new
p matcher.match('gnome')
# => "dwarf"
# etc.
使用方法将代码与匹配规则分开,如果需要,您可以将匹配规则放入文件中。这是的内容match_rules
:
---
- - !ruby/regexp /^gnome|dwarf|hobbit$/
- :dwarf
- - dragon
- :dragon
- - !ruby/regexp /^centaur|unicorn$/
- :equine
- - !ruby/regexp //
- :default
我们不必对Matcher
类进行很多更改即可使其正常工作:
require 'yaml'
class Matcher
def initialize
@matchers = YAML.load_file('match_rules')
end
def match(a)
@matchers.each do |pattern, method|
return send(method, a) if pattern === a
end
end
# ...
end
使用send
您从文件中获取的数据允许创建该文件的人让您调用任何 Matcher 类的方法。为了防止这种情况,您可以简单地为规则中使用的所有方法添加一个前缀:
def matched_dragon(a)
puts "run away!"
end
# etc.
在 match 方法中,添加该前缀:
def match(a)
@matchers.each do |pattern, method|
return send("matched_#{method}", a) if pattern === a
end
end
现在只有以“matched_”为前缀的方法才能被 match 函数调用。
在评论中回答后续问题:
模式是字符串数组的 YAML 如下所示:
---
- - - gnome
- dwarf
- hobbit
- :small_person
- - - dragon
- :dragon