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)
class_eval
and 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.