Spec-Zone.ru › Elixir 1.8

Код

Утилиты для управления компиляцией кода, оценкой кода и загрузкой кода.

Этот модуль дополняет 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_or_path)

Возвращает документацию для данного модуля или пути к файлу .beam.

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_or_path)

(since 1.7.0)
fetch_docs(module() | String.t()) ::
  {:docs_v1, annotation, beam_language, format, module_doc :: doc_content,
   metadata, docs :: [doc_element]}
  | {:error, :module_not_found | :chunk_not_found | {:invalid_chunk, binary()}}
when annotation: :erl_anno.anno(),
     beam_language: :elixir | :erlang | :lfe | :alpaca | atom(),
     doc_content: %{optional(binary()) => binary()} | :none | :hidden,
     doc_element:
       {{kind :: atom(), function_name :: atom(), arity()}, annotation,
        signature, doc_content, metadata},
     format: binary(),
     signature: [binary()],
     metadata: map()

Возвращает документацию для данного модуля или пути к файлу .beam.

При передаче имени модуля она находит его 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 добавляет скобки ко всем вызовам, за исключением:

  1. вызовов, содержащих блоки do/end
  2. локальных вызовов без скобок, где имя и арность локального вызова также перечислены в :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 VM использует для поиска модулей кода.

Путь расширяется с помощью 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()) ::
  {: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, которая преобразует строковое представление в строку/двоичное представление.

string_to_quoted!(string, opts \\ [])

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

Преобразует заданную строку в её строковое представление.

Возвращает ast при успехе, в противном случае генерирует исключение. Исключением является TokenMissingError в случае отсутствия токена (обычно, потому что выражение неполное), SyntaxError в остальных случаях.

См. string_to_quoted/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.8.2/Code.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API