本文介绍了Ruby中用于带大写起始字母的方法的可选parens?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开始在我的.NET应用程序中为DSL使用IronRuby(但是在纯Ruby中测试时,行为似乎是一致的)-作为此过程的一部分,我定义了通过define_method从DSL调用的方法

I just started out using IronRuby (but the behaviour seems consistent when I tested it in plain Ruby) for a DSL in my .NET application - and as part of this I'm defining methods to be called from the DSL via define_method.

但是,在调用以大写字母开头的方法时,我遇到了有关可选括号的问题.

However, I've run into an issue regarding optional parens when calling methods starting with an uppercase letter.

给出以下程序:

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

在控制台中运行此代码(使用纯红宝石)会产生以下输出:

Running this code in a console (using plain ruby) yields the following output:

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中方法的通用命名约定为小写.但是,parren现在真的在杀死我的DSL语法.

I realize that the Ruby convention is that constants start with an uppercase letter and that the general naming convention for methods in Ruby is lowercase. But the parens are really killing my DSL syntax at the moment.

有什么办法解决这个问题?

Is there any way around this issue?

推荐答案

这只是Ruby模糊度解决方案的一部分.

This is just part of Ruby's ambiguity resolution.

在Ruby中,方法和变量位于不同的名称空间中,因此可以存在具有相同名称的方法和变量(或常量).这意味着使用时,需要某种区分它们的方法.通常,这不是问题:消息有接收者,变量没有.消息有参数,变量没有.变量被分配给消息,而不是消息.

In Ruby, methods and variables live in different namespaces, therefore there can be methods and variables (or constants) with the same name. This means that, when using them, there needs to be some way to distinguish them. In general, that's not a problem: messages have receivers, variables don't. Messages have arguments, variables don't. Variables are assigned to, messages aren't.

唯一的问题是,当您没有接收者,没有参数且没有赋值时.然后,Ruby无法分辨无参数的无接收器消息发送和变量之间的区别.因此,它必须组成一些任意规则,这些规则基本上是:

The only problem is when you have no receiver, no argument and no assignment. Then, Ruby cannot tell the difference between a receiverless message send without arguments and a variable. So, it has to make up some arbitrary rules, and those rules are basically:

  • 对于以小写字母开头的模棱两可的标记,最好将其解释为消息发送,除非您肯定知道它是变量(即 parser (不是(!)口译员)之前已经看过作业)
  • 对于以大写字母开头的含糊不清的令牌,更喜欢将其解释为常量
  • for an ambiguous token starting with a lowercase letter, prefer to interpret it as a message send, unless you positively know it is a variable (i.e. the parser (not(!) the interpreter) has seen an assignment before)
  • for an ambiguous token starting with an uppercase letter, prefer to interpret it as a constant

请注意,对于带有参数发送的消息(即使参数列表为空),也没有歧义,这就是第三个示例起作用的原因.

Note that for a message send with arguments (even if the argument list is empty), there is no ambiguity, which is why your third example works.

  • test():显然是一条消息发送,这里没有歧义
  • test:可能是消息发送或变量;解决规则说这是一条消息发送
  • Test():显然是一条消息发送,这里没有歧义
  • self.Test:显然是一条消息发送,在这里没有歧义
  • Test:可能是消息发送或常量;解析规则说这是一个常量
  • test(): obviously a message send, no ambiguity here
  • test: might be a message send or a variable; resolution rules say it is a message send
  • Test(): obviously a message send, no ambiguity here
  • self.Test: also obviously a message send, no ambiguity here
  • Test: might be a message send or a constant; resolution rules say it is a constant

请注意,这些规则有些微妙,例如:

Note that those rules are a little bit subtle, for example here:

if false
  foo = 'This will never get executed'
end

foo # still this will get interpreted as a variable

规则说,模棱两可的标记是被解释为变量还是消息发送是由 parser 而不是解释器确定的.因此,因为解析器已经看到foo = whatever,所以即使代码永远不会执行,并且foo会像Ruby中所有未初始化的变量一样计算为nil,它还是将foo标记为变量.

The rules say that whether an ambiguous token gets interpreted as a variable or a message send is determined by the parser and not the interpreter. So, because the parser has seen foo = whatever, it tags foo as a variable, even though the code will never get executed and foo will evaluate to nil as all uninitialized variables in Ruby do.

TL; DR摘要:您是SOL.

TL;DR summary: you're SOL.

您可以 可以执行的操作是覆盖const_missing以将其转换为消息发送.像这样:

What you could do is override const_missing to translate into a message send. Something like this:

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时,selfDemoClass,这意味着它将尝试调用DemoClass.test时应该通过demo.test调用DemoClass#test.

Except this obviously won't work, since const_missing is defined on DemoClass and thus, when const_missing is run, self is DemoClass which means that it tries to call DemoClass.test when it should be calling DemoClass#test via demo.test.

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

I don't know how to easily solve this.

这篇关于Ruby中用于带大写起始字母的方法的可选parens?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 07:24