Skip to content

Commit

Permalink
Merge pull request #45 from tverlaan/tv_better_try_wrapper
Browse files Browse the repository at this point in the history
Support `catch` as part of `do`-block
  • Loading branch information
Arjan Scherpenisse committed Feb 12, 2021
2 parents 557f1fa c628978 commit becb785
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 46 deletions.
31 changes: 20 additions & 11 deletions lib/decorator/decorate.ex
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 158,11 @@ defmodule Decorator.Decorate do
defp ensure_do([{:do, _} | _] = body), do: body
defp ensure_do(body), do: [do: body]

defp apply_decorator(context, mfa, do: body) do
[do: apply_decorator(context, mfa, body)]
end

defp apply_decorator(context, mfa, do: body, rescue: rescue_block) do
[
do: apply_decorator(context, mfa, body),
rescue: apply_decorator_to_rescue(context, mfa, rescue_block)
]
# a do-block will automatically be put in a `try do` by Elixir when one of the keywords
# `rescue`, `catch` or `after` is present. hence `try_clauses`.
defp apply_decorator(context, mfa, [{:do, body} | try_clauses]) do
[do: apply_decorator(context, mfa, body)]
apply_decorator_try_clauses(context, mfa, try_clauses)
end

defp apply_decorator(context, {module, fun, args}, body) do
Expand All @@ -181,8 177,21 @@ defmodule Decorator.Decorate do
raise ArgumentError, "Invalid decorator: #{inspect(decorator)}"
end

defp apply_decorator_to_rescue(context, mfa, rescue_block) do
rescue_block
defp apply_decorator_try_clauses(_, _, []), do: []

defp apply_decorator_try_clauses(context, mfa, [{:after, after_block} | try_clauses]) do
[after: apply_decorator(context, mfa, after_block)]
apply_decorator_try_clauses(context, mfa, try_clauses)
end

defp apply_decorator_try_clauses(context, mfa, [{try_clause, try_match_block} | try_clauses])
when try_clause in [:rescue, :catch] do
[{try_clause, apply_decorator_to_try_clause_block(context, mfa, try_match_block)}]
apply_decorator_try_clauses(context, mfa, try_clauses)
end

defp apply_decorator_to_try_clause_block(context, mfa, try_match_block) do
try_match_block
|> Enum.map(fn {:->, meta, [match, body]} ->
{:->, meta, [match, apply_decorator(context, mfa, body)]}
end)
Expand Down
35 changes: 0 additions & 35 deletions test/exception_test.exs

This file was deleted.

85 changes: 85 additions & 0 deletions test/try_wrapper_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 1,85 @@
# two arguments
defmodule DecoratorTest.Fixture.TryWrapperDecorator do
use Decorator.Define, test: 0

def test(body, _context) do
{:ok, body}
end
end

defmodule DecoratorTest.Fixture.TryWrapperTestModule do
use DecoratorTest.Fixture.TryWrapperDecorator

@decorate test()
def rescued(a) do
if a == :raise do
raise RuntimeError, "text"
end

a
rescue
_ in RuntimeError -> :error
end

@decorate test()
def catched(a) do
if a == :throw do
throw(a)
end

a
catch
_ -> :thrown
end

@decorate test()
def try_after(a) do
a
after
IO.write("after")
end

@decorate test()
def rescued_and_catched(a) do
case a do
:throw -> throw(a)
:raise -> raise RuntimeError, "text"
a -> a
end
rescue
_ in RuntimeError -> :error
catch
_ -> :thrown
end
end

defmodule DecoratorTest.TryWrapper do
use ExUnit.Case
import ExUnit.CaptureIO

alias DecoratorTest.Fixture.TryWrapperTestModule

test "Functions which have a 'rescue' clause" do
assert {:ok, 3} = TryWrapperTestModule.rescued(3)
assert {:ok, :error} = TryWrapperTestModule.rescued(:raise)
end

test "Functions which have a 'catch' clause" do
assert {:ok, 3} = TryWrapperTestModule.catched(3)
assert {:ok, :thrown} = TryWrapperTestModule.catched(:throw)
end

test "Functions which have an 'after' clause" do
assert capture_io(fn ->
send(self(), TryWrapperTestModule.try_after(3))
end) == "after"

assert_received {:ok, 3}
end

test "Functions which have a 'rescue' and a 'catch' clause" do
assert {:ok, 3} = TryWrapperTestModule.rescued_and_catched(3)
assert {:ok, :thrown} = TryWrapperTestModule.rescued_and_catched(:throw)
assert {:ok, :error} = TryWrapperTestModule.rescued_and_catched(:raise)
end
end

0 comments on commit becb785

Please sign in to comment.