Code

Utilities for managing code compilation, code evaluation, and code loading.

This module complements Erlang’s :code module to add behaviour which is specific to Elixir. Almost all of the functions in this module have global side effects on the behaviour of Elixir.

Summary

Functions

append_path(path)

Appends a path to the end of the Erlang VM code path list

available_compiler_options()

Returns a list with the available compiler options

compile_quoted(quoted, file \\ "nofile")

Compiles the quoted expression

compile_string(string, file \\ "nofile")

Compiles the given string

compiler_options()

Gets the compilation options from the code server

compiler_options(opts)

Sets compilation options

delete_path(path)

Deletes a path from the Erlang VM code path list. This is the list of directories the Erlang VM uses for finding module code

ensure_compiled(module)

Ensures the given module is compiled and loaded

ensure_compiled?(module)

Ensures the given module is compiled and loaded

ensure_loaded(module)

Ensures the given module is loaded

ensure_loaded?(module)

Ensures the given module is loaded

eval_file(file, relative_to \\ nil)

Evals the given file

eval_quoted(quoted, binding \\ [], opts \\ [])

Evaluates the quoted contents

eval_string(string, binding \\ [], opts \\ [])

Evaluates the contents given by string

format_file!(file, opts \\ [])

Formats a file

format_string!(string, opts \\ [])

Formats the given code string

get_docs(module, kind)

Returns the docs for the given module

load_file(file, relative_to \\ nil)

Loads the given file

loaded_files()

Lists all loaded files

prepend_path(path)

Prepends a path to the beginning of the Erlang VM code path list

require_file(file, relative_to \\ nil)

Requires the given file

string_to_quoted(string, opts \\ [])

Converts the given string to its quoted form

string_to_quoted!(string, opts \\ [])

Converts the given string to its quoted form

unload_files(files)

Removes files from the loaded files list

Functions

append_path(path)

append_path(Path.t()) :: true | {:error, :bad_directory}

Appends a path to the end of the Erlang VM code path list.

This is the list of directories the Erlang VM uses for finding module code.

The path is expanded with Path.expand/1 before being appended. If this path does not exist, an error is returned.

Examples

Code.append_path(".")
#=> true

Code.append_path("/does_not_exist")
#=> {:error, :bad_directory}

available_compiler_options()

available_compiler_options() :: [atom()]

Returns a list with the available compiler options.

See compiler_options/1 for more info.

Examples

iex> Code.available_compiler_options
[:docs, :debug_info, :ignore_module_conflict, :relative_paths, :warnings_as_errors]

compile_quoted(quoted, file \\ "nofile")

compile_quoted(Macro.t(), binary()) :: [{module(), binary()}]

Compiles the quoted expression.

Returns a list of tuples where the first element is the module name and the second one is its bytecode (as a binary). A file can be given as second argument which will be used for reporting warnings and errors.

compile_string(string, file \\ "nofile")

compile_string(List.Chars.t(), binary()) :: [{module(), binary()}]

Compiles the given string.

Returns a list of tuples where the first element is the module name and the second one is its bytecode (as a binary). A file can be given as second argument which will be used for reporting warnings and errors.

For compiling many files at once, check Kernel.ParallelCompiler.compile/2.

compiler_options()

compiler_options() :: %{optional(atom()) => boolean()}

Gets the compilation options from the code server.

Check compiler_options/1 for more information.

Examples

Code.compiler_options()
#=> %{debug_info: true, docs: true,
#=>   warnings_as_errors: false, ignore_module_conflict: false}

compiler_options(opts)

compiler_options(Enumerable.t()) :: %{optional(atom()) => boolean()}

Sets compilation options.

These options are global since they are stored by Elixir’s Code Server.

