Ruby中的可选parens用于带大写起始字母的方法?

时间:2010-06-01 15:16:08

标签: ruby ironruby

我刚开始使用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语法。

有没有解决这个问题的方法?

1 个答案:

答案 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_missingself,这意味着它应该在DemoClass通过DemoClass.test调用DemoClass#test时调用{<1}}。

我不知道如何轻松解决这个问题。