Project

General

Profile

Feature #14111

ArgumentErrorが発生した時メソッドのプロトタイプをメッセージに含む

Added by esjee (SJ Stoker) about 2 years ago. Updated 6 months ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:83790]

Description

(日本人じゃないですが、日本語を勉強してますから、日本語でレポートしてみました
日本語で会話することはまだ馴れてないから、読みつらいや見苦しいところもあると思います
そういうを指摘してくれれば幸いです)

Abstract

ArgumentErrorが発生したときのメッセージをより有意義にするため、コールしたメソッドのプロトタイプを表示することを提案したいと思います

Background

今ではArgumentErrorが発生するとこんな感じです

[1] pry(main)> cat ./spec/kerk_class.rb
class Kerk
  def foo1(a)
  end
end
[2] pry(main)> require './spec/kerk_class.rb'
=> true
[3] pry(main)> Kerk.new.foo1
ArgumentError: wrong number of arguments (0 for 1)
from /home/esjee/src/printprototype/spec/kerk_class.rb:2:in `foo1'

簡単なメソッドやよく使うメソッドではこれでも問題ありません
しかし、他の人のコードとか、あまり使わないメソッドだとこのメソッドのソースを読まないと分からないこともある
Rubyのメソッドだとマニュアルを参照するしかないかもしれない

Proposal

ArgumentErrorのメッセージにコールしたメソッドのプロトタイプを含む
例えば

[4] pry(main)> Kerk.new.foo1
ArgumentError: wrong number of arguments (0 for 1)
Method prototype:
    def foo1(a)
from /home/esjee/src/printprototype/spec/kerk_class.rb:2:in `foo1'

Implementation

https://github.com/esjee/PrintPrototype

とくにこのファイル
https://github.com/esjee/PrintPrototype/blob/master/lib/printprototype/core_ext/argument_error.rb

Evaluation

ですけど、この実装には複数の問題があります

  • 複数のラインで書かれたメソッドのプロトタイプはどうやって見つければ?
  • 全ファイルを読み込んでるため、巨大なファイルだとパフォーマンスに問題があるかもしれない
  • Ruby自身のメソッドではrbファイルが見つからないため、表示できない
  • sentry-ravenに頼ってはいけないでしょう

Discussion

これまで読んでいただいて、ありがとうございました
私から二つの質問があります

  • これはよいfeatureだと思いますか?
  • 上で挙げられた複数な問題をどうやって乗り越えられるでしょうか?

Summary

ArgumentErrorが発生した時にもっと有意義なメッセージを表示したいと思います
私はこれをgemにしようと思いましたが、満足のできる実装にはできませんでした
小さくても、これはRubyを改良するfeatueだと信じてるです
皆さんの意見と助けを求め、これを書きました


Files


Related issues

Related to Ruby master - Feature #14145: Proposal: Better Method#inspectOpenActions

History

#1

Updated by esjee (SJ Stoker) about 2 years ago

  • Description updated (diff)

Updated by nobu (Nobuyoshi Nakada) about 2 years ago

esjee (SJ Stoker) wrote:

Evaluation

  • 複数のラインで書かれたメソッドのプロトタイプはどうやって見つければ?
  • 全ファイルを読み込んでるため、巨大なファイルだとパフォーマンスに問題があるかもしれない
  • sentry-ravenに頼ってはいけないでしょう

エラーの起きたレシーバやメソッド名をArgumentErrorから得られるように拡張して、Method#parametersで引数の情報を取り出すようにするのがいいかもしれません。

  • Ruby自身のメソッドではrbファイルが見つからないため、表示できない

Cで実装されたメソッドの引数についての情報は、今のところ数(arity)しか保存されていません。
RDocを調べるなどしないとなりません。

Discussion

  • これはよいfeatureだと思いますか?

よいと思います。

Updated by esjee (SJ Stoker) about 2 years ago

nobu (Nobuyoshi Nakada) wrote:

...

返事してくれてありがとうございました。
数時間RubyのCをいじったらなんとか進みました。

必要なレシーバとメソッド名をArgumentErrorをinstance_variableとして加えてみました。パッチを添付しました。
GitHubにもプッシュしましたから、これで同じパッチが見えるはず: https://github.com/ruby/ruby/compare/trunk...esjee:print_prototype?expand=1

RubyじゃなくCで自装されてるメソッドは残念ながらまだです。
そういうメソッドは全部変えていかないと駄目みたいです。
まだこの方法が望ましいかどかも分からないいまではそれはやりすぎかと。

添付したパッチはどう思いますか?多分ですけど、改善できるところもあるとおもいます。

Updated by nobu (Nobuyoshi Nakada) over 1 year ago

いくつか問題があるようです。

  • define_method で定義されたメソッドで ArgumentError が起きるとSEGV
  • label はメソッド名とは同じとは限らない
  • 特異メソッドを持つオブジェクトをインスタンス変数にセットすると Marshal.dump できない

また、 ArgumentError#to_s は別ライブラリ(gem)で提供するということでしょうか。
「重箱の隅をつつく」ようですが、エラー発生から表示までの間にメソッドが再定義されることもないとは言えません。

とりあえず ArgumentError#receiverArgumentError#method_name を定義するパッチです。
https://github.com/nobu/ruby/tree/feature/14111-ArgumentError-attributes

Updated by esjee (SJ Stoker) over 1 year ago

返事ありがとうございます。https://github.com/nobu/ruby/tree/feature/14111-ArgumentError-attributesのパッチで大体の問題は解決されるようです。

今まだ苦戦してるところはこういうメソッド:

def foo(a, b = 3); end

を理想の

Method prototype:
    def foo1(a, b = 3)

にすることです。

nobuさんが前に挙がったMethod#parametersを使うとデフォルト値の方は含まれてません。
デフォルト値がもうすこし複雑だったらこれを表示する方法は難しいのではないかと思います。

例えば、こういうメソッドがあったら:

def foo(a, b = (->() { Time.now.to_i }).call)

def bar(a, b = (->() { $count ||= 0; $count += 1}).call)

bのデフォル値を表示することは難儀になると思います。

nobuさんのパッチを使ったら、こういうメッセージを発生することは出来るようになります:

$ cat kerk.rb
class Foo
  def bar(a, b, c = 3, *all_the_args, d:, e: 7)
  end
end

Foo.new.bar

$ ./ruby kerk.rb
Traceback (most recent call last):
    1: from kerk.rb:6:in `<main>'
/home/esjee/src/ruby/kerk.rb:2:in `bar': wrong number of arguments (given 0, expected 2+; required keyword: d) (ArgumentError)

Method parameters:
    a (required)
    b (required)
    c (optional)
    all_the_args (rest)
    d (required keyword)
    e (optional keyword)

できればデフォル値も含みたいのですが、今のところそれを可能するいいアイデアはありません。

nobuさんのパッチをrubyに入れることでgemでこういうメッセージを発生することが可能になるので、まずはそれで進みたいと思います。
ちなみに、興味があれば、添付したrbファイルはnobuさんのパッチを使って、上のメッセージを作られるパッチです。

#7

Updated by shyouhei (Shyouhei Urabe) about 1 year ago

Updated by matz (Yukihiro Matsumoto) 6 months ago

Currently, some methods (especially C defined methods) lack method parameter information to provide this kind of description.
We are working on improving this region, so I put this proposal pending for the time being.

Matz.

Also available in: Atom PDF