Available options are:

  • :docs - when true, retain documentation in the compiled module. Defaults to true.

  • :debug_info - when true, retain debug information in the compiled module. This allows a developer to reconstruct the original source code. Defaults to false.

  • :ignore_module_conflict - when true, override modules that were already defined without raising errors. Defaults to false.

  • :relative_paths - when true, use relative paths in quoted nodes, warnings and errors generated by the compiler. Note disabling this option won’t affect runtime warnings and errors. Defaults to true.

  • :warnings_as_errors - causes compilation to fail when warnings are generated. Defaults to false.

It returns the new map of compiler options.

Examples

Code.compiler_options(debug_info: true)
#=> %{debug_info: true, docs: true,
#=>   warnings_as_errors: false, ignore_module_conflict: false}

delete_path(path)

delete_path(Path.t()) :: boolean()

Deletes a path from the Erlang VM code path list. This is the list of directories the Erlang VM uses for finding module code.

The path is expanded with Path.expand/1 before being deleted. If the path does not exist, this function returns false.

Examples

Code.prepend_path(".")
Code.delete_path(".")
#=> true

Code.delete_path("/does_not_exist")
#=> false

ensure_compiled(module)

ensure_compiled(module()) ::
  {:module, module()}
  | {:error, :embedded | :badfile | :nofile | :on_load_failure}

Ensures the given module is compiled and loaded.

If the module is already loaded, it works as no-op. If the module was not loaded yet, it checks if it needs to be compiled first and then tries to load it.

If it succeeds in loading the module, it returns {:module, module}. If not, returns {:error, reason} with the error reason.

Check ensure_loaded/1 for more information on module loading and when to use ensure_loaded/1 or ensure_compiled/1.

ensure_compiled?(module)

ensure_compiled?(module()) :: boolean()

Ensures the given module is compiled and loaded.

Similar to ensure_compiled/1, but returns true if the module is already loaded or was successfully loaded and compiled. Returns false otherwise.

ensure_loaded(module)

ensure_loaded(module()) ::
  {:module, module()}
  | {:error, :embedded | :badfile | :nofile | :on_load_failure}

Ensures the given module is loaded.

If the module is already loaded, this works as no-op. If the module was not yet loaded, it tries to load it.

If it succeeds in loading the module, it returns {:module, module}. If not, returns {:error, reason} with the error reason.

Code loading on the Erlang VM

Erlang has two modes to load code: interactive and embedded.

By default, the Erlang VM runs in interactive mode, where modules are loaded as needed. In embedded mode the opposite happens, as all modules need to be loaded upfront or explicitly.

Therefore, this function is used to check if a module is loaded before using it and allows one to react accordingly. For example, the URI module uses this function to check if a specific parser exists for a given URI scheme.

ensure_compiled/1

Elixir also contains an ensure_compiled/1 function that is a superset of ensure_loaded/1.

Since Elixir’s compilation happens in parallel, in some situations you may need to use a module that was not yet compiled, therefore it can’t even be loaded.

When invoked, ensure_compiled/1 halts the compilation of the caller until the module given to ensure_compiled/1 becomes available or all files for the current project have been compiled. If compilation finishes and the module is not available, an error tuple is returned.

ensure_compiled/1 does not apply to dependencies, as dependencies must be compiled upfront.

In most cases, ensure_loaded/1 is enough. ensure_compiled/1 must be used in rare cases, usually involving macros that need to invoke a module for callback information.

Examples

iex> Code.ensure_loaded(Atom)
{:module, Atom}

iex> Code.ensure_loaded(DoesNotExist)
{:error, :nofile}

ensure_loaded?(module)

ensure_loaded?(module()) :: boolean()

Ensures the given module is loaded.

Similar to ensure_loaded/1, but returns true if the module is already loaded or was successfully loaded. Returns false otherwise.

Examples

iex> Code.ensure_loaded?(Atom)
true

eval_file(file, relative_to \\ nil)

eval_file(binary(), nil | binary()) :: {term(), binding :: list()}

Evals the given file.

Accepts relative_to as an argument to tell where the file is located.

