Protocols are powered by behaviours behind the scenes

This commit is contained in:
José Valim
2012-10-08 20:13:45 +02:00
parent 77677d5f90
commit 11f934b74a
2 changed files with 26 additions and 23 deletions
+5 -20
View File
@@ -59,11 +59,10 @@ defmodule Protocol do
Protocol.assert_protocol(protocol)
defmodule name do
def __impl__, do: unquote(protocol)
@behaviour unquote(protocol)
unquote(block)
def __impl__, do: unquote(protocol)
end
Protocol.assert_impl(name, protocol)
end
end
@@ -85,28 +84,14 @@ defmodule Protocol do
end
end
@doc """
Check if the given `impl` is a valid impl for `protocol`.
Raises an error if not.
"""
def assert_impl(impl, protocol) do
remaining = protocol.__protocol__(:functions) -- impl.__info__(:functions)
if remaining != [] do
pp = Enum.map_join remaining, ", ", fn {x,y} -> "#{x}/#{y}" end
raise ArgumentError,
message: "#{inspect impl} did not implement #{inspect protocol}, missing: #{pp}"
end
end
@doc """
Defines meta information about the protocol and internal callbacks.
"""
def meta(env, functions, fallback) do
contents = quote do
def __protocol__(:name), do: __MODULE__
def __protocol__(:functions), do: unquote(:lists.sort(functions))
def __protocol__(:name), do: __MODULE__
def __protocol__(:functions), do: unquote(:lists.sort(functions))
def behaviour_info(:callbacks), do: [{ :__impl__, 0 }|__protocol__(:functions)]
def __impl_for__(arg) do
case __raw_impl__(arg) do
+21 -3
View File
@@ -89,8 +89,9 @@ handle_file_warning(_, _File, { _Line, v3_kernel, bad_call }) -> [];
%% Rewrite
handle_file_warning(_, File, {Line,erl_lint,{undefined_behaviour_func,{Fun,Arity},Module}}) ->
Raw = "undefined callback function ~s/~B (behaviour ~s)",
Message = io_lib:format(Raw, [Fun,Arity,inspect(Module)]),
Kind = protocol_or_behaviour(Module),
Raw = "undefined ~s function ~s/~B (for ~s ~s)",
Message = io_lib:format(Raw, [Kind, Fun, Arity, Kind, inspect(Module)]),
io:format(file_format(Line, File, Message));
handle_file_warning(_, File, {Line,erl_lint,{undefined_behaviour,Module}}) ->
@@ -153,4 +154,21 @@ format_error([], Desc) ->
io_lib:format("~p", [Desc]);
format_error(Module, Desc) ->
Module:format_error(Desc).
Module:format_error(Desc).
protocol_or_behaviour(Module) ->
case is_protocol(Module) of
true -> protocol;
false -> behaviour
end.
is_protocol(Module) ->
case code:ensure_loaded(Module) of
{ ok, _ } ->
case erlang:function_exported(Module, '__protocol__', 1) of
true -> Module:'__protocol__'(name) == Module;
false -> false
end;
{ error, _ } ->
false
end.