rugby ruby irb

rugby - interactive ruby download



Cómo ejecutar IRB.start en el contexto de la clase actual (8)

A partir de Ruby 2.4.0, puedes hacer esto:

require ''irb'' binding.irb

Esto iniciará un REPL de IBR en el que tendrá el valor correcto para self y podrá acceder a todas las variables locales y variables de instancia que estén dentro del alcance. Escriba Ctrl + D o quit para reanudar su programa Ruby.

Acabo de pasar por PragProg Pruebas continuas con Ruby , donde hablan de invocar IRB en el contexto de la clase actual para inspeccionar el código manualmente.

Sin embargo, citan que si IRB.start en una clase, self está predefinido y se refiere al objeto en el que estábamos cuando se llamaba a start, lo que no es cierto en mi caso.

Incluso para ejemplos muy simples como

a = "hello" require ''irb'' ARGV.clear # otherwise all script parameters get passed to IRB IRB.start

Cuando intento acceder a la variable, obtengo lo obvio

NameError: undefined local variable or method `a'' for main:Object

Funciona solo cuando cambio a variable global

$a = "hello" require ''irb'' ARGV.clear # otherwise all script parameters get passed to IRB IRB.start

entonces puedo acceder

irb(main):001:0> $a => 1

¿Hay alguna forma de evitar esto para acceder a las variables locales y de instancia en la clase actual?


Aquí le mostramos cómo invocar IRB desde su script en el contexto de donde llama a IRB.start ..

require ''irb'' class C def my_method @var = ''hi'' $my_binding = binding IRB.start(__FILE__) end end C.new.my_method

La ejecución de su script invocará a IRB. Cuando llegas al prompt tienes una cosa más que hacer ...

% ./my_script.rb irb(main):001:0> @var.nil? => true irb(main):002:0> cb $my_binding => #<C:0x000000009da300 @var="hi"> irb(#<C:0x000000009da300>):003:0> @var.nil? => false irb(#<C:0x000000009da300>):004:0> @var => "hi"

¡Disfrutar!


Como ya descubrió, self no se refiere al objeto donde se inició IRB, sino a TOPLEVEL_BINDING , que parece ser una instancia de la clase Object .

Aún puede ejecutar una sesión de IRB con una clase u objeto específico como contexto, pero no es tan simple como simplemente iniciar IRB.

Si lo que te interesa es iniciar IRB con un contexto específico, entonces es muy fácil hacerlo cuando inicias IRB manualmente. Simplemente inicie IRB normalmente y luego llame al método irb , pasándole el objeto / clase que desee como contexto.

$ irb irb(main):002:0> require ''myclass'' => true irb(main):003:0> irb MyClass irb#1(MyClass):001:0> self => MyClass

También puede iniciar una sesión de IRB programáticamente y especificar el contexto, pero no es tan fácil como debería ser porque tiene que reproducir parte del código de inicio de IRB. Después de mucha experimentación y excavación en el código fuente de IRB, pude encontrar algo que funciona:

require ''irb'' IRB.setup nil IRB.conf[:MAIN_CONTEXT] = IRB::Irb.new.context require ''irb/ext/multi-irb'' IRB.irb nil, self


En lugar de global, podría usar variables de instancia, por ejemplo:

require ''irb'' @a = "hello" ARGV.clear IRB.start >> @a => "hello"


La gema ruby-debug-base agrega un método binding_n al módulo Kernel y esto le dará acceso al objeto de enlace que se puede usar en una evaluación para dar acceso a las variables de la pila de llamadas. Recuerde emitir Debugger.start para activar el seguimiento de la pila de llamadas.

Aquí hay un ejemplo que muestra su uso para ver lo que sucede dentro de irb (un programa de Ruby). Uno también podría poner el '' debugger '' y el debugger.start dentro de su propio código Ruby.

$ irb ruby-1.8.7-p302 > require ''rubygems'' => true ruby-1.8.7-p302 > require ''ruby-debug-base'' => true ruby-1.8.7-p302 > Debugger.start => true ruby-1.8.7-p302 > puts caller /tmp/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/irb/workspace.rb:52 :i n `irb_binding'' #` /tmp/.rvm/rubies/ruby-1.8.7-p302/lib/ruby/1.8/irb/workspace.rb:52 => nil ruby-1.8.7-p302 > eval "main", binding_n(2) => #<Object:0xb7762958 @prompt={:PROMPT_I=>"ruby-1.8.7-p302 > ", :PROMPT_N=>" ruby-1.8.7-p302 ?> ", :PROMPT_S=>"ruby-1.8.7-p302%l> ", :PROMPT_C=>"ruby-1.8.7-p302 > ", :AUTO_INDENT=>true, :RETURN=>" => %s /n"}> ruby-1.8.7-p302 >

Si está dispuesto a ejecutar una versión parcheada de Ruby para 1.9.2, visite http://gitnub.com/rocky/rb-threadframe para ver qué es un mejor acceso a la pila de llamadas. Rubinius proporciona esta capacidad incorporada a través de Rubinius :: VM.backtrace .


Mi solución para Ruby 2.2.3. Es muy similar a la de Bryant.

def to_s "Sample" end def interactive banana = "Hello" @banana = "There" require ''irb'' IRB.setup(nil) workspace = IRB::WorkSpace.new(binding) irb = IRB::Irb.new(workspace) IRB.conf[:MAIN_CONTEXT] = irb.context irb.eval_input end irb(Sample):001:0> puts banana Hello => nil irb(Sample):002:0> puts @banana There => nil irb(Sample):003:0>

Puedo acceder a variables locales y variables de instancia. El require ''irb'' por supuesto, podría estar en la parte superior del archivo. La configuración de banana y @banana es solo para demostrar que puedo acceder a ellos desde el indicador irb. El to_s es un método para obtener un aviso bastante pero hay otras opciones. Y no hay una razón real para hacer un método separado, pero tal como está, puedes colocarlo en cualquier lugar y debería funcionar.


Usar palanca

a = ''hello'' require ''pry'' binding.pry


Yo sugeriría probar esto en ripl , una alternativa irb. El ejemplo anterior funciona:

a = ''hello'' require ''ripl'' Ripl.start :binding => binding

Tenga en cuenta que las variables locales funcionan porque está pasando el enlace actual con la opción: binding.

Posiblemente podría hacer lo mismo en irb, pero como está poco documentado y no probado, sus posibilidades de hacerlo de manera limpia son escasas o nulas.