While load_file/2 loads a file and returns the loaded modules and their byte code, eval_file/2 simply evaluates the file contents and returns the evaluation result and its bindings (exactly the same return value as eval_string/3).

eval_quoted(quoted, binding \\ [], opts \\ [])

eval_quoted(Macro.t(), list(), Macro.Env.t() | keyword()) ::
  {term(), binding :: list()}

Evaluates the quoted contents.

Warning: Calling this function inside a macro is considered bad practice as it will attempt to evaluate runtime values at compile time. Macro arguments are typically transformed by unquoting them into the returned quoted expressions (instead of evaluated).

See eval_string/3 for a description of bindings and options.

Examples

iex> contents = quote(do: var!(a) + var!(b))
iex> Code.eval_quoted(contents, [a: 1, b: 2], file: __ENV__.file, line: __ENV__.line)
{3, [a: 1, b: 2]}

For convenience, you can pass __ENV__/0 as the opts argument and all options will be automatically extracted from the current environment:

iex> contents = quote(do: var!(a) + var!(b))
iex> Code.eval_quoted(contents, [a: 1, b: 2], __ENV__)
{3, [a: 1, b: 2]}

eval_string(string, binding \\ [], opts \\ [])

eval_string(List.Chars.t(), list(), Macro.Env.t() | keyword()) ::
  {term(), binding :: list()}

Evaluates the contents given by string.

The binding argument is a keyword list of variable bindings. The opts argument is a keyword list of environment options.

Warning: string can be any Elixir code and will be executed with the same privileges as the Erlang VM: this means that such code could compromise the machine (for example by executing system commands). Don’t use eval_string/3 with untrusted input (such as strings coming from the network).

Options

Options can be:

  • :file - the file to be considered in the evaluation

  • :line - the line on which the script starts

Additionally, the following scope values can be configured:

  • :aliases - a list of tuples with the alias and its target

  • :requires - a list of modules required

  • :functions - a list of tuples where the first element is a module and the second a list of imported function names and arity; the list of function names and arity must be sorted

  • :macros - a list of tuples where the first element is a module and the second a list of imported macro names and arity; the list of function names and arity must be sorted

Notice that setting any of the values above overrides Elixir’s default values. For example, setting :requires to [] will no longer automatically require the Kernel module. In the same way setting :macros will no longer auto-import Kernel macros like Kernel.if/2, Kernel.SpecialForms.case/2, and so on.

Returns a tuple of the form {value, binding}, where value is the value returned from evaluating string. If an error occurs while evaluating string an exception will be raised.

binding is a keyword list with the value of all variable bindings after evaluating string. The binding key is usually an atom, but it may be a tuple for variables defined in a different context.

Examples

iex> Code.eval_string("a + b", [a: 1, b: 2], file: __ENV__.file, line: __ENV__.line)
{3, [a: 1, b: 2]}

iex> Code.eval_string("c = a + b", [a: 1, b: 2], __ENV__)
{3, [a: 1, b: 2, c: 3]}

iex> Code.eval_string("a = a + b", [a: 1, b: 2])
{3, [a: 3, b: 2]}

For convenience, you can pass __ENV__/0 as the opts argument and all imports, requires and aliases defined in the current environment will be automatically carried over:

iex> Code.eval_string("a + b", [a: 1, b: 2], __ENV__)
{3, [a: 1, b: 2]}

format_file!(file, opts \\ [])

format_file!(binary(), keyword()) :: iodata()

Formats a file.

See format_string!/2 for more information on code formatting and available options.

format_string!(string, opts \\ [])

format_string!(binary(), keyword()) :: iodata()

Formats the given code string.

The formatter receives a string representing Elixir code and returns iodata representing the formatted code according to pre-defined rules.

