Pregunta

Para generar simulacros para omniauth, agregué este método a 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

Luego llamo al mismo archivo:

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

Pero entiendo:

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

Solución

class_evaly module_eval (que son equivalentes) se utilizan para evaluar e ejecutar inmediatamente las cadenas como código Ruby. Como tal, pueden usarse como una instalación de metaprogramación para crear dinámicamente métodos. Un ejemplo es

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

Creará dos métodos foo y bar que imprimen sus respectivos valores. Como puede ver, creo una cadena que contiene el código fuente real de la función y lo paso a class_eval.

Si bien este es un instrumento muy capaz de ejecutar código creado dinámicamente, debe usarse con gran cuidado. Si comete errores aquí, sucederán cosas malas ™. Por ejemplo, si usa valores proporcionados por el usuario al generar código, haga De Verdad Seguro que las variables contienen solo valores que espera. La función basada en evaluación generalmente debe usarse como el último recurso.

Una variante más limpia y generalmente preferida es usar define_method al igual que:

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

(Tenga en cuenta que la resonancia magnética es un poco más rápido con la variante eval. Pero eso no importa la mayor parte del tiempo en comparación con la seguridad y la claridad adicionales).

Ahora en su código dado, escribe efectivamente el código en una cadena que se puede ejecutar directamente. Usando class_eval Aquí conduce a la cadena que se ejecuta en el contexto del objeto más superior (Kernel en este caso). Como este es un objeto especial singleton que no puede ser instanciado (similar a nulo, verdadero y falso), obtienes este error.

Sin embargo, a medida que crea un código ejecutable directamente, no necesita usar class_eval (o cualquier forma de eval) en absoluto. Simplemente ejecute su código en un bucle tal como está. Y siempre recuerde: las variantes de metaprogramación (de las cuales los métodos EVAL se encuentran entre los más malos) solo deben usarse como el último recurso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top