СУХОЙ способ повторного создания одного и того же набора исключений в нескольких местах

короткая:

Есть ли в Ruby способ СУХОЙ:

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

Но это приводит к тому, что метод повторного повышения известных исключений отображается в обратной трассировке.

изменить: я думаю, что я хочу, было бы что-то вроде макроса предварительной обработки C

Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
3
0
2 013
5

Ответы 5

подумав еще немного, я пришел к такому выводу:

interpreter_block {do_something}

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

Хотя это все еще не тихо, то, что я хотел бы иметь, по крайней мере, теперь дополнительная запись в обратной трассировке стала несколько лучше.

Если у вас есть вся необходимая информация в исключениях, и вам вообще не нужна обратная трассировка, вы можете просто определить свою собственную ошибку и вызвать ее, вместо того, чтобы повторно вызывать существующее исключение. Это даст ему новую трассировку. (Конечно, предположительно, ваш пример кода неполный, и в блоке восстановления происходит другая обработка - в противном случае лучше всего просто позволить ошибке всплыть естественным образом.)

class MyError < StandardError; end

def interpreter_block
  yield
rescue ExceptionOne, ExceptionTwo, ExceptionEtc => exc
  raise MyError
end

Мне все еще нужна обратная трассировка, но я не хочу, чтобы отображались вложенные методы 31.4 из интерпретатора. Исключения, которые я хочу перехватить, - это исключения, которые возникают из-за ошибок в загружаемой строке. Поэтому обратная трассировка внутри интерпретатора не так важна, как само исключение.

Patrick Huizinga 26.09.2008 15:53

Вы можете просто использовать значок на массиве.

Прямо из 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

Хотя это не то, что я хочу, спасибо, что показали эту пластинку.

Patrick Huizinga 26.09.2008 16:03

О, я понимаю, к чему ты сейчас, извини

Orion Edwards 27.09.2008 08:10

Это может быть немного неприятно, но я думаю, что вы можете просто удалить строку из трассировки ;-)

COMMON_ERRORS = [ArgumentError, RuntimeError]

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

Я не уверен, что это такая хорошая идея. После этого вы получите массу удовольствия от отладки вашего интерпретатора ;-)

Примечание: Верхушка дерева может вас заинтересовать.

Это не сработает, потому что вы поднимаете внутри интерпретатора_block после, пытаясь удалить эту часть обратной трассировки.

Patrick Huizinga 26.09.2008 16:08

Кстати, меня не волнует ничего злого, потому что исключения должны сообщать об ошибках в интерпретируемой строке, а не о самом интерпретаторе.

Patrick Huizinga 26.09.2008 16:29

Это хакерский прием, но что касается очистки трассировки, что-то вроде этого отлично работает:

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>'

Чего мы не хотим, так это второй и третьей строк. Итак, мы их удаляем, и в итоге получаем:

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>'

Другие вопросы по теме