Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lib/ex_doc.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ defmodule ExDoc do
Elixir Documentation System. ExDoc produces documentation for Elixir projects
"""

alias ExDoc.Markdown

defmodule Config do
@moduledoc """
Configuration structure that holds all the available options for ExDoc
Expand Down Expand Up @@ -39,6 +41,7 @@ defmodule ExDoc do
language: @default.language,
logo: nil,
main: nil,
markdown_processor: nil,
output: @default.output,
project: nil,
retriever: @default.retriever,
Expand Down Expand Up @@ -67,6 +70,7 @@ defmodule ExDoc do
language: String.t,
logo: nil | Path.t,
main: nil | String.t,
markdown_processor: nil | atom,
output: nil | Path.t,
project: nil | String.t,
retriever: :atom,
Expand Down Expand Up @@ -102,6 +106,12 @@ defmodule ExDoc do
# 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
# The app environment has priority over the mix config
processor_from_env = Markdown.get_markdown_processor_from_app_env()
if !processor_from_env && options[:markdown_processor] do
Markdown.set_markdown_processor(options[:markdown_processor])
end
# After this, we have no use for the :markdown processor option
options = normalize_options(options)
preconfig = %Config{
project: project,
Expand Down
12 changes: 11 additions & 1 deletion lib/ex_doc/markdown.ex
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,23 @@ defmodule ExDoc.Markdown do
bin
end

@doc false
def get_markdown_processor_from_app_env do
Application.get_env(:ex_doc, @markdown_processor_key)
end

@doc false
def set_markdown_processor(processor) do
Application.put_env(:ex_doc, @markdown_processor_key, processor)
end

defp get_markdown_processor do
case Application.fetch_env(:ex_doc, @markdown_processor_key) do
{:ok, processor} ->
processor
:error ->
processor = find_markdown_processor() || raise_no_markdown_processor()
Application.put_env(:ex_doc, @markdown_processor_key, processor)
set_markdown_processor(processor)
processor
end
end
Expand Down
18 changes: 18 additions & 0 deletions lib/ex_doc/markdown/mocks.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule ExDoc.Markdown.MockMarkdownProcessor.MockMarkdownProcessorError do
@moduledoc false

defexception message: "You're using a mock markdown processor"
end

defmodule ExDoc.Markdown.MockMarkdownProcessor do
@moduledoc false

# To be used in only in testing

def to_html(_, _) do
# When we get an exception, we know this processor's been used
# This seems to be the easiest way to ensure we're choosing the right processor
# without instrumenting the code
raise ExDoc.Markdown.MockMarkdownProcessor.MockMarkdownProcessorError
end
end
84 changes: 84 additions & 0 deletions test/ex_doc/markdown_processor_option_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
defmodule ExDoc.MarkdownProcessorOptionTest do
use ExUnit.Case

alias ExDoc.Markdown.MockMarkdownProcessor
alias ExDoc.Markdown.MockMarkdownProcessor.MockMarkdownProcessorError

setup do
File.rm_rf(output_dir())
File.mkdir_p!(output_dir())
end

defp output_dir do
Path.expand("../../tmp/html", __DIR__)
end

defp beam_dir do
Path.expand("../../tmp/beam", __DIR__)
end

defp doc_config_markdown_processor_not_set do
[project: "Elixir",
version: "1.0.1",
formatter: "html",
assets: "test/tmp/html_assets",
output: output_dir(),
source_root: beam_dir(),
source_beam: beam_dir(),
logo: "test/fixtures/elixir.png",
extras: ["test/fixtures/README.md"]]
end

defp doc_config_markdown_processor_set do
# MockMarkdownProcessor will raise an exception if used to process files
# This exception will be our way to tell that someting's not right.
Keyword.put(doc_config_markdown_processor_not_set(),
:markdown_processor,
MockMarkdownProcessor)
end

def generate_docs(config) do
# A wrapper around the child process, so that we can use assert_raise below.
# Propagates the MockMarkdownProcessorError exception from the chid process.
# Raises a MockMarkdownProcessorError if the exception causes the child process to exit.
Process.flag(:trap_exit, true)
try do
ExDoc.generate_docs(config[:project], config[:version], config)
catch
# Raise the exception so that it can be captured by assert_raise
:exit, {{%MockMarkdownProcessorError{} = exception, _}, _} -> raise exception
# The purpose of these tests is to detect if the right markdown processor is used.
_ -> :ok
end
end

test "app env not set, markdown_processor option set" do
Application.delete_env(:ex_doc, :markdown_processor)
# ExDoc.Markdown should respect our choice and run the mock processor
assert_raise MockMarkdownProcessorError, fn ->
generate_docs doc_config_markdown_processor_set()
end
end

test "app env not set, markdown_processor option not set" do
Application.delete_env(:ex_doc, :markdown_processor)
generate_docs doc_config_markdown_processor_not_set()
end

test "app env set, markdown_processor option set" do
Application.put_env(:ex_doc, :markdown_processor, MockMarkdownProcessor)
# It's been given two mock processors
assert_raise MockMarkdownProcessorError, fn ->
generate_docs doc_config_markdown_processor_set()
end
end

test "app env set, markdown_processor option not set" do
Application.put_env(:ex_doc, :markdown_processor, MockMarkdownProcessor)
# The app env has priority
assert_raise MockMarkdownProcessorError, fn ->
generate_docs doc_config_markdown_processor_not_set()
end
end

end