1defmodule Behaviour do 2 @moduledoc """ 3 Mechanism for handling behaviours. 4 5 This module is deprecated. Instead of `defcallback/1` and 6 `defmacrocallback/1`, the `@callback` and `@macrocallback` 7 module attributes can be used respectively. See the 8 documentation for `Module` for more information on these 9 attributes. 10 11 Instead of `MyModule.__behaviour__(:callbacks)`, 12 `MyModule.behaviour_info(:callbacks)` can be used. 13 """ 14 15 @moduledoc deprecated: "Use @callback and @macrocallback attributes instead" 16 17 @doc """ 18 Defines a function callback according to the given type specification. 19 """ 20 @deprecated "Use the @callback module attribute instead" 21 defmacro defcallback(spec) do 22 do_defcallback(:def, split_spec(spec, quote(do: term))) 23 end 24 25 @doc """ 26 Defines a macro callback according to the given type specification. 27 """ 28 @deprecated "Use the @macrocallback module attribute instead" 29 defmacro defmacrocallback(spec) do 30 do_defcallback(:defmacro, split_spec(spec, quote(do: Macro.t()))) 31 end 32 33 defp split_spec({:when, _, [{:"::", _, [spec, return]}, guard]}, _default) do 34 {spec, return, guard} 35 end 36 37 defp split_spec({:when, _, [spec, guard]}, default) do 38 {spec, default, guard} 39 end 40 41 defp split_spec({:"::", _, [spec, return]}, _default) do 42 {spec, return, []} 43 end 44 45 defp split_spec(spec, default) do 46 {spec, default, []} 47 end 48 49 defp do_defcallback(kind, {spec, return, guards}) do 50 case Macro.decompose_call(spec) do 51 {name, args} -> 52 do_callback(kind, name, args, return, guards) 53 54 _ -> 55 raise ArgumentError, "invalid syntax in #{kind}callback #{Macro.to_string(spec)}" 56 end 57 end 58 59 defp do_callback(kind, name, args, return, guards) do 60 fun = fn 61 {:"::", _, [left, right]} -> 62 ensure_not_default(left) 63 ensure_not_default(right) 64 left 65 66 other -> 67 ensure_not_default(other) 68 other 69 end 70 71 :lists.foreach(fun, args) 72 73 spec = 74 quote do 75 unquote(name)(unquote_splicing(args)) :: unquote(return) when unquote(guards) 76 end 77 78 case kind do 79 :def -> quote(do: @callback(unquote(spec))) 80 :defmacro -> quote(do: @macrocallback(unquote(spec))) 81 end 82 end 83 84 defp ensure_not_default({:\\, _, [_, _]}) do 85 raise ArgumentError, "default arguments \\\\ not supported in defcallback/defmacrocallback" 86 end 87 88 defp ensure_not_default(_), do: :ok 89 90 @doc false 91 defmacro __using__(_) do 92 quote do 93 warning = 94 "the Behaviour module is deprecated. Instead of using this module, " <> 95 "use the @callback and @macrocallback module attributes. See the " <> 96 "documentation for Module for more information on these attributes" 97 98 IO.warn(warning) 99 100 @doc false 101 def __behaviour__(:callbacks) do 102 __MODULE__.behaviour_info(:callbacks) 103 end 104 105 def __behaviour__(:docs) do 106 {:docs_v1, _, :elixir, _, _, _, docs} = Code.fetch_docs(__MODULE__) 107 108 for {{kind, name, arity}, line, _, doc, _} <- docs, kind in [:callback, :macrocallback] do 109 case kind do 110 :callback -> {{name, arity}, line, :def, __behaviour__doc_value(doc)} 111 :macrocallback -> {{name, arity}, line, :defmacro, __behaviour__doc_value(doc)} 112 end 113 end 114 end 115 116 defp __behaviour__doc_value(%{"en" => doc}), do: doc 117 defp __behaviour__doc_value(:hidden), do: false 118 defp __behaviour__doc_value(_), do: nil 119 120 import unquote(__MODULE__) 121 end 122 end 123end 124