From df696e95578b23ab44022897c1436a268e7dcd68 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 8 Dec 2018 22:04:07 -0800 Subject: [PATCH 1/2] =?UTF-8?q?=CE=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/ex_doc.ex | 173 ++++++++++++++++------------------------- lib/ex_doc/config.ex | 11 +-- lib/ex_doc/markdown.ex | 21 +++-- 3 files changed, 80 insertions(+), 125 deletions(-) diff --git a/lib/ex_doc.ex b/lib/ex_doc.ex index 7169a8714..96262b06f 100644 --- a/lib/ex_doc.ex +++ b/lib/ex_doc.ex @@ -1,139 +1,102 @@ defmodule ExDoc do @moduledoc false - @ex_doc_version Mix.Project.config()[:version] alias ExDoc.Config - @doc """ - Returns the ExDoc version (used in templates). - """ - @spec version :: String.t() - def version, do: @ex_doc_version - - @doc """ - Generates documentation for the given `project`, `vsn` (version) - and `options`. - """ - @spec generate_docs(String.t(), String.t(), Keyword.t()) :: atom - def generate_docs(project, vsn, options) - when is_binary(project) and is_binary(vsn) and is_list(options) do - config = build_config(project, vsn, options) - - if processor = options[:markdown_processor] do - ExDoc.Markdown.put_markdown_processor(processor) - end - - if markdown_processor_options = options[:markdown_processor_options] do - ExDoc.Markdown.configure_processor(markdown_processor_options) - end + @doc "Returns the ExDoc version. (Used in templates.)" + @spec version :: String.t - docs = config.retriever.docs_from_dir(config.source_beam, config) - find_formatter(config.formatter).run(docs, config) - end + @ex_doc_version Mix.Project.config()[:version] + def version, do: @ex_doc_version - # Builds configuration by merging `options`, and normalizing the options. - @spec build_config(String.t(), String.t(), Keyword.t()) :: ExDoc.Config.t() - defp build_config(project, vsn, options) do + @doc "Generates docs for the given `project`, `vsn` (version) & `options`." + @spec generate_docs(String.t, String.t, Keyword.t) :: atom + def generate_docs(project, version, options) when is_binary(project) + and is_binary(version) + and is_list(options) + do options = normalize_options(options) + config = struct(%Config{ + project: project, + version: version, + source_root: Keyword.get(options, :source_root, File.cwd!()) + }, options) - preconfig = %Config{ - project: project, - version: vsn, - main: options[:main], - homepage_url: options[:homepage_url], - source_root: options[:source_root] || File.cwd!() - } + # two side-effects + ExDoc.Markdown.put_markdown_processor(options[:markdown_processor]) + ExDoc.Markdown.configure_processor(options[:markdown_processor_options]) - struct(preconfig, options) + docs = config.retriever.docs_from_dir(config.source_beam, config) + find_formatter(config.formatter).run(docs, config) # below `normalize_module_nesting_prefixes/1` end - # Short path for programmatic interface - defp find_formatter(modname) when is_atom(modname), do: modname - - defp find_formatter("ExDoc.Formatter." <> _ = name) do - [name] - |> Module.concat() - |> check_formatter_module(name) - end + defp normalize_options(options) do + pattern = options[:source_url_pattern] || + guess_url(options[:source_url], options[:source_ref] || + ExDoc.Config.default_source_ref()) - defp find_formatter(name) do - [ExDoc.Formatter, String.upcase(name)] - |> Module.concat() - |> check_formatter_module(name) + Keyword.put(options, :source_url_pattern, pattern) + |> normalize_output() # below `append_slash/1` end - defp check_formatter_module(modname, argname) do - if Code.ensure_loaded?(modname) do - modname + defp guess_url(url, ref) do + with {:ok, host_with_path} <- http_or_https(url), + {:ok, pattern} <- known_pattern(host_with_path, ref) + do + "https://" <> append_slash(host_with_path) <> pattern else - raise "formatter module #{inspect(argname)} not found" + _ -> url end end - # Helpers + defp http_or_https("http://" <> rest), do: {:ok, rest} + defp http_or_https("https://" <> rest), do: {:ok, rest} + defp http_or_https(_), do: :error - defp normalize_options(options) do - pattern = - options[:source_url_pattern] || - guess_url(options[:source_url], options[:source_ref] || ExDoc.Config.default_source_ref()) + defp known_pattern("github.com/" <> _, ref), do: {:ok, "blob/#{ref}/%{path}#L%{line}"} + defp known_pattern("gitlab.com/" <> _, ref), do: {:ok, "blob/#{ref}/%{path}#L%{line}"} + defp known_pattern("bitbucket.org/" <> _, ref), do: {:ok, "src/#{ref}/%{path}#cl-%{line}"} + defp known_pattern(_host_with_path, _ref), do: :error - options - |> Keyword.put(:source_url_pattern, pattern) - |> normalize_output() - |> normalize_module_nesting_prefixes() - end + defp append_slash(url), do: + if :binary.last(url) == ?/, do: url, else: url <> "/" defp normalize_output(options) do - if is_binary(options[:output]) do - Keyword.put(options, :output, String.trim_trailing(options[:output], "/")) + output = options[:output] + + if is_binary(output) do + Keyword.put(options, :output, String.trim_trailing(output, "/")) else options end + |> normalize_module_nesting_prefixes() end + # Sorts `:nest_modules_by_prefix` in descending order. Helps to find longest match. defp normalize_module_nesting_prefixes(options) do - # sort in descending order to facilitate finding longest match - normalized_prefixes = - options - |> Keyword.get(:nest_modules_by_prefix, []) - |> Enum.map(&inspect/1) - |> Enum.sort() - |> Enum.reverse() + normalized_prefixes = options + |> Keyword.get(:nest_modules_by_prefix, []) + |> Enum.map(&inspect/1) + |> Enum.sort + |> Enum.reverse() Keyword.put(options, :nest_modules_by_prefix, normalized_prefixes) end - defp guess_url(url, ref) do - with {:ok, host_with_path} <- http_or_https(url), - {:ok, pattern} <- known_pattern(host_with_path, ref) do - "https://" <> append_slash(host_with_path) <> pattern - else - _ -> url - end - end - - defp http_or_https("http://" <> rest), - do: {:ok, rest} - - defp http_or_https("https://" <> rest), - do: {:ok, rest} - - defp http_or_https(_), - do: :error - - defp known_pattern("github.com/" <> _, ref), - do: {:ok, "blob/#{ref}/%{path}#L%{line}"} - - defp known_pattern("gitlab.com/" <> _, ref), - do: {:ok, "blob/#{ref}/%{path}#L%{line}"} - - defp known_pattern("bitbucket.org/" <> _, ref), - do: {:ok, "src/#{ref}/%{path}#cl-%{line}"} - - defp known_pattern(_host_with_path, _ref), - do: :error - - defp append_slash(url) do - if :binary.last(url) == ?/, do: url, else: url <> "/" - end + # Short path for programmatic interface + defp find_formatter(modname) when is_atom(modname), + do: modname + defp find_formatter("ExDoc.Formatter." <> _ = name), + do: [name] + |> Module.concat() + |> check_formatter_module(name) + defp find_formatter(name), + do: [ExDoc.Formatter, String.upcase(name)] + |> Module.concat() + |> check_formatter_module(name) + + defp check_formatter_module(modname, argname), do: + if Code.ensure_loaded?(modname), + do: modname, + else: raise "formatter module #{inspect(argname)} not found" end diff --git a/lib/ex_doc/config.ex b/lib/ex_doc/config.ex index b028edc28..cd3bfed6d 100644 --- a/lib/ex_doc/config.ex +++ b/lib/ex_doc/config.ex @@ -2,15 +2,10 @@ defmodule ExDoc.Config do @moduledoc false @default_formatter "html" - @default_source_ref "master" - - def default_source_ref do - @default_source_ref - end + def default_formatter, do: @default_formatter - def default_formatter do - @default_formatter - end + @default_source_ref "master" + def default_source_ref, do: @default_source_ref def before_closing_head_tag(_), do: "" def before_closing_body_tag(_), do: "" diff --git a/lib/ex_doc/markdown.ex b/lib/ex_doc/markdown.ex index 4779880ff..c9f24cc35 100644 --- a/lib/ex_doc/markdown.ex +++ b/lib/ex_doc/markdown.ex @@ -130,20 +130,17 @@ defmodule ExDoc.Markdown do end end + @doc "Changes the markdown processor globally." + def put_markdown_processor(processor), do: + if processor, do: Application.put_env(:ex_doc, @markdown_processor_key, processor) + @doc """ - Changes the markdown processor globally. + This function configures the markdown processor with the given options. + It's called exactly once when ExDoc reads its own configuration options. + It's supposed to be called for its side-effects. """ - def put_markdown_processor(processor) do - Application.put_env(:ex_doc, @markdown_processor_key, processor) - end - - @doc false - def configure_processor(options) do - # This function configures the markdown processor with the given options. - # It's called exactly once when ExDoc reads its own configuration options. - # It's supposed to be called for its side-effects. - get_markdown_processor().configure(options) - end + def configure_processor(options), do: + if options, do: get_markdown_processor().configure(options) defp find_markdown_processor do Enum.find(@markdown_processors, fn module -> From 7966ca08bd7ad7d160d74954f90911fd1059dc58 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 8 Dec 2018 22:15:42 -0800 Subject: [PATCH 2/2] ... mix format --- lib/ex_doc.ex | 93 +++++++++++++++++++++++------------------- lib/ex_doc/markdown.ex | 8 ++-- 2 files changed, 56 insertions(+), 45 deletions(-) diff --git a/lib/ex_doc.ex b/lib/ex_doc.ex index 96262b06f..650c557ff 100644 --- a/lib/ex_doc.ex +++ b/lib/ex_doc.ex @@ -4,62 +4,66 @@ defmodule ExDoc do alias ExDoc.Config @doc "Returns the ExDoc version. (Used in templates.)" - @spec version :: String.t + @spec version :: String.t() @ex_doc_version Mix.Project.config()[:version] def version, do: @ex_doc_version @doc "Generates docs for the given `project`, `vsn` (version) & `options`." - @spec generate_docs(String.t, String.t, Keyword.t) :: atom - def generate_docs(project, version, options) when is_binary(project) - and is_binary(version) - and is_list(options) - do + @spec generate_docs(String.t(), String.t(), Keyword.t()) :: atom + def generate_docs(project, version, options) + when is_binary(project) and is_binary(version) and is_list(options) do options = normalize_options(options) - config = struct(%Config{ - project: project, - version: version, - source_root: Keyword.get(options, :source_root, File.cwd!()) - }, options) + + config = + struct( + %Config{ + project: project, + version: version, + source_root: Keyword.get(options, :source_root, File.cwd!()) + }, + options + ) # two side-effects ExDoc.Markdown.put_markdown_processor(options[:markdown_processor]) ExDoc.Markdown.configure_processor(options[:markdown_processor_options]) docs = config.retriever.docs_from_dir(config.source_beam, config) - find_formatter(config.formatter).run(docs, config) # below `normalize_module_nesting_prefixes/1` + find_formatter(config.formatter).run(docs, config) + # below `normalize_module_nesting_prefixes/1` end defp normalize_options(options) do - pattern = options[:source_url_pattern] || - guess_url(options[:source_url], options[:source_ref] || - ExDoc.Config.default_source_ref()) + pattern = + options[:source_url_pattern] || + guess_url(options[:source_url], options[:source_ref] || ExDoc.Config.default_source_ref()) Keyword.put(options, :source_url_pattern, pattern) - |> normalize_output() # below `append_slash/1` + |> normalize_output() + + # below `append_slash/1` end defp guess_url(url, ref) do with {:ok, host_with_path} <- http_or_https(url), - {:ok, pattern} <- known_pattern(host_with_path, ref) - do + {:ok, pattern} <- known_pattern(host_with_path, ref) do "https://" <> append_slash(host_with_path) <> pattern else _ -> url end end - defp http_or_https("http://" <> rest), do: {:ok, rest} + defp http_or_https("http://" <> rest), do: {:ok, rest} defp http_or_https("https://" <> rest), do: {:ok, rest} - defp http_or_https(_), do: :error + defp http_or_https(_), do: :error - defp known_pattern("github.com/" <> _, ref), do: {:ok, "blob/#{ref}/%{path}#L%{line}"} - defp known_pattern("gitlab.com/" <> _, ref), do: {:ok, "blob/#{ref}/%{path}#L%{line}"} + defp known_pattern("github.com/" <> _, ref), do: {:ok, "blob/#{ref}/%{path}#L%{line}"} + defp known_pattern("gitlab.com/" <> _, ref), do: {:ok, "blob/#{ref}/%{path}#L%{line}"} defp known_pattern("bitbucket.org/" <> _, ref), do: {:ok, "src/#{ref}/%{path}#cl-%{line}"} - defp known_pattern(_host_with_path, _ref), do: :error + defp known_pattern(_host_with_path, _ref), do: :error - defp append_slash(url), do: - if :binary.last(url) == ?/, do: url, else: url <> "/" + defp append_slash(url), do: if(:binary.last(url) == ?/, do: url, else: url <> "/") defp normalize_output(options) do output = options[:output] @@ -74,11 +78,12 @@ defmodule ExDoc do # Sorts `:nest_modules_by_prefix` in descending order. Helps to find longest match. defp normalize_module_nesting_prefixes(options) do - normalized_prefixes = options - |> Keyword.get(:nest_modules_by_prefix, []) - |> Enum.map(&inspect/1) - |> Enum.sort - |> Enum.reverse() + normalized_prefixes = + options + |> Keyword.get(:nest_modules_by_prefix, []) + |> Enum.map(&inspect/1) + |> Enum.sort() + |> Enum.reverse() Keyword.put(options, :nest_modules_by_prefix, normalized_prefixes) end @@ -86,17 +91,23 @@ defmodule ExDoc do # Short path for programmatic interface defp find_formatter(modname) when is_atom(modname), do: modname + defp find_formatter("ExDoc.Formatter." <> _ = name), - do: [name] - |> Module.concat() - |> check_formatter_module(name) + do: + [name] + |> Module.concat() + |> check_formatter_module(name) + defp find_formatter(name), - do: [ExDoc.Formatter, String.upcase(name)] - |> Module.concat() - |> check_formatter_module(name) - - defp check_formatter_module(modname, argname), do: - if Code.ensure_loaded?(modname), - do: modname, - else: raise "formatter module #{inspect(argname)} not found" + do: + [ExDoc.Formatter, String.upcase(name)] + |> Module.concat() + |> check_formatter_module(name) + + defp check_formatter_module(modname, argname), + do: + if(Code.ensure_loaded?(modname), + do: modname, + else: raise("formatter module #{inspect(argname)} not found") + ) end diff --git a/lib/ex_doc/markdown.ex b/lib/ex_doc/markdown.ex index c9f24cc35..ef318beb9 100644 --- a/lib/ex_doc/markdown.ex +++ b/lib/ex_doc/markdown.ex @@ -131,16 +131,16 @@ defmodule ExDoc.Markdown do end @doc "Changes the markdown processor globally." - def put_markdown_processor(processor), do: - if processor, do: Application.put_env(:ex_doc, @markdown_processor_key, processor) + def put_markdown_processor(processor), + do: if(processor, do: Application.put_env(:ex_doc, @markdown_processor_key, processor)) @doc """ This function configures the markdown processor with the given options. It's called exactly once when ExDoc reads its own configuration options. It's supposed to be called for its side-effects. """ - def configure_processor(options), do: - if options, do: get_markdown_processor().configure(options) + def configure_processor(options), + do: if(options, do: get_markdown_processor().configure(options)) defp find_markdown_processor do Enum.find(@markdown_processors, fn module ->