3

短い:

RubyでこれをDRY化する方法はありますか:

def entry_point_one
  begin
    do_something
  rescue MySyntaxErrorOne, MySyntaxErrorTwo, MySyntaxErrorEtc => syn_err
    raise syn_err.exception(syn_err.message)
  end
end

def entry_point_two
  begin
    do_something_else
  rescue MySyntaxErrorOne, MySyntaxErrorTwo, MySyntaxErrorEtc => syn_err
    raise syn_err.exception(syn_err.message)
  end
end

より長いです:

私は通訳を構築しています。このインタープリターは、さまざまなエントリ ポイントを使用して呼び出すことができます。このインタープリターに「汚い」文字列をフィードすると、エラーが発生することが予想されます。ただし、do_something によって直接または間接的に呼び出されるすべてのメソッドのバック トレース全体によって、特にインタープリターが再帰を使用するため、スパムにならないようにするとよいでしょう。

上記のスニペットでわかるように、エラーを再発生させてバック トレースを削除する方法を既に知っています。私がしたいのは、上記の例の重複を削除することです。私がこれまでに最も近いのはこれです:

def entry_point_one
  re_raise_known_exceptions {do_something}
end

def entry_point_two
  re_raise_known_exceptions {do_something_else}
end

def re_raise_known_exceptions
  yield
rescue MySyntaxErrorOne, MySyntaxErrorTwo, MySyntaxErrorEtc => syn_err
    raise syn_err.exception(syn_err.message)
end

しかし、これにより re-raise-known-exceptions メソッドがバック トレースに表示されます。

編集:私が欲しいのは、Cの前処理マクロのようなものだと思います

4

5 に答える 5

3

配列でスプラットを使用できます。

IRB から直接:

COMMON_ERRORS = [ArgumentError, RuntimeError] # add your own 

def f
  yield
rescue *COMMON_ERRORS => err
  puts "Got an error of type #{err.class}"
end


f{ raise ArgumentError.new }
Got an error of type ArgumentError

f{ raise 'abc' }
Got an error of type RuntimeError
于 2008-09-26T02:22:01.023 に答える
2

もう少し考えてみたところ、次のようになりました。

interpreter_block {do_something}

def interpreter_block
  yield
rescue ExceptionOne, ExceptionTwo, ExceptionEtc => exc
  raise exc.exception(exc.message)
end

私が望んでいることはまだ静かではありませんが、少なくともバックトレースの余分なエントリは見栄えが良くなりました.

于 2008-09-25T22:16:17.447 に答える
1

これは少しハックですが、バックトレースのクリーンアップに関する限り、次のようなものがうまく機能します。

class Interpreter

  def method1
    error_catcher{ puts 1 / 0 }
  end

  def error_catcher
    yield
  rescue => err
    err.set_backtrace(err.backtrace - err.backtrace[1..2])
    raise err
  end

end

主なトリックはこの行err.set_backtrace(err.backtrace - err.backtrace[1..2])です。それがなければ、次のようになります (IRB から)。

ZeroDivisionError: divided by 0
  from (irb):43:in `/'
  from (irb):43:in `block in method1'
  from (irb):47:in `error_catcher'
  from (irb):43:in `method1'
  from (irb):54
  from /Users/peterwagenet/.ruby_versions/ruby-1.9.1-p129/bin/irb:12:in `<main>'

2 行目と 3 行目は不要です。したがって、それらを削除すると、次のようになります。

ZeroDivisionError: divided by 0
  from (irb):73:in `/'
  from (irb):73:in `method1'
  from (irb):84
  from /Users/peterwagenet/.ruby_versions/ruby-1.9.1-p129/bin/irb:12:in `<main>'
于 2009-10-04T23:22:14.967 に答える
1

少し悪いかもしれませんが、バックトレースから行を単純に削除できると思います;-)

COMMON_ERRORS = [ArgumentError, RuntimeError]

def interpreter_block
  yield
rescue *COMMON_ERRORS => err
  err.backtrace.delete_if{ |line| line=~/interpreter_block/ }
  raise err
end

それがそんなに良い考えかどうかはわかりませんが。後でインタプリタをデバッグするのはとても楽しいでしょう ;-)

補足: Treetopに興味があるかもしれません。

于 2008-09-26T11:56:55.310 に答える
0

例外に必要なすべての情報があり、バックトレースがまったく必要ない場合は、既存の例外を再発生させる代わりに、独自のエラーを定義して発生させることができます。これにより、新しいバックトレースが得られます。(もちろん、サンプルコードが不完全で、レスキューブロックで他の処理が行われている可能性があります。それ以外の場合は、エラーを自然に発生させるのが最善の策です。)

class MyError < StandardError; end

def interpreter_block
  yield
rescue ExceptionOne, ExceptionTwo, ExceptionEtc => exc
  raise MyError
end
于 2008-09-25T23:13:05.470 に答える