53

我有一堆代码要看,现在是调试时间。因为我从来都不是 Ruby 调试器的粉丝,所以我正在寻找一种通过代码并阅读它的方法。

我想要做的是获取定义加载类的文件的位置:

Foo::Bar.create(:param) # how can I know file location in runtime?

对于更小、组织更好的项目,我只会搜索,class Bar但在这里这是不可能的,因为有很多名为 的类Bar,而且更糟糕的是,其中一些在同一个命名空间下。我知道,等待发生的麻烦。

注意:我使用的是 Ruby 1.8.7。

4

8 回答 8

50

对于Ruby 1.9,有一个名为Methodssource_location方法:Procs

返回包含此方法的 Ruby 源文件名和行号,如果此方法未在 Ruby(即本机)中定义,则返回 nil

因此,您可以请求该方法:

m = Foo::Bar.method(:create)

然后询问source_location该方法的:

m.source_location

这将返回一个包含文件名和行号的数组。例如对于ActiveRecord::Base#validates这个返回:

ActiveRecord::Base.method(:validates).source_location
# => ["/Users/laas/.rvm/gems/ruby-1.9.2-p0@arveaurik/gems/activemodel-3.2.2/lib/active_model/validations/validates.rb", 81]

对于类和模块,Ruby 不提供内置支持,但是有一个优秀的 Gist 可以在source_location没有指定方法的情况下返回给定方法的文件或类的第一个文件:

编辑:对于 Ruby 1.8.7,有一个可以向后移植的 gem source_location

于 2012-10-22T14:00:49.843 回答
31

仅供参考,在 Rails 的控制台或 Rails 应用程序的调试会话中,您可以找到定义该特定类的文件的磁盘位置。像

> show-source Job

这会给你

From: /home/john/projects/iisifix/app/models/job.rb @ line 13:
Class name: Job
Number of monkeypatches: 6. Use the `-a` option to display all available monkeypatches
Number of lines: 66

class Job < ApplicationRecord
  belongs_to :quote_request
  belongs_to :garage
于 2016-12-20T09:10:51.490 回答
3

这是一个简单的示例,展示了我如何在代码中跟踪位置。如果我需要知道模块中的位置:

class Foo
  attr_reader :initialize_loc
  def initialize
    @initialize_loc = [__FILE__, __LINE__]
    # do more stuff...
  end
end

如果我需要知道发生了什么事情:

require_relative 't1'

foo = Foo.new
# do lots of stuff until you want to know where something was initialized.
puts 'foo initialized at %s:%s' % foo.initialize_loc

当我运行代码时,我得到:

FooBar:Desktop foobar ruby t2.rb 
foo initilized at /Users/foobar/Desktop/t1.rb:4

如果我不想弄乱模块的源代码,并且希望调试器在我需要它时跳入,我会让调试器这样做:

require_relative 't1'
require 'ruby-debug'

debugger
foo = Foo.new
# do lots of stuff until you want to know where something was initilized.
puts 'foo initilized at %s:%s' % foo.initialize_loc

执行将停止,我将在紧随其后的行进入调试器debugger

[0, 9] in t2.rb
  1  require_relative 't1'
  2  require 'ruby-debug'
  3  
  4  debugger
=> 5  foo = Foo.new
  6  # do lots of stuff until you want to know where something was initilized.
  7  puts 'foo initilized at %s:%s' % foo.initialize_loc
  8  
t2.rb:5
foo = Foo.new
(rdb:1) 

一个简单的s将“步入”我进入下一行代码,这将在initialize块中Foo

(rdb:1) s
[-1, 8] in /Users/foobar/Desktop/t1.rb
  1  class Foo
  2    attr_reader :initialize_loc
  3    def initialize
=> 4      @initialize_loc = [__FILE__, __LINE__]
  5      # do more stuff...
  6    end
  7  end
  8  
/Users/foobar/Desktop/t1.rb:4
@initialize_loc = [__FILE__, __LINE__]
(rdb:1) 

除此之外,使用诸如grep -rn target_to_find path_to_search递归搜索目录并列出与目标匹配的行的文件名和行号之类的工具将大大有助于找到您要查找的内容。

或者,:vim /target_to_find/ path_to_search从 Vim 内部使用将返回您要查找的文件。

于 2012-10-22T14:09:43.820 回答
0

坏消息!我猜在运行时没有办法知道在 Ruby 1.8.7 中创建或定义了一个类的文件。

如果项目有一些像rails这样的结构,你就能猜到。

但在 Ruby 中,可以为同一个类定义多个文件的方法 类甚至可以在运行时定义(元编程)。

这意味着定义类的地方可能不止一个。您要查找的内容可以分布在多个文件中。

我想您将不得不搜索 Bar 的所有定义并查看它们是否在模块 Foo 中,或者首先查找所有 Foo 定义并检查其中的内容。如果代码是一团糟,我看不出一个简单的方法,你将不得不按照 spaguetti 形式指向 poi。一个好的编辑器和多个文件搜索可能会有所帮助,但您需要通读代码。

编辑:毕竟是一些好消息。在 Ruby 1.9 中有source_location并且看起来有 1.8.7 的反向移植。但是,如果定义是在运行时由 eval 进行的,那么我不确定它是否会起作用。我认为最简单的解决方案是像 Rubymine 这样的优秀编辑器,它通常可以告诉你代码是在哪里定义的。

于 2012-10-22T13:28:20.580 回答
0

坦率地说,鉴于您描述的代码组织,我认为 ruby​​-debug 是发现调用站点目的地的简单途径:只需设置断点并介入。如果您真的对调试器过敏,您可以检测调用站点与Kernel#set_trace_func.

$max_trace = 10
set_trace_func proc { |event, file, line, id, binding, classname|
  printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
  $max_trace -= 1 
  set_trace_func(nil) unless $max_trace > 0
}
于 2012-10-22T14:00:55.760 回答
0

更改对象的超类时出现此错误,修复方法是停止并启动 spring。

于 2018-05-01T19:47:07.947 回答
0

要找到一个函数.source_location

> ActiveModel.method(:as_json).source_location
["/usr/local/bundle/gems/activesupport-6.1.4.4/lib/active_support/core_ext/object/json.rb", 54]

要查找模块 Object.const_source_location

Object.const_source_location('ActiveModel')
["/usr/local/bundle/gems/activemodel-6.1.4.4/lib/active_model/gem_version.rb", 3]
于 2022-02-24T15:57:56.320 回答
-2
Klass.method(Klass.methods.first).source_location

使用source_location方法,我可以搜索类中定义的第一个方法。我想这不是万无一失的,因为元编程和其他黑客。

于 2019-02-22T13:54:13.527 回答