2010-11-15 55 views
25

我刚刚通过PragProg 使用Ruby进行连续测试,他们谈论在当前类的上下文中调用IRB以手动检查代码。如何在当前类的上下文中运行IRB.start

然而,他们报价,如果你在一个类中调用IRB.start自我是预定的,并指我们在开始时被称为这是不是在我的情况下,真正的对象。

即使是很简单的例子,像

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

当我尝试访问a变量,我得到了明显

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

当我改变a为全局变量

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

然后我可以访问它

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

是否有任何方法可以访问当前类中的本地变量和实例变量?

回答

15

我建议在ripl尝试这一点,IRB替代。上述示例的工作原理如下:

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

请注意,局部变量的工作原理是因为您使用:binding选项传递当前绑定。

你可能可以在irb中做同样的事情,但由于它没有很好的记录和未经测试,所以干净利落的可能性很小。

+0

不幸的是,这是JRuby下的一个禁区。 – 2011-03-10 08:14:23

+0

你应该打开一个问题:https://github.com/cldwalker/ripl/issues。 ripl已被验证在jruby上工作 – cldwalker 2011-03-10 21:26:25

+2

其次,建议避免IRB。撬是另一种选择。 – 2012-05-27 05:02:04

10

而不是全球可以使用实例变量,例如:

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

>> @a 
=> "hello" 
+0

使用实例变量会改变什么? – abcde123483 2012-10-09 14:13:51

+1

@ulvund好吧,与局部变量不同,它们在IRB.start之后仍然可见(即,用'a'代替这个代码中的@ a'不起作用),但与全局变量不同,它们不会污染全局名称空间主要对象的那些)。无论如何,其他答案已经提到了让本地人工作的方法,所以如果使用外部库或者做更多的工作不是问题,那么这是更好的选择。 (我宁愿撬自己。) – Arkku 2012-10-10 09:26:23

0

ruby-debug-base宝石增加了binding_n方法将内核模块,这将让您使用绑定,可以在EVAL用来给访问调用堆栈变量对象。记得发出Debugger.start来打开调用堆栈跟踪。

下面是一个例子,展示了它用于反思irb(一个Ruby程序)内部正在发生的事情。我们也可以在你自己的Ruby代码中加入require's和Debugger.start

$ 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 > 

如果你愿意运行Ruby的补丁版本为1.9.2看到http://gitnub.com/rocky/rb-threadframe什么,我觉得是调用堆栈更好的访问。 Rubinius提供此功能,通过内置Rubinius :: VM.backtrace

36

正如您已经发现的那样,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 
+5

恕我直言,回答这个问题的唯一答案。 – amoebe 2013-03-13 14:42:36

+0

Upvoted,为我工作,并回答原来的问题(而不是建议替代品),谢谢! – dolzenko 2014-02-25 12:46:04

+0

史诗般的答案。谢谢 - 完全适合我(红宝石1.9.3)第一次尝试。感谢你做这项工作,所以我不必这样做。 – 2014-08-27 18:11:02

6

以下是如何从你的脚本在调用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 
=> #<C:0x000000009da300 @var="hi"> 
irb(#<C:0x000000009da300>):003:0> @var.nil? 
=> false 
irb(#<C:0x000000009da300>):004:0> @var 
=> "hi" 

享受!

+2

Pry更适合这个:http://pry.github.com – horseyguy 2011-08-14 11:38:40

+5

可能是这样,但问题是,“如何在当前类的上下文中运行IRB.start”。我的回答是唯一一个实际上 – Ben 2012-09-08 21:44:04

+1

你不能访问局部变量,因此它不回答这个问题 – Nowaker 2013-11-10 15:37:19

9

使用Pry

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

我有一些Ripl问题(这是可以接受的解决方案)给了​​我另一个上下文,而不是我期望的。我也投票赞成Pry。 – abcde123483 2013-09-02 13:40:42

+0

我无法撬动工作,也许有些不兼容'/usr/local/share/gems/gems/term-ansicolor-1.2.2/lib/term/ansicolor.rb:188 :in'color':错误的参数数量(0表示1..2)(ArgumentError) \t from /usr/local/share/gems/gems/pry-0.10.0/lib/pry/output.rb:35 :在'decolorize_maybe'' – akostadinov 2014-06-13 09:06:39

2

我对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的设置只是为了证明我可以从irb提示符访问它们。 to_s是获得非常迅速的方法之一,但还有其他选择。并没有真正的理由制定一个单独的方法,但现在,你可以在任何地方使用它,它应该工作。

1

随着Ruby 2.4.0的,你可以这样做:

require 'irb' 
binding.irb 

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

+0

感谢,轻松和工作! – 2017-04-08 14:13:41

相关问题