diff options
author | Andrea Leopardi <an.leopardi@gmail.com> | 2016-09-24 16:28:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-09-24 16:28:29 +0200 |
commit | 2d23f09430f9b9d8a2306ebd2a514bb7403b02b0 (patch) | |
tree | 7e221dbaa35dd2f08f2cfc1b9f0dfddecf36f47e | |
parent | 43e8f2e6e5ef3293da8f7351fec2c7a5d5169fc8 (diff) | |
download | elixir-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.ex | 16 | ||||
-rw-r--r-- | lib/iex/lib/iex/info.ex | 28 | ||||
-rw-r--r-- | lib/iex/test/iex/helpers_test.exs | 2 | ||||
-rw-r--r-- | lib/iex/test/iex/info_test.exs | 8 |
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") |