Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Tidy up and rename __protocol_for__ to __impl_for__, related to #250

  • Loading branch information...
commit e53406d3cd60e15be79528d38be02dbaf63fbaa0 1 parent 7c26b21
@josevalim josevalim authored
Showing with 62 additions and 52 deletions.
  1. +60 −50 lib/protocol.ex
  2. +2 −2 test/elixir/protocol_test.exs
View
110 lib/protocol.ex
@@ -1,21 +1,23 @@
defmodule Protocol do
+ @moduledoc false
+
# We need to use Erlang.lists because Enum is not available yet
require Erlang.lists, as: L
- # Handle `defprotocol`. It will define a function for each
- # protocol plus two extra functions:
- #
- # * `__protocol__/1` - returns the protocol name when :name is given,
- # and key-value pair with the protocol functions
- # when :functions is given;
- #
- # * `__protocol_for__/1` - receives one argument and returns the protocol
- # module that the function should be dispatched to
- # according to the only/except rules. If no protocol
- # matches, returns nil;
- #
- # * `__protocol_for__!/1` - same as above but raises an error if protocol is not found
- #
+ @doc """
+ Handle `defprotocol`. It will define a function for each
+ protocol plus two extra functions:
+
+ * `__protocol__/1` - returns the protocol name when :name is given,
+ and key-value pair with the protocol functions
+ when :functions is given;
+
+ * `__impl_for__/1` - receives one argument and returns a module
+ that implements the protocol for the given
+ data type. If no implementation matches, returns nil;
+
+ * `__impl_for__!/1` - same as above but raises an error if an implementation is not found
+ """
def defprotocol(name, args, opts) do
funs = to_funs(args)
@@ -25,14 +27,16 @@ defmodule Protocol do
def __protocol__(:functions), do: unquote(funs)
{ conversions, fallback } = Protocol.conversions_for(unquote(opts))
Protocol.functions(__MODULE__, unquote(funs), fallback)
- Protocol.protocol_for(__MODULE__, conversions, fallback)
+ Protocol.impl_for(__MODULE__, conversions, fallback)
end
end
end
- # Implement the given protocol for the given module.
- # It also defines a `__impl__` function which
- # returns the protocol being implemented.
+ @doc """
+ Implement the given protocol for the given module.
+ It also defines a `__impl__` function which
+ returns the protocol being implemented.
+ """
def defimpl(protocol, [for: for], [do: block]) do
quote do
protocol = unquote(protocol)
@@ -50,9 +54,10 @@ defmodule Protocol do
end
end
- # Check if the given module is a protocol. Raises an error
- # if not loaded or not a protocol.
- @doc false
+ @doc """
+ Check if the given module is a protocol. Raises an error
+ if not loaded or not a protocol.
+ """
def assert_protocol(module) do
try do
module.__info__(:data)
@@ -67,9 +72,11 @@ defmodule Protocol do
end
end
- # Check if the given `impl` is a valid impl for `protocol`.
- # Raises an error if not.
- @doc false
+ @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)
@@ -77,36 +84,38 @@ defmodule Protocol do
raise ArgumentError, message: "#{impl} did not implement #{protocol}, missing: #{remaining}"
end
- # Callback entrypoint that defines the protocol functions.
- # It simply detects the protocol using __protocol_for__ and
- # then dispatches to it.
- @doc false
+ @doc """
+ Callback entrypoint that defines the protocol functions.
+ It simply detects the protocol using __impl_for__ and
+ then dispatches to it.
+ """
def functions(module, funs, fallback) do
contents = lc fun in L.reverse(funs), do: each_function(fun, fallback)
Module.eval_quoted module, contents, [], file: __FILE__, line: __LINE__
end
- # Implements the function that detects the protocol and returns
- # the module to dispatch to. Returns module.Record for records
- # which should be properly handled by the dispatching function.
- @doc false
- def protocol_for(module, conversions, fallback) do
- contents = lc kind in conversions, do: each_protocol_for(kind, conversions)
+ @doc """
+ Implements the function that detects the protocol and returns
+ the module to dispatch to. Returns module.Record for records
+ which should be properly handled by the dispatching function.
+ """
+ def impl_for(module, conversions, fallback) do
+ contents = lc kind in conversions, do: each_impl_for(kind, conversions)
# If we don't implement all protocols and any is not in the
# list, we need to add a final clause that returns nil.
if !L.member({ Any, :is_any }, conversions) && length(conversions) < 10 do
contents = contents ++ [quote do
- defp __raw_protocol__(_) do
+ defp __raw_impl__(_) do
nil
end
end]
end
- # Finally add __protocol_for__ and __protocol_for__!
+ # Finally add __impl_for__ and __impl_for__!
contents = contents ++ [quote do
- def __protocol_for__(arg) do
- case __raw_protocol__(arg) do
+ def __impl_for__(arg) do
+ case __raw_impl__(arg) do
match: __MODULE__.Record
target = Module.concat(__MODULE__, :erlang.element(1, arg))
if :erlang.function_exported(target, :__protocol__, 1) do
@@ -119,8 +128,8 @@ defmodule Protocol do
end
end
- def __protocol_for__!(arg) do
- if module = __protocol_for__(arg) do
+ def __impl_for__!(arg) do
+ if module = __impl_for__(arg) do
module
else:
raise Protocol.UndefinedError, protocol: __MODULE__, structure: arg
@@ -131,9 +140,10 @@ defmodule Protocol do
Module.eval_quoted module, contents, [], file: __FILE__, line: __LINE__
end
- # Returns the default conversions according to the given
- # only/except options.
- @doc false
+ @doc """
+ Returns the default conversions according to the given
+ only/except options.
+ """
def conversions_for(opts) do
kinds = all_types
@@ -183,9 +193,9 @@ defmodule Protocol do
# Specially handle tuples as they can also be record.
# If this is the case, module.Record will be returned.
- defp each_protocol_for({ _, :is_record }, conversions) do
+ defp each_impl_for({ _, :is_record }, conversions) do
quote do
- defp __raw_protocol__(arg) when is_tuple(arg) and is_atom(:erlang.element(1, arg)) do
+ defp __raw_impl__(arg) when is_tuple(arg) and is_atom(:erlang.element(1, arg)) do
first = :erlang.element(1, arg)
case unquote(is_builtin?(conversions)) do
match: true
@@ -203,18 +213,18 @@ defmodule Protocol do
end
# Special case any as we don't need to generate a guard.
- defp each_protocol_for({ _, :is_any }, _) do
+ defp each_impl_for({ _, :is_any }, _) do
quote do
- defp __raw_protocol__(_) do
+ defp __raw_impl__(_) do
__MODULE__.Any
end
end
end
# Generate all others protocols.
- defp each_protocol_for({ kind, fun }, _) do
+ defp each_impl_for({ kind, fun }, _) do
quote do
- defp __raw_protocol__(arg) when unquote(fun).(arg) do
+ defp __raw_impl__(arg) when unquote(fun).(arg) do
Module.concat __MODULE__, unquote(kind)
end
end
@@ -233,7 +243,7 @@ defmodule Protocol do
quote do
def unquote(name).(unquote_splicing(args)) do
args = [unquote_splicing(args)]
- case __raw_protocol__(xA) do
+ case __raw_impl__(xA) do
match: __MODULE__.Record
try do
target = Module.concat(__MODULE__, :erlang.element(1, xA))
View
4 test/elixir/protocol_test.exs
@@ -59,7 +59,7 @@ defmodule ProtocolTest do
end
test :protocol_with_only_with_undefined do
- assert_equal nil, ProtocolTest.WithOnly.__protocol_for__(:foo)
+ assert_equal nil, ProtocolTest.WithOnly.__impl_for__(:foo)
assert_raises Protocol.UndefinedError, "protocol ProtocolTest.WithOnly not implemented for :foo", fn ->
ProtocolTest.WithOnly.blank(:foo)
@@ -96,7 +96,7 @@ defmodule ProtocolTest do
# Assert that the given protocol is going to be dispatched.
defp assert_protocol_for(target, impl, thing) do
joined = Module.concat(target, impl)
- assert_equal joined, target.__protocol_for__ thing
+ assert_equal joined, target.__impl_for__ thing
end
# Dispatch `blank(thing)` to the given `target`
Please sign in to comment.
Something went wrong with that request. Please try again.