语法错误,意外||在instance_eval字符串中

时间:2016-11-05 00:59:27

标签: ruby

我想在instance_eval字符串中插入一个值。参数alias_name有时可以是nil或字符串。如果它是nil,那么我调用另一个返回字符串的方法,如下所示:

def create_document(klass, alias_name)
  klass.instance_eval <<-EOS
      def alias_name
        #{alias_name} || name
      end
  EOS
end

但实际上这给了我一个语法错误:

Uncaught exception: (eval):2: syntax error, unexpected ||
         || name
           ^

我正在仔细查看此代码,但我没有看到语法错误。如果#{alias_name}返回nil或string,为什么会导致错误?

毕竟这一切都有效:

> nil || 'something else'
 => "something else" 
> 'something' || 'something else'
 => "something" 

alias_name为零时,根本不会对其进行评估。它就像在instance_eval字符串中只是不存在一样,导致语法错误。但即使这样也行不通:

alias_name = alias_name || ""
klass.instance_eval <<-EOS
  def alias_name
    if #{alias_name}.present?
      #{alias_name}
    else
      demodulized_name
    end
  end
EOS

会出现此错误:

Uncaught exception: (eval):2: syntax error, unexpected '.'
        if .present?
            ^
你知道吗?它好像alias_name不存在。

1 个答案:

答案 0 :(得分:2)

使用字符串插值时,"s #{expr} s"相当于:

's ' + expr.to_s + ' s'

nil.to_s是一个空字符串,所以:

klass.instance_eval <<-EOS
  def alias_name
    #{alias_name} || name
  end
EOS

结束如:

klass.instance_eval %q{
  def alias_name
    || name
  end
}

alias_namenil或空字符串时:

def alias_name
  || name
end

在语法上不是正确的Ruby代码。

你正在向klass.instance_eval提供的heredoc不知道有任何特殊的“这是Ruby代码”上下文,它只是像任何其他字符串一样构建一个字符串并盲目地调用to_s关于#{}插值。

也许您想使用inspect代替to_s

klass.instance_eval <<-EOS
  def alias_name
    #{alias_name.inspect} || name
  end
EOS

这将为您提供类似以下的Ruby代码:

def alias_name
  nil || name
end

alias_namenil时:

def alias_name
  "pancakes" || name
end

alias_name是字符串'pancakes'时。

或许您希望在instance_eval之外进行测试,如果alias_name是另一种方法的名称:

if alias_name.present?
  klass.instance_eval <<-EOS
    def alias_name
      #{alias_name} || name
    end
  EOS
else
  klass.instance_eval <<-EOS
    def alias_name
      name
    end
  EOS
end