我刚开始使用IronRuby(但是我在普通Ruby中测试它的行为似乎是一致的)我的.NET应用程序中的DSL - 作为其中的一部分,我定义了通过define_method从DSL调用的方法
但是,在调用以大写字母开头的方法时,我遇到了关于可选parens的问题。
鉴于以下计划:
class DemoClass
define_method :test do puts "output from test" end
define_method :Test do puts "output from Test" end
def run
puts "Calling 'test'"
test()
puts "Calling 'test'"
test
puts "Calling 'Test()'"
Test()
puts "Calling 'Test'"
Test
end
end
demo = DemoClass.new
demo.run
在控制台中运行此代码(使用普通红宝石)会产生以下输出:
ruby .\test.rb
Calling 'test'
output from test
Calling 'test'
output from test
Calling 'Test()'
output from Test
Calling 'Test'
./test.rb:13:in `run': uninitialized constant DemoClass::Test (NameError)
from ./test.rb:19:in `<main>'
我意识到Ruby约定是常量以大写字母开头,并且Ruby中方法的一般命名约定是小写的。但是parens目前正在杀死我的DSL语法。
有没有解决这个问题的方法?
答案 0 :(得分:7)
这只是Ruby暧昧解决方案的一部分。
在Ruby中,方法和变量存在于不同的名称空间中,因此可以存在具有相同名称的方法和变量(或常量)。这意味着,当使用时,需要有一些方法来区分它们。一般来说,这不是问题:消息有接收者,变量没有。消息有参数,变量没有。分配变量,消息不分配。
唯一的问题是当你没有接收器,没有参数和没有任务时。然后,Ruby无法区分无参数的无接收消息和变量之间的区别。因此,它必须构成一些任意规则,这些规则基本上是:
请注意,对于带参数的消息发送(即使参数列表为空),也没有歧义,这就是您的第三个示例有效的原因。
test()
:显然发送了一条消息,这里没有歧义test
:可能是消息发送或变量;解决规则说这是一个消息发送Test()
:显然发送了一条消息,这里没有歧义self.Test
:也显然是一条消息发送,这里没有歧义Test
:可能是消息发送或常量;决议规则说这是一个常数请注意,这些规则有点微妙,例如:
if false
foo = 'This will never get executed'
end
foo # still this will get interpreted as a variable
规则说明,模糊标记是否被解释为变量或消息发送是由解析器而不是解释器决定的。因此,因为解析器已经看到foo = whatever
,所以它将foo
标记为变量,即使代码永远不会执行,foo
将评估为nil
所有未初始化的变量在Ruby中。
TL; DR摘要:你是SOL。
像这样:
const_missing
除此之外显然不起作用,因为class DemoClass
def test; puts "output from test" end
def Test; puts "output from Test" end
def run
puts "Calling 'test'"
test()
puts "Calling 'test'"
test
puts "Calling 'Test()'"
Test()
puts "Calling 'Test'"
Test
end
def self.const_missing(const)
send const.downcase
end
end
demo = DemoClass.new
demo.run
上定义了const_missing
,因此,当DemoClass
运行时,const_missing
为self
,这意味着它应该在DemoClass
通过DemoClass.test
调用DemoClass#test
时调用{<1}}。
我不知道如何轻松解决这个问题。