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

ForMethodsおよびProcsRuby 1.9 にはsource_locationというメソッドがあります。

このメソッドを含む 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]

source_locationクラスとモジュールについて、Ruby は組み込みサポートを提供していませんが、メソッドが指定されていない場合に特定のメソッドのファイルまたはクラスの最初のファイルを返すために構築される優れた Gist があります。

編集: 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_searchVim 内から を使用すると、探しているファイルが返されます。

于 2012-10-22T14:09:43.820 に答える
0

悪いニュース!Ruby 1.8.7でクラスを作成または定義したファイルを実行時に知る方法はないと思います。

プロジェクトにレールのような構造がある場合は、それを推測できます。

しかし、Ruby では、複数のファイルで同じクラスのメソッドを定義できます。クラスは実行時に定義することもできます (メタプログラミング)。

つまり、クラスが定義されている場所が複数ある可能性があります。また、探しているものが複数のファイルに分散している可能性があります。

Bar のすべての定義を検索して、それらがモジュール Foo 内にあるかどうかを確認するか、すべての Foo 定義を見つけて内部を確認することから始める必要があると思います。コードがごちゃごちゃしている場合、簡単な方法がわかりません。スパゲッティ フォーム ポイントに従って poi を指定する必要があります。優れたエディターと複数のファイル検索が役立つかもしれませんが、コード全体を読む必要があります。

編集:結局のところ、いくつかの良いニュース。Ruby 1.9 にはsource_location1.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 に答える