Код
Утилиты для управления компиляцией кода, оценкой кода и загрузкой кода.
Этот модуль дополняет модуль Erlang’s :code, добавляя поведение, специфичное для Elixir. Почти все функции в этом модуле оказывают глобальное влияние на поведение Elixir.
Работа с файлами
Этот модуль содержит три функции для компиляции и оценки файлов. Вот краткое описание их и их поведения:
-
require_file/2- компилирует файл и отслеживает его имя. Он не компилирует файл повторно, если он уже был запрошен. -
compile_file/2- компилирует файл без отслеживания его имени. Компилирует файл несколько раз при многократном вызове. -
eval_file/2- оценивает содержимое файла без отслеживания его имени. Возвращает результат последнего выражения в файле вместо определённых в нём модулей.
Вкратце, первую функцию нужно использовать, когда вы хотите отслеживать файлы, обрабатываемые системой, чтобы избежать повторной компиляции одного и того же файла. Это часто используется в скриптах.
compile_file/2 необходимо использовать, когда вы заинтересованы в модулях, определённых в файле, без отслеживания. eval_file/2 следует использовать, когда вы заинтересованы в результате оценки файла, а не в определённых в нём модулях.
Обзор
Функции
- append_path(path)
-
Добавляет путь в конец списка путей кода Erlang VM.
- available_compiler_options()
-
Возвращает список доступных опций компилятора.
- compile_file(file, relative_to \\ nil)
-
Компилирует заданный файл.
- compile_quoted(quoted, file \\ "nofile")
-
Компилирует выражение в виде строки.
- compile_string(string, file \\ "nofile")
-
Компилирует заданную строку.
- compiler_options()
-
Получает параметры компиляции из сервера кода.
- compiler_options(opts)
-
Устанавливает параметры компиляции.
- delete_path(path)
-
Удаляет путь из списка путей кода Erlang VM. Это список каталогов, используемых Erlang VM для поиска кода модулей.
- ensure_compiled(module)
-
Гарантирует, что указанный модуль скомпилирован и загружен.
- ensure_compiled?(module)
-
Гарантирует, что указанный модуль скомпилирован и загружен.
- ensure_loaded(module)
-
Гарантирует, что указанный модуль загружен.
- ensure_loaded?(module)
-
Гарантирует, что указанный модуль загружен.
- eval_file(file, relative_to \\ nil)
-
Вычисляет заданный файл.
- eval_quoted(quoted, binding \\ [], opts \\ [])
-
Вычисляет содержимое в виде строки.
- eval_string(string, binding \\ [], opts \\ [])
-
Вычисляет содержимое, заданное
string - fetch_docs(module)
-
Возвращает документацию для данного модуля.
- format_file!(file, opts \\ [])
-
Форматирует файл.
- format_string!(string, opts \\ [])
-
Форматирует данный код
string - get_docs(module, kind) устаревший
-
Устаревшая функция для получения старого формата документации.
- prepend_path(path)
-
Добавляет путь в начало списка путей кода Erlang VM.
- purge_compiler_modules()
-
Очистка модулей компилятора.
- require_file(file, relative_to \\ nil)
-
Загружает заданный
file - required_files()
-
Список всех загруженных файлов.
- string_to_quoted!(string, opts \\ [])
-
Преобразует данную строку в её строковое представление.
- string_to_quoted(string, opts \\ [])
-
Преобразует данную строку в её строковое представление.
- unrequire_files(files)
-
Удаляет файлы из списка загруженных файлов.
Функции
append_path(path)
append_path(Path.t()) :: true | {:error, :bad_directory} Добавляет путь в конец списка путей кода Erlang VM.
Это список каталогов, используемых Erlang VM для поиска кода модулей.
Путь расширяется с помощью Path.expand/1 перед добавлением. Если такого пути не существует, возвращается ошибка.
Примеры
Code.append_path(".")
#=> true
Code.append_path("/does_not_exist")
#=> {:error, :bad_directory} available_compiler_options()
available_compiler_options() :: [atom()]
Возвращает список доступных опций компилятора.
См. compiler_options/1 для получения дополнительной информации.
Примеры
iex> Code.available_compiler_options() [:docs, :debug_info, :ignore_module_conflict, :relative_paths, :warnings_as_errors]
compile_file(file, relative_to \\ nil)
compile_file(binary(), nil | binary()) :: [{module(), binary()}] Компилирует заданный файл.
Принимает relative_to в качестве аргумента, чтобы указать, где находится файл.
Возвращает список кортежей, где первый элемент — имя модуля, а второй — его байткод (как бинарное значение). В отличие от require_file/2, он не отслеживает имя файла скомпилированного файла.
Если вы хотите получить результат оценки файла, а не модулей, определённых в нём, см. eval_file/2.
Для одновременной компиляции нескольких файлов см. Kernel.ParallelCompiler.compile/2.
compile_quoted(quoted, file \\ "nofile")
compile_quoted(Macro.t(), binary()) :: [{module(), binary()}] Компилирует выражение в виде строки.
Возвращает список кортежей, где первый элемент — имя модуля, а второй — его байткод (как бинарное значение). В качестве второго аргумента может быть передан file, который будет использоваться для отчётности о предупреждениях и ошибках.
compile_string(string, file \\ "nofile")
compile_string(List.Chars.t(), binary()) :: [{module(), binary()}] Компилирует заданную строку.
Возвращает список кортежей, где первый элемент — имя модуля, а второй — его байткод (как бинарное значение). В качестве второго аргумента может быть передан file, который будет использоваться для отчётности о предупреждениях и ошибках.
Предупреждение: string может содержать любой код Elixir, и код может быть выполнен с такими же правами, как и у Erlang VM: это означает, что такой код может представлять угрозу для машины (например, выполняя системные команды). Не используйте compile_string/2 с недоверенным вводом (например, строками, полученными из сети).
compiler_options()
compiler_options() :: %{optional(atom()) => boolean()} Получает параметры компиляции из сервера кода.
См. compiler_options/1 для получения дополнительной информации.
Примеры
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()} Устанавливает параметры компиляции.
Эти параметры являются глобальными, так как хранятся сервером кода Elixir.
Доступные параметры:
-
:docs- когдаtrue, сохраняет документацию в скомпилированном модуле. По умолчаниюtrue. -
:debug_info- когдаtrue, сохраняет отладочную информацию в скомпилированном модуле. Это позволяет разработчику восстановить исходный код. По умолчаниюfalse. -
:ignore_module_conflict- когдаtrue, перезаписывает уже определённые модули без генерирования ошибок. По умолчаниюfalse. -
:relative_paths- когдаtrue, использовать относительные пути в цитируемых узлах, предупреждениях и ошибках, сгенерированных компилятором. Обратите внимание, что отключение этого параметра не повлияет на предупреждения и ошибки во время выполнения. По умолчаниюtrue. -
:warnings_as_errors- вызывает отказ компиляции при появлении предупреждений. По умолчаниюfalse.
Возвращает новую карту параметров компиляции.
Примеры
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()
Удаляет путь из списка путей кода Erlang VM. Это список каталогов, используемых Erlang VM для поиска кода модулей.
Путь расширяется с помощью Path.expand/1 перед удалением. Если путь не существует, эта функция возвращает false.
Примеры
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} Обеспечивает компиляцию и загрузку указанного модуля.
Если модуль уже загружен, функция работает как no-op. Если модуль ещё не загружен, он проверяет, нужно ли его сначала скомпилировать, а затем пытается загрузить.
Если загрузка модуля проходит успешно, она возвращает {:module, module}. В противном случае возвращает {:error, reason} с причиной ошибки.
См. ensure_loaded/1 для получения дополнительной информации о загрузке модулей и о том, когда использовать ensure_loaded/1 или ensure_compiled/1.
ensure_compiled?(module)
ensure_compiled?(module()) :: boolean()
Обеспечивает компиляцию и загрузку указанного модуля.
Аналогично ensure_compiled/1, но возвращает true , если модуль уже загружен или был успешно загружен и скомпилирован. В противном случае возвращает false.
ensure_loaded(module)
ensure_loaded(module()) ::
{:module, module()}
| {:error, :embedded | :badfile | :nofile | :on_load_failure} Обеспечивает загрузку указанного модуля.
Если модуль уже загружен, эта функция работает как no-op. Если модуль ещё не загружен, она пытается загрузить его.
Если загрузка модуля проходит успешно, она возвращает {:module, module}. В противном случае возвращает {:error, reason} с причиной ошибки.
Загрузка кода в Erlang VM
Erlang имеет два режима загрузки кода: интерактивный и встроенный.
По умолчанию Erlang VM работает в интерактивном режиме, где модули загружаются по мере необходимости. Встроенном режиме происходит обратное: все модули должны быть загружены заранее или явно.
Поэтому эта функция используется для проверки загрузки модуля перед его использованием и позволяет соответствующим образом реагировать. Например, модуль URI использует эту функцию для проверки наличия определённого парсера для заданной схемы URI.
ensure_compiled/1
В Elixir также есть функция ensure_compiled/1, которая является расширением ensure_loaded/1.
Поскольку компиляция в Elixir происходит параллельно, в некоторых ситуациях может потребоваться использовать модуль, который ещё не был скомпилирован, поэтому его нельзя загрузить.
При вызове ensure_compiled/1 приостанавливает компиляцию вызывающего кода до тех пор, пока модуль, переданный в ensure_compiled/1, не станет доступен или пока не будут скомпилированы все файлы для текущего проекта. Если компиляция завершится, а модуль не будет доступен, возвращается кортеж ошибки.
ensure_compiled/1 не относится к зависимостям, так как зависимости должны быть скомпилированы заранее.
В большинстве случаев достаточно ensure_loaded/1. ensure_compiled/1 необходимо использовать в редких случаях, обычно связанных с макросами, которые требуют вызова модуля для получения информации о колбэках.
Примеры
iex> Code.ensure_loaded(Atom)
{:module, Atom}
iex> Code.ensure_loaded(DoesNotExist)
{:error, :nofile} ensure_loaded?(module)
ensure_loaded?(module()) :: boolean()
Обеспечивает загрузку указанного модуля.
Аналогично ensure_loaded/1, но возвращает true , если модуль уже загружен или был успешно загружен. В противном случае возвращает false.
Примеры
iex> Code.ensure_loaded?(Atom) true
eval_file(file, relative_to \\ nil)
eval_file(binary(), nil | binary()) :: {term(), binding :: list()} Выполняет заданный файл.
Принимает relative_to в качестве аргумента, чтобы указать местоположение файла.
В то время как require_file/2 и compile_file/2 возвращают загруженные модули и их байткод, eval_file/2 просто выполняет содержимое файла и возвращает результат выполнения и его привязки (именно такое же значение возврата, как у eval_string/3).
eval_quoted(quoted, binding \\ [], opts \\ [])
eval_quoted(Macro.t(), list(), Macro.Env.t() | keyword()) ::
{term(), binding :: list()} Выполняет цитируемое содержимое.
Предупреждение: Вызов этой функции внутри макроса считается плохой практикой, поскольку она попытается выполнить значения времени выполнения во время компиляции. Аргументы макросов обычно преобразуются в возвращаемые цитируемые выражения (вместо оценки).
См. eval_string/3 для описания привязок и параметров.
Примеры
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]} Для удобства вы можете передать __ENV__/0 в качестве аргумента opts и все параметры будут автоматически извлечены из текущей среды:
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()} Выполняет содержимое, заданное string.
Аргумент binding представляет собой список ключевых слов переменных привязок. Аргумент opts - список ключевых слов параметров среды.
Предупреждение: string может быть любым кодом Elixir и будет выполняться с теми же правами, что и Erlang VM: это означает, что такой код может скомпрометировать машину (например, выполнив системные команды). Не используйте eval_string/3 с недоверенным вводом (например, строками, полученными из сети).
Параметры
Параметры могут быть:
-
:file- файл, который будет рассматриваться при выполнении -
:line- строка, в которой начинается сценарий
Кроме того, следующие значения области могут быть настроены:
-
:aliases- список кортежей с псевдонимом и его целевым объектом -
:requires- список необходимых модулей -
:functions- список кортежей, где первый элемент — модуль, а второй — список импортированных имён функций и их аритей; список имён функций и аритей должен быть отсортирован -
:macros- список кортежей, где первый элемент — модуль, а второй — список импортированных имён макросов и их аритей; список имён макросов и аритей должен быть отсортирован
Обратите внимание, что установка любого из вышеперечисленных значений переопределяет значения по умолчанию Elixir. Например, установка :requires на [] больше не будет автоматически требовать модуль Kernel. Аналогично, установка :macros больше не будет автоматически импортировать макросы Kernel, такие как Kernel.if/2, Kernel.SpecialForms.case/2 и т. д.
Возвращает кортеж вида {value, binding}, где value - значение, возвращаемое при выполнении string. Если при выполнении string произойдёт ошибка, будет поднято исключение.
binding - список ключевых слов с значениями всех привязок переменных после выполнения string. Ключ привязки обычно представляет собой атом, но может быть кортежем для переменных, определённых в другом контексте.
Примеры
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]} Для удобства вы можете передать __ENV__/0 в качестве аргумента opts и все импорты, требования и псевдонимы, определённые в текущей среде, будут автоматически перенесены:
iex> Code.eval_string("a + b", [a: 1, b: 2], __ENV__)
{3, [a: 1, b: 2]} fetch_docs(module) (since 1.7.0)
fetch_docs(module() | String.t()) ::
{:docs_v1, anno, beam_language, format, module_doc :: doc, metadata,
docs :: [{{kind, name, arity()}, anno, signature, doc, metadata}]}
| {:error, :module_not_found | :chunk_not_found | {:invalid_chunk, binary()}}
| future_formats
when anno: :erl_anno.anno(),
beam_language: atom(),
format: binary(),
doc: %{optional(binary()) => binary()} | :none | :hidden,
kind: atom(),
name: atom(),
signature: [binary()],
metadata: map(),
future_formats: term() Возвращает документацию для указанного модуля.
При указании имени модуля ищет его код BEAM и считывает документацию из него.
При указании пути к файлу .beam загрузит документацию непосредственно из этого файла.
Возвращает значение, хранящееся в блоке документации в формате, определённом в EEP 48, или {:error, reason} , если блок не доступен.
Примеры
# Module documentation of an existing module
iex> {:docs_v1, _, :elixir, _, %{"en" => module_doc}, _, _} = Code.fetch_docs(Atom)
iex> module_doc |> String.split("\n") |> Enum.at(0)
"Convenience functions for working with atoms."
# A module that doesn't exist
iex> Code.fetch_docs(ModuleNotGood)
{:error, :module_not_found} format_file!(file, opts \\ []) (since 1.6.0)
format_file!(binary(), keyword()) :: iodata()
Форматирует файл.
См. format_string!/2 для получения дополнительной информации о форматировании кода и доступных параметрах.
format_string!(string, opts \\ []) (since 1.6.0)
format_string!(binary(), keyword()) :: iodata()
Форматирует предоставленный код string.
Форматировщик получает строку, представляющую код Elixir, и возвращает iodata, представляющую отформатированный код в соответствии с предопределёнными правилами.
Параметры
-
:file- файл, содержащий строку, используемый для вывода сообщений об ошибках -
:line- строка, с которой начинается строка, используемый для вывода сообщений об ошибках -
:line_length- длина строки, к которой следует стремиться при форматировании документа. По умолчанию 98. Это значение используется как ссылка, но не навязывается форматировщиком, так как иногда требуется вмешательство пользователя. См. раздел «Запуск форматировщика» -
:locals_without_parens- список пар имён и аритей, которые следует сохранять без скобок, когда это возможно. Аритей может быть атомом:*, что подразумевает все аритеты этого имени. Форматировщик уже включает список функций, а этот параметр дополняет этот список. -
:rename_deprecated_at- переименовать все известные устаревшие функции на указанной версии в их не устаревшие аналоги. Ожидает действительнуюVersion, которая обычно является минимальной версией Elixir, поддерживаемой проектом.
Принципы проектирования
Форматировщик был разработан на основе трёх принципов.
Вначале форматировщик по умолчанию никогда не изменяет семантики кода. Это означает, что входное и выходное AST эквивалентны. Дополнительное поведение, такое как :rename_deprecated_at, может нарушить это гарантию.
Второй принцип заключается в предоставлении минимального количества настроек. Это облегчает принятие форматировщика, устраняя точки разногласий, обеспечивая при этом, что один стиль последовательно соблюдается всем сообществом.
Форматировщик не жестко кодирует имена. Форматировщик не будет вести себя особым образом, потому что функция называется defmodule, def, и т. д. Этот принцип отражает цель Elixir быть расширяемым языком, где разработчики могут расширять язык новыми конструкциями, как если бы они были частью языка. Когда абсолютно необходимо изменить поведение на основе имени, это поведение должно быть настраиваемым, например, опция :locals_without_parens.
Выполнение форматировщика
Форматировщик пытается уместить как можно больше на одной строке и вводит разрывы строк там, где это возможно, когда он не может.
В некоторых случаях это может привести к нежелательному форматированию. Поэтому некоторый код, сгенерированный форматировщиком, может быть не эстетичным и может потребовать явного вмешательства разработчика. Вот почему мы не рекомендуем слепо запускать форматировщик в существующей базе кода. Вместо этого вы должны отформатировать и проверить каждый отформатированный файл.
Давайте рассмотрим некоторые примеры. Следующий код:
"this is a very long string ... #{inspect(some_value)}" может быть отформатирован как:
"this is a very long string ... #{
inspect(some_value)
}" Это происходит, потому что единственное место, где форматировщик может вставить новую строку без изменения семантики кода, находится в интерполяции. В таких сценариях мы рекомендуем разработчикам напрямую корректировать код. Здесь мы можем использовать бинарный оператор конкатенации <>/2:
"this is a very long string " <>
"... #{inspect(some_value)}" Конкатенация строк позволяет коду уместиться на одной строке и также предоставляет больше возможностей для форматировщика.
Аналогичный пример — когда форматировщик разбивает определение функции на несколько пунктов:
def my_function(
%User{name: name, age: age, ...},
arg1,
arg2
) do
...
end Хотя приведенный выше код полностью верен, вы можете предпочесть сопоставить переменные структуры внутри тела функции, чтобы сохранить определение на одной строке:
def my_function(%User{} = user, arg1, arg2) do
%{name: name, age: age, ...} = user
...
end В некоторых ситуациях вы можете использовать тот факт, что форматировщик не генерирует элегантный код, как подсказку для рефакторинга. Рассмотрим этот код:
def board?(board_id, %User{} = user, available_permissions, required_permissions) do
Tracker.OrganizationMembers.user_in_organization?(user.id, board.organization_id) and
required_permissions == Enum.to_list(MapSet.intersection(MapSet.new(required_permissions), MapSet.new(available_permissions)))
end В приведенном выше коде очень длинные строки, и запуск форматировщика не решит эту проблему. На самом деле, форматировщик может сделать более очевидным, что у вас есть сложные выражения:
def board?(board_id, %User{} = user, available_permissions, required_permissions) do
Tracker.OrganizationMembers.user_in_organization?(user.id, board.organization_id) and
required_permissions ==
Enum.to_list(
MapSet.intersection(
MapSet.new(required_permissions),
MapSet.new(available_permissions)
)
)
end Рассматривайте такие случаи как подсказку, что ваш код следует переработать:
def board?(board_id, %User{} = user, available_permissions, required_permissions) do
Tracker.OrganizationMembers.user_in_organization?(user.id, board.organization_id) and
matching_permissions?(required_permissions, available_permissions)
end
defp matching_permissions?(required_permissions, available_permissions) do
intersection =
required_permissions
|> MapSet.new()
|> MapSet.intersection(MapSet.new(available_permissions))
|> Enum.to_list()
required_permissions == intersection
end Подводя итог: поскольку форматировщик не может изменить семантику вашего кода, иногда необходимо внести коррективы или переработать код, чтобы получить оптимальное форматирование. Чтобы лучше понять, как управлять форматировщиком, в следующих разделах мы опишем случаи, когда форматировщик сохраняет кодировку пользователя и как управлять многострочными выражениями.
Сохранение форматирования пользователя
Форматировщик в некоторых случаях учитывает входной формат. Эти случаи перечислены ниже:
-
Незначительные цифры в числах сохраняются как есть. Однако форматировщик всегда вставляет подчеркивания для десятичных чисел с более чем 5 цифрами и преобразует шестнадцатеричные цифры в верхний регистр
-
Строки, списки символов, атомы и сигилы сохраняются как есть. Ни один символ автоматически не экранируется или не экранируется. Выбор разделителя также сохраняется из входных данных
-
Новые строки внутри блоков сохраняются как во входных данных, за исключением: 1) выражения, занимающие несколько строк, всегда будут иметь пустую строку перед и после, и 2) пустые строки всегда объединяются в одну пустую строку
-
Выбор между
:doключевым словом иdo/endблоками предоставляется пользователю -
Списки, кортежи, битовые строки, карты, структуры и вызовы функций будут разбиты на несколько строк, если за открывающей скобкой следует новая строка, а перед закрывающей скобкой — новая строка
-
Операторы конвейера, такие как
|>и другие с таким же приоритетом, будут занимать несколько строк, если они занимали несколько строк на входе
Вышеперечисленные поведения не гарантируются. В будущем мы можем удалить или добавить новые правила. Цель документирования их состоит в том, чтобы предоставить лучшее понимание того, чего ожидать от форматировщика.
Многострочные списки, карты, кортежи и т. д.
Вы можете принудительно сделать так, чтобы списки, кортежи, битовые строки, карты, структуры и вызовы функций имели по одному элементу на строке, добавив новую строку после открывающей скобки и новую строку перед закрывающей скобкой. Например:
[ foo, bar ]
Если вокруг скобок нет новых строк, форматировщик попытается уместить все на одной строке, так что фрагмент кода ниже
[foo, bar]
будет отформатирован как
[foo, bar]
Вы также можете принудительно сделать так, чтобы вызовы функций и ключевые слова отображались на нескольких строках, поместив каждый элемент на отдельную строку:
defstruct name: nil,
age: 0 Форматировщик сохранит приведенный выше код с одним элементом ключевого слова на строке. Чтобы этого избежать, просто объедините все в одну строку.
Скобки и отсутствие скобок в вызовах функций
В Elixir есть два синтаксиса для вызовов функций: со скобками и без них. По умолчанию Elixir добавит скобки ко всем вызовам, за исключением:
- вызовов, имеющих блоки do/end
- локальных вызовов без скобок, где имя и арность локального вызова также перечислены в
:locals_without_parens(за исключением вызовов с арностью 0, где компилятор всегда требует скобок)
Выбор скобок и отсутствие скобок также влияет на отступы. Когда вызов функции со скобками не помещается на одной строке, форматировщик вставляет новую строку вокруг скобок и отступает аргументы на два пробела:
some_call( arg1, arg2, arg3 )
С другой стороны, вызовы функций без скобок всегда отступают на длину самого вызова функции, как это:
some_call arg1,
arg2,
arg3 Если последний аргумент является структурой данных, например, картами и списками, и начало структуры данных помещается на одной строке с вызовом функции, то отступ не происходит, что позволяет написать код такого вида:
Enum.reduce(some_collection, initial_value, fn element, acc ->
# code
end)
some_function_without_parens %{
foo: :bar,
baz: :bat
} Комментарии к коду
Форматировщик также обрабатывает комментарии к коду таким образом, чтобы гарантировать, что пробел всегда добавляется между началом комментария (#) и следующим символом.
Форматировщик также выносит все заключительные комментарии на предыдущую строку. Например, приведенный ниже код
hello #world
будет переписан как
# world hello
Поскольку комментарии к коду обрабатываются отдельно от представления кода (AST), в некоторых ситуациях форматировщик кода может рассматривать комментарии к коду как неоднозначные. Например, комментарий в анонимной функции ниже
fn
arg1 ->
body1
# comment
arg2 ->
body2
end и в этом
fn
arg1 ->
body1
# comment
arg2 ->
body2
end считаются эквивалентными (вложенность отбрасывается вместе с большей частью форматирования пользователем). В таких случаях форматировщик кода всегда форматирует последний вариант.
get_docs(module, kind)
get_docs(module(), :moduledoc | :docs | :callback_docs | :type_docs | :all) :: nilЭта функция устарела. Code.get_docs/2 всегда возвращает nil, так как устаревшая документация больше не хранится в файлах BEAM. Используйте Code.fetch_docs/1 вместо этого.
Устаревшая функция для получения старого формата документации.
Elixir v1.7 использует EEP 48, который представляет собой новый формат документации, предназначенный для совместного использования во всех языках BEAM. Старый формат, используемый Code.get_docs/2, больше недоступен, и поэтому эта функция всегда возвращает nil. Используйте Code.fetch_docs/1 вместо этого.
prepend_path(path)
prepend_path(Path.t()) :: true | {:error, :bad_directory} Добавляет путь в начало списка путей кода виртуальной машины Erlang.
Это список каталогов, которые виртуальная машина Erlang использует для поиска кода модулей.
Путь расширяется с помощью Path.expand/1 перед добавлением в начало. Если такого пути не существует, возвращается ошибка.
Примеры
Code.prepend_path(".")
#=> true
Code.prepend_path("/does_not_exist")
#=> {:error, :bad_directory} purge_compiler_modules() (since 1.7.0)
purge_compiler_modules() :: {:ok, non_neg_integer()} Очистка модулей компилятора.
Компилятор использует временные модули для компиляции кода. Например, elixir_compiler_1, elixir_compiler_2, и т. д. В случае, если скомпилированный код содержит ссылки на анонимные функции или подобные, компилятор Elixir может не иметь возможности освободить эти модули, оставляя ненужный код в памяти и в конечном итоге приводя к модулям, таким как elixir_compiler_12345.
Эта функция очищает все модули, в настоящее время используемые компилятором, что позволяет повторно использовать старые имена модулей компилятора. Если какие-либо процессы выполняют код из таких модулей, они также будут завершены.
Возвращает {:ok, number_of_modules_purged}.
require_file(file, relative_to \\ nil)
require_file(binary(), nil | binary()) :: [{module(), binary()}] | nil Загружает указанный file.
Принимает relative_to в качестве аргумента, чтобы указать расположение файла. Если файл уже загружен, require_file/2 ничего не делает и возвращает nil.
Обратите внимание, что если require_file/2 вызывается разными процессами одновременно, первый процесс, вызывающий require_file/2, получает блокировку, а остальные будут блокироваться до тех пор, пока файл не станет доступен. Это означает, что если require_file/2 вызывается более одного раза с заданным файлом, этот файл будет скомпилирован только один раз. Первый процесс, вызвавший require_file/2, получит список загруженных модулей, другие получат nil.
См. compile_file/2, если вы хотите скомпилировать файл без отслеживания его имен файлов. Наконец, если вы хотите получить результат вычисления файла, а не модулей, определенных в нем, см. eval_file/2.
Примеры
Если файл не загружен, возвращает список модулей:
modules = Code.require_file("eex_test.exs", "../eex/test")
List.first(modules)
#=> {EExTest.Compiled, <<70, 79, 82, 49, ...>>} Если код был загружен, возвращает nil:
Code.require_file("eex_test.exs", "../eex/test")
#=> nil required_files() (since 1.7.0)
required_files() :: [binary()]
Список всех загруженных файлов.
Примеры
Code.require_file("../eex/test/eex_test.exs")
List.first(Code.required_files()) =~ "eex_test.exs"
#=> true string_to_quoted!(string, opts \\ [])
string_to_quoted!(List.Chars.t(), keyword()) :: Macro.t()
Преобразует заданную строку в её строковое представление.
Возвращает ast, если преобразование успешно, иначе генерирует исключение. Исключение — TokenMissingError в случае отсутствия токена (обычно, потому что выражение неполное), SyntaxError в противном случае.
См. string_to_quoted/2 для информации об опциях.
string_to_quoted(string, opts \\ [])
string_to_quoted(List.Chars.t(), keyword()) ::
{:ok, Macro.t()} | {:error, {line :: pos_integer(), term(), term()}} Преобразует заданную строку в её строковое представление.
Возвращает {:ok, quoted_form} при успехе, {:error, {line, error, token}} в противном случае.
Опции
-
:file— имя файла, которое будет указано в случае ошибок при разборе. По умолчанию «nofile». -
:line— начальная строка разбираемой строки. По умолчанию 1. -
:columns— приtrue, добавить:columnключ к метаданным цитирования. По умолчаниюfalse. -
:existing_atoms_only— приtrue, генерировать ошибку при обнаружении не существующих атомов токенизатором. По умолчаниюfalse. -
:warn_on_unnecessary_quotes— приfalse, не предупреждать при наличии лишних кавычек у атомов, ключевых слов или вызовов. По умолчаниюtrue.
Macro.to_string/2
Обратным преобразованием строки в её строковое представление является Macro.to_string/2, которое преобразует строковое представление в строку/двоичное представление.
unrequire_files(files) (since 1.7.0)
unrequire_files([binary()]) :: :ok
Удаляет файлы из списка требуемых файлов.
Модули, определённые в файле, не удаляются; вызов этой функции только удаляет их из списка, позволяя их повторно потребовать.
Примеры
# Require EEx test code
Code.require_file("../eex/test/eex_test.exs")
# Now unrequire all files
Code.unrequire_files(Code.required_files())
# Notice modules are still available
function_exported?(EExTest.Compiled, :before_compile, 0)
#=> true
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.7.4/Code.html