2010-11-15 16 views
25

He estado examinando PragProg Pruebas continuas con Ruby, donde se habla de invocar IRB en el contexto de la clase actual para inspeccionar el código manualmente.Cómo ejecutar IRB.start en el contexto de la clase actual

Sin embargo, se cita que si se invoca IRB.start en una clase, auto está predefinido, y se refiere al objeto que se encontraba al inicio fue llamado cual no es cierto en mi caso.

Incluso para ejemplo muy simple como

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

Cuando intento acceder a la variable a, tengo la obvia

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

Sólo funciona cuando cambio a a la variable global

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

entonces puedo acceder a él

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?

Respuesta

15

yo sugeriría tratando 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 pasa el enlace actual con la opción: binding.

Puede hacer lo mismo en irb, pero como está poco documentado y no probado, sus posibilidades de hacerlo limpiamente son escasas o nulas.

+0

Desafortunadamente, este es un no-go bajo JRuby. –

+0

Debe abrir un problema: https://github.com/cldwalker/ripl/issues. Se ha verificado que ripl trabaja en jruby – cldwalker

+2

Segundo, el consejo es evitar el IRB para esto. Pry es otra opción. –

10

En lugar de mundial podría utilizar variables de instancia, por ejemplo .:

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

>> @a 
=> "hello" 
+0

¿Qué cambiaría el uso de variables de instancia? – abcde123483

+1

@ulvund Bueno, a diferencia de las variables locales, permanecen visibles después de 'IRB.start' (es decir, reemplazar' @ a' en este código con 'a' no funcionaría), pero a diferencia de las variables globales, no contaminan el espacio de nombres global (solo el del objeto principal). En cualquier caso, otras respuestas ya mencionan maneras de lograr que los lugareños trabajen, así que si usar una biblioteca externa o hacer un poco más de trabajo no es un problema, entonces esas son mejores alternativas. (Preferiría Pry yo mismo.) – Arkku

0

El ruby-debug-base joya añade un método binding_n al núcleo módulo y esto le dará acceso objeto que se puede utilizar en una eval para dar acceso a la pila de llamadas variables de unión. Recuerde emitir Debugger.start para activar el seguimiento de la pila de llamadas.

Aquí hay un ejemplo que muestra su uso para introspectar qué está pasando dentro de irb (un programa de Ruby). Uno podría poner el requiriendo y Debugger.start dentro de su propio código de Ruby también.

$ 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 usted está dispuesto a ejecutar una versión parcheada de Rubí para ver 1.9.2 http://gitnub.com/rocky/rb-threadframe por lo que creo que es un mejor acceso a la pila de llamadas. Rubinius proporciona esta capacidad incorporada a través de Rubinius :: VM.backtrace.

36

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

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

Si te importa iniciar el IRB en un contexto específico, entonces es realmente fácil hacerlo cuando estás iniciando el 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 mediante programación y especificar el contexto, pero no es tan fácil como debería ser porque usted tiene que reproducir algunos de código de puesta en marcha del IRB. Después de mucha experimentación y escarbar en el código fuente del IRB, yo era capaz de llegar a 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 
+5

En mi humilde opinión, la única respuesta que responde esta pregunta. – amoebe

+0

Upvoted, funciona para mí y responde la pregunta original (en lugar de sugerir alternativas), ¡gracias! – dolzenko

+0

Respuesta épica. Gracias - totalmente funciona para mí (ruby 1.9.3) primer intento. Gracias por hacer ese trabajo, así que no tengo que hacerlo. –

6

Aquí está cómo invocar IRB de su script en el contexto de donde usted llama IRB.start ..

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

C.new.my_method 

Ejecutando el script invocará IRB. Cuando llegue al mensaje, tiene 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" 

¡Disfrútelo!

+2

Pry es mejor para esto: http://pry.github.com – horseyguy

+5

Eso puede ser. Pero la pregunta es, "Cómo ejecutar IRB.start en el contexto de la clase actual". Mi respuesta es la única que en realidad responde la pregunta – Ben

+1

No se puede acceder a las variables locales, por lo que no responde a la pregunta – Nowaker

9

Uso Pry:

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

Tengo algunos problemas con Ripl (que es la solución aceptada) que me da otro contexto de lo que esperaba. Así que en una inspección más cercana I Estoy votando por Pry también. – abcde123483

+0

No pude hacer palanca para trabajar, tal vez alguna incompatibilidad '/usr/local/share/gems/gems/term-ansicolor-1.2.2/lib/term/ansicolor.rb:188 : en 'color': número incorrecto de argumentos (0 para 1..2) (ArgumentError) \t de /usr/local/share/gems/gems/pry-0.10.0/lib/pry/output.rb:35 : en 'decolorize_maybe'' – akostadinov

2

Mi solución para Ruby 2.2.3. Es muy similar al

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 de irb. El to_s es un método para obtener un mensaje bastante rápido, pero hay otras opciones. Y no hay una razón real para hacer un método separado, pero tal como está, puedes colocar esto en cualquier lugar y debería funcionar.

1

A partir de Rubí 2.4.0, usted puede hacer esto:

require 'irb' 
binding.irb 

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

+0

gracias, fácil y en funcionamiento! –

Cuestiones relacionadas