Ruby instance_eval和const_missing

时间:2017-07-31 21:14:49

标签: ruby dsl

我想在const_missing中致电instance_eval,但似乎遗漏了一些内容:

class A
  def self.const_missing(c)
    puts "Constant missing: #{c}"
  end

  def method_missing(m, *args, &block)
    puts "Method missing: #{m}"
  end       
end

# Works:
a = A.new
a.myMethod # OK: "Method missing: myMethod" 
a.MYCONST  # Sort of OK: "Method missing: MYCONST"

# Doesn't work
a.instance_eval {
  myMethod # OK: "Method missing: myMethod"
  MYCONST  # uninitialized constant MYCONST (NameError)
}

问:const_missinginstance_eval的电话在哪里?如何将其重定向到班级A? (Ruby 1.9.3,如果这很重要)

上下文:我正在编写一个小型DSL,其中大写字母用作州名。

DSL.evaluate {
  ENTER_STATE_A
  WAIT_FOR_INPUT
}

这些应该映射到方法,但我想保持大写。

2 个答案:

答案 0 :(得分:2)

您正在尝试访问ruby正在解释为方法的常量w / a.MYCONST。相反,您需要使用::来访问类本身而不是该类的实例:

a = A.new
a.instance_eval {
  self::class::MYCONST # => Constant missing: MYCONST
}

似乎在MYCONST内拨打instance_eval时,它被Object.const_missing抓住了。例如,如果您覆盖它,则会看到您之后的行为:

def Object.const_missing(c)
  puts "Constant missing: #{c}"
end 

a = A.new
a.instance_eval {
  MYCONST # => Constant missing: MYCONST
}

我不建议实际这样做。我只是为了说明发生了什么而展示了这一点。

答案 1 :(得分:1)

请注意,当你这样做时

a.MYCONST

你得到了Method missing: MYCONST(而不是Constant missing: MYCONST)。

您应该执行以下操作:

a.instance_eval {
  myMethod
  A::MYCONST
}