require 'pry'
var = "variable"
class Gnar
def self.gar
@var = "lar!"
# binding.pry
# Pry.start(binding)
# Pry.start
end
end
Gnar.gar当我取消对binding.pry的评论时,我发现自己正处于self == Gnar的REPL中。当我取消评论Pry.start(binding)时,Pry从未启动过。当我取消对Pry.start的评论时,我发现自己正处于self == main的REPL中。
我不明白这种行为,我想真正掌握这个重要的Ruby调试工具的本质。我想集中讨论binding.pry和Pry.start(binding)的行为。
在一种情况下,我们在binding对象上调用binding方法,而在另一种情况下,我们用binding作为参数调用Pry类上的.start方法。
让我们从binding.pry开始。根据医生们,#pry的定义如下:
def pry(object=nil, hash={})
if object.nil? || Hash === object
Pry.start(self, object || {})
else
Pry.start(object, hash)
end
end基于该方法定义,当我们在没有参数的对象上调用#pry时,我们调用Pry.start(self, {}),其中self是binding上下文中的self。
那么,在Pry.start中发生了什么呢?文档中的定义是相当长的,但我注意到的是,self作为target of Pry.start传入,然后在这一行中使用:
options[:target] = Pry.binding_for(target || toplevel_binding) #line 152在此之前
# Enter the matrix
driver.start(options) #line 169考虑到所有这些,我的理解是,binding.pry通过driver.start(options)和options[:target] = Pry.binding_for(binding)生成REPL。如果Pry.start(binding) target == binding 在这两种情况下都没有表现出相同的行为(即没有启动REPL),为什么没有表现出相同的行为呢?我做了什么不正确的假设?,我有点理解,Pry.start会以self == main作为默认的target == toplevel_binding来启动REPL。
发布于 2019-09-27 04:53:42
从控制台中调用Pry.start(binding)应该与调用binding.pry具有类似的效果
rails c
Loading development environment (Rails 5.1.6.2)
[1] pry(main)> class Gnar
[1] pry(main)* def self.gar
[1] pry(main)* @var = "lar!"
[1] pry(main)* Pry.start(binding)
[1] pry(main)* end
[1] pry(main)* end
=> :gar
[2] pry(main)> Gnar.gar
From: /Users/redacted/.gem/gems/pry-0.12.2/lib/pry/pry_instance.rb @ line 388 Pry#evaluate_ruby:
383: def evaluate_ruby(code)
384: inject_sticky_locals!
385: exec_hook :before_eval, code, self
386:
387: result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
=> 388: set_last_result(result, code)
389: ensure
390: update_input_history(code)
391: exec_hook :after_eval, result, self
392: end
[1] pry(#<Pry>)> 绑定对象封装代码在特定位置的执行上下文。Binding#pry在绑定对象上启动一个撬REPL。
Pry.start只是启动了一个撬的REPL。如果您不传递它一个绑定,那么它只是一个没有任何执行上下文的Pry;如果传递给它的绑定的执行上下文是一个撬实例,控制台将通过从pry(main) (无上下文)更改为pry(#<Pry>)>来告诉您它是否具有上下文:
$ rails c
Loading development environment (Rails 5.1.6.2)
[1] pry(main)> Pry.start(binding)
From: /Users/redacted/.gem/gems/pry-0.12.2/lib/pry/pry_instance.rb @ line 388 Pry#evaluate_ruby:
383: def evaluate_ruby(code)
384: inject_sticky_locals!
385: exec_hook :before_eval, code, self
386:
387: result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
=> 388: set_last_result(result, code)
389: ensure
390: update_input_history(code)
391: exec_hook :after_eval, result, self
392: end
[1] pry(#<Pry>)> exit
=> nil
[2] pry(main)> binding.pry
From: /Users/redacted/.gem/gems/pry-0.12.2/lib/pry/pry_instance.rb @ line 388 Pry#evaluate_ruby:
383: def evaluate_ruby(code)
384: inject_sticky_locals!
385: exec_hook :before_eval, code, self
386:
387: result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
=> 388: set_last_result(result, code)
389: ensure
390: update_input_history(code)
391: exec_hook :after_eval, result, self
392: end
[1] pry(#<Pry>)> exit
=> nil
[3] pry(main)> exit类似地,从类方法中调用binding.pry会在该类的执行上下文(pry(ClassName))中打开一个撬REPL。从实例方法中调用binding.pry将在该实例(pry(#<ClassName>)的执行上下文中打开一个撬REPL。
rails c
Loading development environment (Rails 5.1.6.2)
[1] pry(main)> class A
[1] pry(main)* def self.b
[1] pry(main)* binding.pry
[1] pry(main)* end
[1] pry(main)*
[1] pry(main)* def c
[1] pry(main)* binding.pry
[1] pry(main)* end
[1] pry(main)* end
=> :c
[2] pry(main)> A.b
From: (pry) @ line 4 A.b:
2: def self.b
3: binding.pry
=> 4: end
[1] pry(A)> exit
=> nil
[3] pry(main)> A.new.c
From: (pry) @ line 8 A#c:
6: def c
7: binding.pry
=> 8: end
[1] pry(#<A>)> exit
=> nil希望这能有所帮助。
https://stackoverflow.com/questions/58125631
复制相似问题