2017-03-27 103 views
21

除了散列作为最后一个参数之外,您可以在方法调用中放弃Ruby中的括号并获得一致的结果(您仍然需要关注优先级)。奇怪的语法错误与parens

然而,我遇到一个例子,其中这不是这种情况:

''.split(/ ./) # => [] 
''.split /./ # => [] 
''.split/./ # !> SyntaxError: unexpected '.' 

这是一个错误/消退(I与2.1.2测试它 - > 2.4.1 RUBYS)?

是否有其他通用的情况下,丢弃parens不能按预期工作?


Reported it,让我们来看看。


更新:票被否决含糊了一下。目前还不清楚它是否是一个错误,但它不会被修复,并建议在这些情况下使用%r{}。原因确实是开场斜线被解释为分裂。

+3

是的,解析器似乎被正则表达式中的空间所困惑... –

+0

@SergioTulentsev,如果它是一个错误,我会报告它。但是,在我的假设中,我是否正确:我应该期望非parens代码能够普遍工作,或者是否有一些特殊情况在一段时间内被认为是例外情况(除了哈希之外)? – ndn

+0

为什么你会在正则表达式中有空间?我认为这本身就是一个问题。 – thesecretmaster

回答

19

除了thesecretmaster's answer,让我们来看看Ruby的语法分析器中:

require 'ripper' 
require 'pp' 

pp Ripper.lex("''.split /./") 
# [[[1, 0], :on_tstring_beg,  "'" ], 
# [[1, 1], :on_tstring_end,  "'" ], 
# [[1, 2], :on_period,   "." ], 
# [[1, 3], :on_ident,   "split"], 
# [[1, 8], :on_sp,    " " ], 
# [[1, 9], :on_regexp_beg,  "/" ], 
# [[1, 10], :on_tstring_content, "." ], 
# [[1, 11], :on_regexp_end,  "/" ]] 

添加空间,使红宝石承认/字符的除法运算符:

pp Ripper.lex("''.split/./") 
# [[[1, 0], :on_tstring_beg, "'" ], 
# [[1, 1], :on_tstring_end, "'" ], 
# [[1, 2], :on_period,  "." ], 
# [[1, 3], :on_ident,  "split"], 
# [[1, 8], :on_sp,   " " ], 
# [[1, 9], :on_op,   "/" ], 
# [[1, 10], :on_sp,   " " ], 
# [[1, 11], :on_period,  "." ], 
# [[1, 12], :on_op,   "/" ]] 

是否有其他丢弃包袱的一般情况不能按预期工作?

人为的例子:

def foo(i = 1) 
    10 * i 
end 

foo(- 2) #=> -20 
foo - 2 #=> 8 

另一种:

b = 2 
def a(arg) 
    arg 
end 

a *b #=> 2 

a = 5 

a *b #=> 10 

第一a *b被解释为a(*b),而第二变a * b。添加圆括号强制Ruby调用该方法:

a(*b) #=> 2 
+0

太棒了,如果你不介意的话,我会在错误报告中加入这个。 – ndn

+0

与一元对二进制减去以及。我没有想过。 – ndn

+3

你可以在最后一个例子的末尾调用'a(* b)'来获得更好的WTF效果。 –

9

尽管这看起来像是一个问题,但它并不是一个非常重要的问题,因为\s在正则表达式中会捕获空间。例如:

''.split(/ ./) # => [] 
''.split /./ # => [] 
''.split/./ # !> SyntaxError: unexpected '.' 
''.split /\s./ # => [] 

或者,如果你想匹配只有一个空间,你只需要propperly逃避它:

''.split /\ ./ # => [] 

红宝石应该分析该参数相同的内部或外部的括号,所以我d提出了一个错误,但它并不是非常紧急,而红宝石的人可能会很高兴,只是离开它。

实际上,@Stefan在评论中提到它可能是解析器将它解读为devision,这是最可能的解释,所以它甚至不是一个错误。但它是那些有趣的小红宝石怪癖之一。

@Stefan还补充说,您可以使用%r{ .}语法创建明确的正则表达式。

+1

如果我愿意,我可以用'\ 8'来避开数字8,但是为什么?正则表达式中没有特殊含义的字符应该直接与该字符匹配。 – ndn

+0

可能是一个解析器问题。我会提交一个错误,但这不是一件非常紧急的事情。可能有一个涉及ruby解析空白的解释,但它应该被解析为与parens中的参数相同的参数。 – thesecretmaster

+1

'%r {。}'是另一个创建明确正则表达式的选项。 – Stefan

9

分区或正则表达式?

正如@ Stefan的answer所写,Ruby试图将它解析为一个部门。

但是没有parens,可能很难区分除法和正则表达式。

例如,如何红宝石解析:

a /b/i 

令人惊讶的是,作为一个部门或正则表达式,取决于上下文。

def a(object) 
    puts object.class 
end 
b = 4 
i = 3 

a /b/i 
# Regexp 

a = 24 
a /b/i 
# 2 

如果a正在一个方法之前定义为变量,脚本会引发NameError:

a = 24 
def a(object) 
    puts object.class 
end 
a(/b/i) 
#Regexp 
a /b/i 
# 5:in `<main>': undefined local variable or method `b' for main:Object (NameError) 

我想说的是,解析背后的模糊逻辑使一些错误或意外的结果不可避免的。

%:String delimiter or modulo?

下面是一个类似的例子,这次是%q。它是一个字符串分隔符还是modulo q

def a(x) 
    puts x 
end 

a(%q+t+) 
# t 
a %q+t+ 
# t 

a = 4 
def a(x) 
    puts x 
end 

a(%q+t+) 
# t 
a %q+t+ 
# syntax error, unexpected end-of-input 

这可能是我第一次看到SyntaxError取决于变量的前值。

&:Proc-> Block,按位与或设置交集?

a &b可以在至少3条不同的解释:

def a 
    yield 
end 

b = ->{ puts "BLOCK" } 

a &b 
# BLOCK 

a = 3 
b = 5 
a &b 
# 1 

a = [1,2,3] 
b = [3,4,5] 
a &b 
# [3] 

许多符号采用红宝石不止一种方法使用,所以有可能是模糊的语法的许多其他例子。

+1

非常棒的例子。它保留了问题的要点,同时表明它不是那么明显。我还希望解析器能够一致地选择其中一种解释。我不知道它可以理解那么多的背景。 – ndn

+1

我不得不在''''例子中的解析器上。 '()'强制方法调用。如果不强制,'a'必须是方法或局部变量。如果两者都定义,则局部变量优先。在某些情况下,它可能无法像某些人所期望的那样工作,但它是一致且易于遵循的。与其他示例的列表不同,这些示例显示解析器在99.99%的时间内很智能,在其余的0.01%中以不明显的方式失败。但是,在省略父亲的时候,它仍然是一个很好的例子。 – ndn

+0

@ndn:你的解释是有道理的。不过,当我的名字被一个局部变量覆盖的时候,我仍然能够调用这个方法。由于无论如何都不鼓励,我从未想过在这种情况下会发生什么。无论如何,你会发现哪些其他的例子令人惊讶?除OP中的原始内容外,我对任何地方都没有惊讶。 –