summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrea Leopardi <an.leopardi@gmail.com>2016-09-24 16:28:29 +0200
committerGitHub <noreply@github.com>2016-09-24 16:28:29 +0200
commit2d23f09430f9b9d8a2306ebd2a514bb7403b02b0 (patch)
tree7e221dbaa35dd2f08f2cfc1b9f0dfddecf36f47e
parent43e8f2e6e5ef3293da8f7351fec2c7a5d5169fc8 (diff)
downloadelixir-2d23f09430f9b9d8a2306ebd2a514bb7403b02b0.tar.gz
Add info about protocols in the i/1 IEx Helpers (#5241)
With this commit, we show info about the protocols that a given data structure implements and in case that data structure is a module that is also a protocol, we show all the data structures that implement that protocols as well.
-rw-r--r--lib/iex/lib/iex/helpers.ex16
-rw-r--r--lib/iex/lib/iex/info.ex28
-rw-r--r--lib/iex/test/iex/helpers_test.exs2
-rw-r--r--lib/iex/test/iex/info_test.exs8
4 files changed, 45 insertions, 9 deletions
diff --git a/lib/iex/lib/iex/helpers.ex b/lib/iex/lib/iex/helpers.ex
index 9dfc97e62..6b6470a3f 100644
--- a/lib/iex/lib/iex/helpers.ex
+++ b/lib/iex/lib/iex/helpers.ex
@@ -429,7 +429,10 @@ defmodule IEx.Helpers do
"""
def i(term) do
- info = ["Term": inspect(term)] ++ IEx.Info.info(term)
+ info =
+ ["Term": inspect(term)] ++
+ IEx.Info.info(term) ++
+ ["Implemented protocols": all_implemented_protocols_for_term(term)]
for {subject, info} <- info do
info = info |> to_string() |> String.trim() |> String.replace("\n", "\n ")
@@ -440,6 +443,17 @@ defmodule IEx.Helpers do
dont_display_result()
end
+ # Given any "term", this function returns all the protocols in
+ # :code.get_path() implemented by the data structure of such term, in the form
+ # of a binary like "Protocol1, Protocol2, Protocol3".
+ defp all_implemented_protocols_for_term(term) do
+ :code.get_path()
+ |> Protocol.extract_protocols()
+ |> Enum.uniq()
+ |> Enum.reject(fn(protocol) -> is_nil(protocol.impl_for(term)) end)
+ |> Enum.map_join(", ", &inspect/1)
+ end
+
@doc """
Flushes all messages sent to the shell and prints them out.
"""
diff --git a/lib/iex/lib/iex/info.ex b/lib/iex/lib/iex/info.ex
index b7e6b32b0..517ba740c 100644
--- a/lib/iex/lib/iex/info.ex
+++ b/lib/iex/lib/iex/info.ex
@@ -35,13 +35,27 @@ defimpl IEx.Info, for: Atom do
end
mod_info = mod.module_info()
- ["Module bytecode": module_object_file(mod),
- "Source": module_source_file(mod_info),
- "Version": module_version(mod_info),
- "Compile options": module_compile_options(mod_info),
- "Description": "#{extra}Call #{inspect mod}.module_info() to access metadata.",
- "Raw representation": ":" <> inspect(Atom.to_string(mod)),
- "Reference modules": "Module, Atom"]
+ generic_info =
+ ["Module bytecode": module_object_file(mod),
+ "Source": module_source_file(mod_info),
+ "Version": module_version(mod_info),
+ "Compile options": module_compile_options(mod_info),
+ "Description": "#{extra}Call #{inspect mod}.module_info() to access metadata."]
+
+ specific_info =
+ if function_exported?(mod, :__protocol__, 1) do
+ impls =
+ mod
+ |> Protocol.extract_impls(:code.get_path())
+ |> Enum.map_join(", ", &inspect/1)
+ ["Protocol": "This module is a protocol. These data structures implement it:\n #{impls}"]
+ else
+ []
+ end
+
+ generic_info ++ specific_info ++
+ ["Raw representation": ":" <> inspect(Atom.to_string(mod)),
+ "Reference modules": "Module, Atom"]
end
defp info_module_like_atom(atom) do
diff --git a/lib/iex/test/iex/helpers_test.exs b/lib/iex/test/iex/helpers_test.exs
index 96da4f6ce..16338d6ae 100644
--- a/lib/iex/test/iex/helpers_test.exs
+++ b/lib/iex/test/iex/helpers_test.exs
@@ -493,7 +493,7 @@ defmodule IEx.HelpersTest do
test "i helper" do
output = capture_iex ~s[i(:ok)]
- assert output == String.trim_trailing("""
+ assert output =~ String.trim_trailing("""
Term
:ok
Data type
diff --git a/lib/iex/test/iex/info_test.exs b/lib/iex/test/iex/info_test.exs
index 8974e6fc4..a9daece59 100644
--- a/lib/iex/test/iex/info_test.exs
+++ b/lib/iex/test/iex/info_test.exs
@@ -29,6 +29,14 @@ defmodule IEx.InfoTest do
assert info[:"Description"] == description
end
+ test "atoms: module that is also a protocol" do
+ info = Info.info(String.Chars)
+ description = info[:"Protocol"]
+ assert description =~ "This module is a protocol"
+ assert description =~ "Atom"
+ assert description =~ "BitString"
+ end
+
test "atoms: module-like atom (Foo)" do
info = Info.info(NonexistentModuleAtom)
assert info[:"Raw representation"] == ~s(:"Elixir.NonexistentModuleAtom")