Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate docs for Erlang projects #1291

Closed
wants to merge 6 commits into from
Closed

Conversation

erszcz
Copy link
Contributor

@erszcz erszcz commented Nov 13, 2020

Hi! This PR fixes some small issues when generating docs from Erlang doc chunks (created by erl_docgen or edoc). These are mostly earlier @wojtekmach's changes and my fixes from #1143, applied on top of the current master.

This PR also exposes the ExDoc.Config.proglang field as a command line switch --proglang. This way it's possible to determine which (Elixir, the default, or Erlang) stylesheet is used for the generated documentation. This might not be flexible enough for projects shipping both Erlang and Elixir APIs, but seems to be a good enough starting point.

A preview of a trivial lib's docs is available at https://erszcz.github.io/kvs.

Currently, the prerequisite to generate Erlang docs is having EDoc with EEP-48 support installed - either as a standalone app from https://github.com/erszcz/edoc or from erlang/otp#2803. With that in place:

$ PATH_TO_EDOC/bin/edoc.escript -app kvs -chunks -pa _build/default/lib/kvs/ebin
$ PATH_TO_EXDOC/bin/ex_doc kvs "0.1.0" _build/default/lib/kvs/ebin/ --main kvs -o ex_doc --proglang elixir

This addresses:

  $ elixir /Users/erszcz/work/elixir-lang/ex_doc/bin/ex_doc kvs "wip" _build/default/lib/kvs/ebin/ --main kvs -o ex_doc
  ** (UndefinedFunctionError) function :kvs.__info__/1 is undefined or private
      :kvs.__info__(:compile)
      (ex_doc 0.23.0) lib/ex_doc/retriever.ex:591: ExDoc.Retriever.source_path/2
      (ex_doc 0.23.0) lib/ex_doc/retriever.ex:131: ExDoc.Retriever.do_generate_node/3
      (ex_doc 0.23.0) lib/ex_doc/retriever.ex:125: ExDoc.Retriever.generate_node/3
      (elixir 1.11.0-dev) lib/enum.ex:3425: Enum.flat_map_list/2
      (ex_doc 0.23.0) lib/ex_doc/retriever.ex:43: ExDoc.Retriever.docs_from_modules/2
      (ex_doc 0.23.0) lib/ex_doc.ex:26: ExDoc.generate_docs/3
This addresses:

  $ elixir /Users/erszcz/work/elixir-lang/ex_doc/bin/ex_doc kvs "wip" _build/default/lib/kvs/ebin/ --main kvs -o ex_doc
  ** (RuntimeError) content type "application/erlang+html" is not supported
      (ex_doc 0.23.0) lib/ex_doc/retriever.ex:172: ExDoc.Retriever.doc_ast/3
      (ex_doc 0.23.0) lib/ex_doc/retriever.ex:217: ExDoc.Retriever.get_module_docs/2
      (ex_doc 0.23.0) lib/ex_doc/retriever.ex:134: ExDoc.Retriever.do_generate_node/3
      (ex_doc 0.23.0) lib/ex_doc/retriever.ex:125: ExDoc.Retriever.generate_node/3
      (elixir 1.11.0-dev) lib/enum.ex:3425: Enum.flat_map_list/2
      (ex_doc 0.23.0) lib/ex_doc/retriever.ex:43: ExDoc.Retriever.docs_from_modules/2
      (ex_doc 0.23.0) lib/ex_doc.ex:26: ExDoc.generate_docs/3
$ elixir /Users/erszcz/work/elixir-lang/ex_doc/bin/ex_doc kvs "wip" _build/default/lib/kvs/ebin/ --main kvs -o ex_doc
** (FunctionClauseError) no function clause matching in ExDoc.Autolink.fragment/4

    The following arguments were given to ExDoc.Autolink.fragment/4:

        # 1
        :no_tool

        # 2
        :type

        # 3
        :t

        # 4
        0

    Attempted function clauses (showing 2 out of 2):

        defp fragment(:ex_doc, kind, name, arity)
        defp fragment(:otp, kind, name, arity)

    (ex_doc 0.23.0) lib/ex_doc/autolink.ex:556: ExDoc.Autolink.fragment/4
    (ex_doc 0.23.0) lib/ex_doc/autolink.ex:395: anonymous fn/7 in ExDoc.Autolink.do_typespec/2
    (elixir 1.11.0-dev) lib/regex.ex:738: Regex.apply_list/5
    (elixir 1.11.0-dev) lib/regex.ex:733: Regex.apply_list/5
    (elixir 1.11.0-dev) lib/regex.ex:675: Regex.do_replace/4
    (ex_doc 0.23.0) lib/ex_doc/autolink.ex:402: anonymous fn/7 in ExDoc.Autolink.do_typespec/2
    (elixir 1.11.0-dev) lib/regex.ex:738: Regex.apply_list/5
    (elixir 1.11.0-dev) lib/regex.ex:733: Regex.apply_list/5
