【问题标题】:Ruby/Rails: class_eval doesn't want to evaluate this codeRuby/Rails:class_eval 不想评估此代码
【发布时间】:2012-02-10 09:09:13
【问题描述】:

为了为 Omniauth 生成模拟,我将此方法添加到 config/environments/development.rb

  def provides_mocks_for(*providers)
    providers.each do |provider|
      class_eval %Q{
        OmniAuth.config.add_mock(provider, {
          :uid => '123456',
          :provider => provider,
          :nickname => 'nickname',
          :info => {
            'email' => "#{provider}@webs.com",
            'name' => 'full_name_' + provider
          }
        })
      }
    end
  end

然后我在同一个文件中调用:

provides_mocks_for :facebook, :twitter, :github, :meetup

但我明白了:

3.1.3/lib/active_support/core_ext/kernel/singleton_class.rb:11:in `class_eval': can't create instance of singleton class (TypeError)

【问题讨论】:

  • 我不是 ruby​​ 元编程方面的专家,但也许你想要instance_eval
  • 你为什么要使用*_eval?只需在没有 eval 的情况下调用您的方法。您当前的代码甚至看起来像这样。
  • @Sergio 我得到instance_eval: can't convert Symbol into String (TypeError)
  • @HolgerJust 你摇滚!您可以将此添加为答案以便我接受吗?

标签: ruby-on-rails ruby instance-eval class-eval


【解决方案1】:

class_evalmodule_eval(它们是等价的)用于评估并立即将字符串作为 Ruby 代码执行。因此,它们可以用作元编程工具来动态创建方法。一个例子是

class Foo
  %w[foo bar].each do |name|
    self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
      def #{name}
        puts '#{name}'
      end
    RUBY
  end
end

它将创建两个方法foobar 打印它们各自的值。如您所见,我创建了一个包含函数实际源代码的字符串,并将其传递给class_eval

虽然这是一种执行动态创建代码的非常强大的工具,但必须非常小心地使用它。如果您在此处犯错,将会发生坏事™。例如。如果您在生成代码时使用用户提供的值,请真正确保变量只包含您期望的值。基于 eval 的函数通常应作为最后的手段。

更简洁且通常首选的变体是使用define_method,如下所示:

class Foo
  %w[foo bar].each do |name|
    define_method name do
      puts name
    end
  end
end

(请注意,使用 eval 变体,MRI 的速度要快一点。但与增加的安全性和清晰度相比,这在大多数情况下并不重要。)

现在,在您给定的代码中,您可以有效地将代码写入可以直接运行的字符串。在此处使用class_eval 会导致字符串在最顶层对象的上下文中执行(在本例中为Kernel)。由于这是一个无法实例化的特殊单例对象(类似于 nil、true 和 false),因此会出现此错误。

但是,当您创建直接可执行代码时,您根本不需要使用class_eval(或任何形式的 eval)。只需按原样在循环中运行您的代码。并且永远记住:元编程变体(其中 eval 方法是最糟糕的方法之一)只能作为最后的手段使用。

【讨论】:

    猜你喜欢
    • 2015-03-11
    • 2013-01-13
    • 2018-12-11
    • 1970-01-01
    • 1970-01-01
    • 2018-11-05
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多