1

请注意,这是对我的问题的跟进

我正在尝试解析以下 Tcl 代码:

foo bar {
  biz buzz
}

在 Tcl 中,foo是方法名,bar是参数,其余的是要处理的“块” eval

现在这是我目前对此的实现:

def self.foo(name, &block)
  puts "Foo --> #{name}"
  if block
    puts "block exists"
  else
    puts "block does not exist"
  end
end

def self.method_missing(meth, *args, &block)
  p meth
  p block
  meth.to_s &block
end

tcl = <<-TCL.gsub(/^\s+/, "").chop
  foo bar {
    biz buzz
  }
TCL

instance_eval(tcl)

输出以下内容:

:bar
#<Proc:0x9e39c80@(eval):1>
Foo --> bar
block does not exist

在此示例中,当块被传递给foo方法时,它不存在。然而method_missing它确实存在(至少它似乎存在)。这里发生了什么?

请注意,我知道 ruby​​ 括号的优先级并意识到这是有效的:

foo (bar) {
  biz buzz
}

但是,我想省略括号。那么这在 ruby​​ 中是否可行(没有词法分析)?

4

3 回答 3

1

这与method_missing. 将块与某些参数一起传递时,您根本不能省略括号。在您的情况下,Ruby 将尝试以bar块作为参数调用方法,并且所有结果都将foo作为单个参数传递给方法。

您可以通过简化方法调用自己尝试此操作(所有元编程只会掩盖您案例中的真正问题):

# make a method which would take anything
def a *args, &block
end

# try to call it both with argument and a block:
a 3 {
  4
}
#=>SyntaxError: (irb):16: syntax error, unexpected '{', expecting $end
#   from /usr/bin/irb:12:in `<main>'
于 2011-04-21T05:40:27.413 回答
1

你可以这样做(我标记了我改变的行):

def self.foo args                  # changed
  name, block = *args              # changed
  puts "Foo --> #{name}"
  if block
    puts "block exists"
  else
    puts "block does not exist"
  end
end

def self.method_missing(meth, *args, &block)
  p meth
  p block
  return meth.to_s, block          # changed
end

这样,块就会存在。

于 2011-04-22T01:21:59.607 回答
0

所以我找到的最好的解决方案是gsub在处理它之前只处理字符串。

tcl = <<-TCL.gsub(/^\s+/, "").chop.gsub('{', 'do').gsub('}', 'end')
  foo bar {
    biz buzz
  }
TCL
于 2011-04-21T12:31:10.607 回答