Skip to content

Commit

Permalink
Add signatures to docs information
Browse files Browse the repository at this point in the history
  • Loading branch information
José Valim committed Jul 2, 2012
1 parent b74447b commit cf3ba5a
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 18 deletions.
80 changes: 67 additions & 13 deletions lib/module.ex
Original file line number Diff line number Diff line change
Expand Up @@ -143,38 +143,92 @@ defmodule Module do
## Examples
defmodule MyModule do
Module.add_doc(__MODULE__, __ENV__.line + 1, :def, { :version, 0 }, "Manually added docs")
Module.add_doc(__MODULE__, __ENV__.line + 1, :def, { :version, 0 }, [], "Manually added docs")
def version, do: 1
end
"""
def add_doc(_module, _line, kind, _tuple, nil) when kind in [:defp, :defmacrop] do
:ok
def add_doc(_module, _line, kind, _tuple, _signature, doc) when kind in [:defp, :defmacrop] do
if doc, do: { :error, :private_doc }, else: :ok
end

def add_doc(_module, _line, kind, _tuple, _doc) when kind in [:defp, :defmacrop] do
{ :error, :private_doc }
end

def add_doc(module, line, kind, tuple, doc) when
def add_doc(module, line, kind, tuple, signature, doc) when
is_binary(doc) or is_boolean(doc) or doc == nil do
assert_not_compiled!(:add_doc, module)
table = docs_table_for(module)

{ signature, _ } = Enum.map_reduce signature, 1, fn(x, acc) ->
{ simplify_signature(x, line, acc), acc + 1 }
end

case { ETS.lookup(table, tuple), doc } do
{ [], _ } ->
ETS.insert(table, { tuple, line, kind, doc })
ETS.insert(table, { tuple, line, kind, signature, doc })
:ok
{ _, nil } ->
{ [{ tuple, line, kind, old, doc }], nil } ->
ETS.insert(table, { tuple, line, kind, merge_signatures(old, signature, 1), doc })
:ok
_ ->
{ :error, :existing_doc }
end
end

# Simplify signatures to be stored in docs

defp simplify_signature({ ://, defline, [left, right ] }, line, i) do
{ ://, defline, [simplify_signature(left, line, i), right] }
end

defp simplify_signature({ var, line, atom }, _, i) when is_atom(atom) do
case atom_to_list(var) do
[?_,?_|_] -> { :"arg#{i}", line, :guess }
[?_|t] -> { list_to_atom(t), line, :guess }
_ -> { var, line, nil }
end
end

defp simplify_signature({ :=, _, [_, right] }, line, i) do
simplify_signature(right, line, i)
end

defp simplify_signature(other, line, i) when is_integer(other), do: { :"int#{i}", line, :guess }
defp simplify_signature(other, line, i) when is_atom(other), do: { :"atom#{i}", line, :guess }
defp simplify_signature(other, line, i) when is_list(other), do: { :"list#{i}", line, :guess }
defp simplify_signature(other, line, i) when is_float(other), do: { :"float#{i}", line, :guess }
defp simplify_signature(other, line, i) when is_binary(other), do: { :"binary#{i}", line, :guess }
defp simplify_signature(_, line, i), do: { :"arg#{i}", line, :guess }

# Merge signatures

defp merge_signatures([h1|t1], [h2|t2], i) do
[merge_signature(h1, h2, i)|merge_signatures(t1, t2, i + 1)]
end

defp merge_signatures([], [], _) do
[]
end

defp merge_signature({ ://, line, [left, right] }, newer, i) do
{ ://, line, [merge_signature(left, newer, i), right] }
end

defp merge_signature(older, { ://, _, [left, _] }, i) do
merge_signature(older, left, i)
end

# The older signature, when given, always have higher precedence
defp merge_signature({ _, _, nil } = older, _newer, _), do: older
defp merge_signature(_older, { _, _, nil } = newer, _), do: newer

# Both are a guess, so check if they are the same guess
defp merge_signature({ var, _, _ } = older, { var, _, _ }, _), do: older

# Otherwise, returns a generic guess
defp merge_signature({ _, line, _ }, _newer, i), do: { :"arg#{i}", line, :guess }

@doc """
Checks if a function was defined, regardless if it is
a macro or a private function. Use function_defined?/3
a macro or a private function. Use `function_defined?/3`
to assert for an specific type.
## Examples
Expand Down Expand Up @@ -404,9 +458,9 @@ defmodule Module do
@doc false
# Used internally to compile documentation. This function
# is private and must be used only internally.
def compile_doc(module, line, kind, pair) do
def compile_doc(module, line, kind, pair, signature) do
doc = read_attribute(module, :doc)
result = add_doc(module, line, kind, pair, doc)
result = add_doc(module, line, kind, pair, signature, doc)
delete_attribute(module, :doc)
result
end
Expand Down
6 changes: 3 additions & 3 deletions src/elixir_def.erl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ store_definition(Kind, Line, Module, Name, Args, Guards, RawExpr, RawS) ->
FunctionTable = table(Module),

CO = elixir_compiler:get_opts(),
compile_docs(Kind, Line, Module, Name, Arity, TS, CO),
compile_docs(Kind, Line, Module, Name, Arity, Args, TS, CO),

Location = retrieve_file(Module, CO),
Stack = S#elixir_scope.macro,
Expand Down Expand Up @@ -112,11 +112,11 @@ compile_super(Module, #elixir_scope{function=Function, super=true}) ->

compile_super(_Module, _S) -> [].

compile_docs(Kind, Line, Module, Name, Arity, S, CO) ->
compile_docs(Kind, Line, Module, Name, Arity, Args, S, CO) ->
case elixir_compiler:get_opt(docs, CO) of
false -> [];
true ->
case '__MAIN__-Module':compile_doc(Module, Line, Kind, { Name, Arity }) of
case '__MAIN__-Module':compile_doc(Module, Line, Kind, { Name, Arity }, Args) of
{ error, Message } -> elixir_errors:handle_file_warning(S#elixir_scope.file,
{ Line, ?MODULE, { Message, { Name, Arity } } });
_ -> []
Expand Down
2 changes: 1 addition & 1 deletion test/elixir/fixtures/compiled_with_docs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ defmodule CompiledWithDocs do
@moduledoc "moduledoc"

@doc "Some example"
def example(true), do: private
def example(false), do: 0
def example(var), do: var && private

def nodoc, do: 2
defp private, do: 1
Expand Down
2 changes: 1 addition & 1 deletion test/elixir/kernel/doc_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ defmodule Kernel.DocTest do
Elixir.ParallelCompiler.files_to_path([path], tmp)
Code.prepend_path(tmp)

expected = [{{:example,1},5,:def,"Some example"},{{:nodoc,0},8,:def,nil}]
expected = [{{:example,1},5,:def,[{:var,6,nil}],"Some example"},{{:nodoc,0},8,:def,[],nil}]
assert CompiledWithDocs.__info__(:docs) == expected
assert CompiledWithDocs.__info__(:moduledoc) == { 1, "moduledoc" }
after
Expand Down

0 comments on commit cf3ba5a

Please sign in to comment.