Options

  • :file - the file which contains the string, used for error reporting

  • :line - the line the string starts, used for error reporting

  • :line_length - the line length to aim for when formatting the document. Defaults to 98.

  • :locals_without_parens - a keyword list of name and arity pairs that should be kept without parens whenever possible. The arity may be the atom :*, which implies all arities of that name. The formatter already includes a list of functions and this option augments this list.

  • :rename_deprecated_at - rename all known deprecated functions at the given version to their non-deprecated equivalent. It expects a valid Version which is usually the minimum Elixir version supported by the project.

Design principles

The formatter was designed under three principles.

First, the formatter never changes the semantics of the code by default. This means the input AST and the output AST are equivalent. Optional behaviour, such as :rename_deprecated_at, is allowed to break this guarantee.

The second principle is to provide as little configuration as possible. This eases the formatter adoption by removing contention points while making sure a single style is followed consistently by the community as a whole.

The formatter does not hard code names. The formatter will not behave specially because a function is named defmodule, def, etc. This principle mirrors Elixir’s goal of being an extensible language where developers can extend the language with new constructs as if they were part of the language. When it is absolutely necessary to change behaviour based on the name, this behaviour should be configurable, such as the :locals_without_parens option.

Keeping user’s formatting

The formatter respects the input format in some cases. Those are listed below:

  • Insignificant digits in numbers are kept as is. The formatter however always inserts underscores for decimal numbers with more than 5 digits and converts hexadecimal digits to uppercase

  • Strings, charlists, atoms and sigils are kept as is. No character is automatically escaped or unescaped. The choice of delimiter is also respected from the input

  • Newlines inside blocks are kept as in the input except for: 1) expressions that take multiple lines will always have an empty line before and after and 2) empty lines are always squeezed together into a single empty line

  • The choice between :do keyword and do/end blocks is left to the user

  • Lists, tuples, bitstrings, maps, structs and function calls will be broken into multiple lines if they are followed by a newline in the opening bracket and preceded by a new line in the closing bracket

  • Pipeline operators, like |> and others with the same precedence, will span multiple lines if they spanned multiple lines in the input

The behaviours above are not guaranteed. We may remove or add new rules in the future. The goal of documenting them is to provide better understanding on what to expect from the formatter.

Adjusting formatted output

The formatter attempts to the fit the most it can on a single line. When the code does not fit a single line, the formatter introduces line breaks in the code.

In some rare situations, this may lead to undesired formatting. For example, the code below:

"this is a very long string ... #{inspect(some_value)}"

may be formatted as:

"this is a very long string ... #{
  inspect(some_value)
}"

This happens because the only place the formatter can introduce a new line without changing the code semantics is in the interpolation. In those scenarios, we recommend developers to directly adjust the code. Here we can use the binary concatenation operator <>:

"this is a very long string " <>
  "... #{inspect(some_value)}"

The string concatenation makes the code fit on a single line and also gives more options to the formatter.

A similar example is when the formatter breaks a function definition over multiple clauses:

def my_function(
  %User{name: name, age: age, ...},
  arg1,
  arg2
) do

While the code above is completely valid, you may prefer to match on the struct variables inside the function body in order to keep the definition on a single line:

def my_function(%User{} = user, arg1, arg2) do
  %{name: name, age: age, ...} = user

Since the formatter cannot change the semantics of your code, sometimes it is necessary to tweak the code to get optimal formatting.

Multi-line lists, maps, tuples, etc

You can force lists, tuples, bitstrings, maps, structs and function calls to have one entry per line by adding a newline after the opening bracket and a new line before the closing bracket lines. For example:

[
  foo,
  bar
]

If there are no newlines around the brackets, then the formatter will try to fit everything on a single line, such that the snippet below

[foo,
 bar]

will be formatted as

[foo, bar]

You can also force function calls and keywords to be rendered on multiple lines by having each entry on its own line:

defstruct name: nil,
          age: 0

The code above will be kept with one keyword entry per line by the formatter. To avoid that, just squash everything into a single line.

Parens and no parens in function calls