@wojtekmach
Copy link
Member

@erszcz great, thank you! It's marked as WIP so please let us know when you think it's ready to be merged in - we don't have to solve everything in this one PR of course, but if we can find an incremental step and merge that, I think that's a good path forward.

Regarding having to use your EDoc branch, I was able to find a workaround. It might be using private code so take it with a grain of salt. Here's generating chunk for foo module in ex_doc app:

$ app=ex_doc; \
  module=foo; \
  app_dir=_build/dev/lib/$app; \
  xml_dir=$app_dir/doc/xml; mkdir -p $xml_dir; \
  chunks_dir=$app_dir/doc/chunks; mkdir -p $chunks_dir; \
  erl_docgen_dir=$(erl -noshell -eval 'io:format("~s", [code:lib_dir(erl_docgen)]), halt()'); \
  escript $erl_docgen_dir/priv/bin/xml_from_edoc.escript -dir $xml_dir src/$module.erl; \
  escript $erl_docgen_dir/priv/bin/chunk.escript $app $app_dir/ebin "" $chunks_dir/$module.chunk

@erszcz
Copy link
Contributor Author

erszcz commented Nov 17, 2020

Hi @wojtekmach!

Regarding having to use your EDoc branch, I was able to find a workaround. [...]

Clever! I’ll have to see how these compare with EDoc chunks - I guess they might be missing callback docs, but I’m not sure right now.

It’s marked as WIP [...]

First, I was interested in your approach to exposing proglang as a CLI switch, but I understand you’re fine with that.

Then, we have the problem with tests. The failing test is 3rd party links, but in mix test context (or MIX_ENV=test iex -S mix), test_module is actually part of ExDoc:

$ MIX_ENV=test iex -S mix
iex(1)> :application.get_application(:test_module)
{:ok, :ex_doc}

This is consistent with the module’s comment in test/support/test_module.ex, which suggests it would more accurately fit into poject-local module, even though it’s an Erlang one.

I guess this should be explored further, since we can expect links to project-local Erlang modules (rare, I guess, though elixir itself is an example of such an app), or 3rd party Erlang modules (projects completely in Erlang; I expect this to be much more common, e.g. telemetry and Telemetry.Metrics). I see no reason not to link to standalone Erlang projects on HexDocs the same way Elixir docs are linked to.

In the scope of this PR, though, I propose to distinguish between Erlang OTP and non-OTP modules and only link to OTP docs. This does not introduce functionality changes and therefore carries no changes in tests.

@erszcz
Copy link
Contributor Author

erszcz commented Nov 17, 2020

I'm now a bit puzzled with the CI results of 390c561. When run locally, the first mix test run fails, but subsequent runs pass as expected. Troubleshooting...

@erszcz erszcz changed the title [WIP] Generate docs for Erlang projects Generate docs for Erlang projects Nov 17, 2020
@erszcz
Copy link
Contributor Author

erszcz commented Nov 17, 2020

@wojtekmach I've removed the WIP label. I think this is now ready to merge or review further if you see anything fishy :)

This sidesteps:

  ** (SyntaxError) nofile:1:15: syntax error before: in. "in" is a reserved word in Elixir and therefore its usage is limited. For instance, it can't be used as a variable or be defined nor invoked as a regular function
      (elixir 1.11.0-dev) lib/code.ex:654: Code.format_string!/2
      (ex_doc 0.23.0) lib/ex_doc/autolink.ex:342: ExDoc.Autolink.typespec/2
      (elixir 1.11.0-dev) lib/enum.ex:1399: Enum."-map/2-lists^map/1-0-"/2
      (ex_doc 0.23.0) lib/ex_doc/formatter/html.ex:86: anonymous fn/5 in ExDoc.Formatter.HTML.render_all/4
      (elixir 1.11.0-dev) lib/enum.ex:2185: Enum."-reduce/3-lists^foldl/2-0-"/3
      (ex_doc 0.23.0) lib/ex_doc/formatter/html.ex:83: anonymous fn/4 in ExDoc.Formatter.HTML.render_all/4
      (elixir 1.11.0-dev) lib/enum.ex:1399: Enum."-map/2-lists^map/1-0-"/2
@wojtekmach
Copy link
Member

@erszcz after #1329 lands, we'll have basic support on master! This is how it'll look like: http://wojtekmach.pl/docs/stdlib/api-reference.html. We still have some internal changes to do before we even introduce the language contract, but we're very close. Then we'd cherry pick things from this PR. THanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants