如何在当前类的上下文中运行IRB.start

我一直在使用Ruby进行PragProg Continuous Testing ,在那里他们讨论在当前类的上下文中调用IRB以手动检查代码。

但是,他们引用了如果你在类中调用IRB.startself是预定义的,并引用我们在调用start时所处的对象,这在我的情况下是不正确的。

即使是非常简单的例子

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

当我尝试访问变量时,我明白了

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

它仅在我更改为全局变量时才有效

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

然后我可以访问它

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

有没有办法解决当前类中的本地和实例变量?

我建议用ripl来尝试这个,这是一种替代品。 以上示例有效:

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

请注意,局部变量有效,因为您使用:binding选项传递当前绑定。

你可能会在irb中做同样的事情,但由于它记录不完整且未经测试,你干净利落的机会很少。

正如您已经发现的那样, self不会引用启动IRB的对象,而是引用TOPLEVEL_BINDING ,它似乎是Object类本身的一个实例。

您仍然可以使用特定的类或对象作为上下文运行IRB会话,但它并不像启动IRB那么简单。

如果您关心的是使用特定的上下文启动IRB,那么当您手动启动IRB时,这很容易。 只需正常启动IRB,然后调用irb方法,将您想要的对象/类作为上下文传递给它。

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

您也可以以编程方式启动IRB会话并指定上下文,但它并不像应该那么容易,因为您必须重现一些IRB的启动代码。 在IRB源代码中进行了大量的实验和挖掘之后,我能够提出一些有效的方法:

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

您可以使用实例变量代替全局变量,例如:

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

使用Pry :

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

以下是在调用IRB.start的上下文中从脚本调用IRB的方法。

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

执行脚本将调用IRB。 当你到达提示时,你还有一件事要做……

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

请享用!

我的Ruby 2.2.3解决方案。 这与布莱恩特非常相似

 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> 

我可以访问局部变量和实例变量。 require 'irb'当然可以位于文件的顶部。 banana@banana的设置只是为了certificate我可以从irb提示符访问它们。 to_s是一种获得漂亮提示的方法,但还有其他选择。 并没有真正的理由来制作一个单独的方法,但就目前而言,你可以将它放在任何地方,它应该工作。

从Ruby 2.4.0开始,您可以这样做:

 require 'irb' binding.irb 

这将启动一个IBR REPL,您将获得正确的self值,并且您将能够访问范围内的所有局部变量和实例变量。 键入Ctrl + D或quit以恢复Ruby程序。

ruby-debug-base gem将一个binding_n方法添加到内核模块,这将为您提供访问绑定对象,该对象可以在eval中用于访问调用堆栈变量。 请记住发出Debugger.start以打开调用堆栈跟踪。

这是一个示例,显示了它用于内省irb (Ruby程序)内部的内容。 可以将requireDebugger.start放在你自己的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 :in `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) => #"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 > 

如果您愿意为1.9.2运行Ruby的修补版本,请参阅http://gitnub.com/rocky/rb-threadframe ,我认为可以更好地访问调用堆栈。 Rubinius通过Rubinius :: VM.backtrace提供此function。