Elixir has two syntaxes for function calls. With parens and no parens. By default, Elixir will add parens to all calls except for:

  1. calls that have do/end blocks
  2. local calls without parens where the name and arity of the local call is also listed under :locals_without_parens

The choice of parens and no parens also affects indentation. When a function call with parens doesn’t fit on the same line, the formatter introduces a newline around parens and indents the arguments with two spaces:

some_call(
  arg1,
  arg2,
  arg3
)

On the other hand, function calls without parens are always indented by the function call length itself, like this:

some_call arg1,
          arg2,
          arg3

If the last argument is a data structure, such as maps and lists, and the beginning of the data structure fits on the same line as the function call, then no indentation happens, this allows code like this:

Enum.reduce(some_collection, initial_value, fn element, acc ->
  # code
end)

some_funtion_without_parens %{
  foo: :bar,
  baz: :bat
}

Code comments

The formatter also handles code comments in a way to guarantee a space is always added between the beginning of the comment (#) and the next character.

The formatter also extracts all trailing comments to their previous line. For example, the code below

hello # world

will be rewritten to

# world
hello

Because code comments are handled apart from the code representation (AST), there are some situations where code comments are seen as ambiguous by the code formatter. For example, the comment in the anonymous function below

fn
  arg1 ->
    body1
    # comment

  arg2 ->
    body2
end

and in this one

fn
  arg1 ->
    body1

  # comment
  arg2 ->
    body2
end

are considered equivalent (the nesting is discarded alongside most of user formatting). In such cases, the code formatter will always format to the latter.

get_docs(module, kind)

get_docs(module(), :all) :: keyword() | nil
get_docs(module(), :type_docs) :: [{type, line, kind, doc}] | nil
when type: {atom(), arity()},
     line: pos_integer(),
     kind: atom(),
     doc: nil | false | binary()
get_docs(module(), :callback_docs) :: [{callback, line, kind, doc}] | nil
when callback: {atom(), arity()},
     line: pos_integer(),
     kind: atom(),
     doc: nil | false | binary()
get_docs(module(), :docs) :: [{function, line, kind, list(), doc}] | nil
when function: {atom(), arity()},
     line: pos_integer(),
     kind: atom(),
     doc: nil | false | binary()
get_docs(module(), :moduledoc) ::
  {line :: pos_integer(), doc :: false | binary()} | nil

Returns the docs for the given module.

When given a module name, it finds its BEAM code and reads the docs from it.

When given a path to a .beam file, it will load the docs directly from that file.

The return value depends on the kind value:

  • :moduledoc - tuple {line, doc} where line is the line on which the module definition starts and doc is the string attached to the module using the @moduledoc attribute, false if @moduledoc false was used, or nil if no @moduledoc was used.

  • :docs - list of all docstrings attached to functions and macros using the @doc attribute. Each tuple has the form {{name, arity}, line, kind, arguments, doc}. doc can be either a string, false if @doc false was used, or nil if no doc was used.

  • :callback_docs - list of all docstrings attached to @callbacks using the @doc attribute. Each tuple has the form {{name, arity}, line, kind, doc}. doc can be either a string or nil if no @doc was set.

  • :type_docs - list of all docstrings attached to @type callbacks using the @typedoc attribute. Each tuple has the form {{name, arity}, line, kind, doc}. doc can be either a string or nil if no @typedoc was used.

  • :all - a keyword list with :docs, :moduledoc, :callback_docs, and :type_docs.

If the module cannot be found, it returns nil.

Examples

# Module documentation of an existing module
iex> {_line, text} = Code.get_docs(Atom, :moduledoc)
iex> text |> String.split("\n") |> Enum.at(0)
"Convenience functions for working with atoms."

# A module that doesn't exist
iex> Code.get_docs(ModuleNotGood, :all)
nil

load_file(file, relative_to \\ nil)

load_file(binary(), nil | binary()) :: [{module(), binary()}]

Loads the given file.

Accepts relative_to as an argument to tell where the file is located. If the file was already required/loaded, loads it again.

It returns a list of tuples {ModuleName, bytecode}, one tuple for each module defined in the file.

Notice that if load_file/2 is invoked by different processes concurrently, the target file will be loaded concurrently many times. Check require_file/2 if you don’t want a file to be loaded concurrently.

Examples

modules = Code.load_file("eex_test.exs", "../eex/test")
List.first(modules)
#=> {EExTest.Compiled, <<70, 79, 82, 49, ...>>}

loaded_files()

loaded_files() :: [binary()]

Lists all loaded files.

Examples

Code.require_file("../eex/test/eex_test.exs")
List.first(Code.loaded_files()) =~ "eex_test.exs"
#=> true

prepend_path(path)

prepend_path(Path.t()) :: true | {:error, :bad_directory}

Prepends a path to the beginning of the Erlang VM code path list.

This is the list of directories the Erlang VM uses for finding module code.

The path is expanded with Path.expand/1 before being prepended. If this path does not exist, an error is returned.

Examples

Code.prepend_path(".")
#=> true

Code.prepend_path("/does_not_exist")
#=> {:error, :bad_directory}

require_file(file, relative_to \\ nil)

require_file(binary(), nil | binary()) :: [{module(), binary()}] | nil

Requires the given file.

Accepts relative_to as an argument to tell where the file is located. The return value is the same as that of load_file/2. If the file was already required or loaded, require_file/2 doesn’t do anything and returns nil.

Notice that if require_file/2 is invoked by different processes concurrently, the first process to invoke require_file/2 acquires a lock and the remaining ones will block until the file is available. This means that if require_file/2 is called more than one times with a given file, that file will be loaded only once. The first process to call require_file/2 will get the list of loaded modules, others will get nil.

Check load_file/2 if you want to load a file multiple times. See also unload_files/1.

Examples

If the code is already loaded, it returns nil:

Code.require_file("eex_test.exs", "../eex/test")
#=> nil

If the code is not loaded yet, it returns the same as load_file/2:

modules = Code.require_file("eex_test.exs", "../eex/test")
List.first(modules)
#=> {EExTest.Compiled, <<70, 79, 82, 49, ...>>}

string_to_quoted(string, opts \\ [])

string_to_quoted(List.Chars.t(), keyword()) ::
  {:ok, Macro.t()} | {:error, {line :: pos_integer(), term(), term()}}

Converts the given string to its quoted form.

Returns {:ok, quoted_form} if it succeeds, {:error, {line, error, token}} otherwise.

Options

  • :file - the filename to be reported in case of parsing errors. Defaults to “nofile”.

  • :line - the starting line of the string being parsed. Defaults to 1.

  • :columns - when true, attach a :column key to the quoted metadata. Defaults to false.

  • :existing_atoms_only - when true, raises an error when non-existing atoms are found by the tokenizer. Defaults to false.

Macro.to_string/2

The opposite of converting a string to its quoted form is Macro.to_string/2, which converts a quoted form to a string/binary representation.

string_to_quoted!(string, opts \\ [])

string_to_quoted!(List.Chars.t(), keyword()) :: Macro.t()

Converts the given string to its quoted form.

It returns the ast if it succeeds, raises an exception otherwise. The exception is a TokenMissingError in case a token is missing (usually because the expression is incomplete), SyntaxError otherwise.

Check string_to_quoted/2 for options information.

unload_files(files)

unload_files([binary()]) :: :ok

Removes files from the loaded files list.

The modules defined in the file are not removed; calling this function only removes them from the list, allowing them to be required again.

Examples

# Load EEx test code, unload file, check for functions still available
Code.load_file("../eex/test/eex_test.exs")

Code.unload_files(Code.loaded_files())
function_exported?(EExTest.Compiled, :before_compile, 0)
#=> true

© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.6.6/Code.html