1

To generate mocks for Omniauth, I Added this method to 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

then I call in the same file:

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

But I get:

3.1.3/lib/active_support/core_ext/kernel/singleton_class.rb:11:in `class_eval': can't create instance of singleton class (TypeError)
4
  • I'm not an expert in ruby metaprogramming, but maybe you want instance_eval? Commented Jan 14, 2012 at 14:41
  • 3
    Why do you use *_eval at all? Just call your method without the eval. Your current code even looks like this. Commented Jan 14, 2012 at 14:48
  • @Sergio I get instance_eval: can't convert Symbol into String (TypeError) Commented Jan 14, 2012 at 14:48
  • @HolgerJust You rock ! Can you add this as an answer so that I accept it? Commented Jan 14, 2012 at 14:53

1 Answer 1

2

class_evaland module_eval (which are equivalent) are used to evaluate and immediately execute strings as Ruby code. As such they can be used as a meta-programming facility to dynamically create methods. An example is

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

It will create two methods foo and bar which print their respective values. As you can see, I create a string containing the actual source code of the function and pass it into class_eval.

While this is a very capable instrument of executing dynamically created code, it must be used with great care. If you make errors here, BAD THINGS WILL HAPPEN™. E.g. if you use user-supplied values when generating code, make really sure the variables contain only values you expect. Eval-based function should generally be used as the last resort.

A cleaner and generally preferred variant is to use define_method like so:

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

(Note that MRI is a wee bit faster with the eval variant. But that doesn't matter most of the time when compared to the added safety and clarity.)

Now in your given code, you effectively write code into a string that can be run directly. Using class_eval here leads to the string being executed in the context of the top-most object (Kernel in this case). As this is a special singleton object which can't be instanciated (similar to nil, true and false), you get this error.

However, as you create directly executable code, you don't need to use class_eval (or any form of eval) at all. Just run your code in a loop as is. And always remember: meta-programming variants (of which the eval methods are among the most bad-ass) should only be used as the last resort.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.