Код
Утилиты для управления компиляцией кода, оценкой кода и загрузкой кода.
Этот модуль дополняет Erlang's :code модуль, добавляя поведение, специфичное для Elixir. Для функций по манипулированию AST Elixir (а не его оценке), см. Macro модуль.
Работа с файлами
Этот модуль содержит три функции для компиляции и оценки файлов. Вот краткое описание их и поведения:
require_file/2- компилирует файл и отслеживает его имя. Он не компилирует файл повторно, если он уже был запрошен ранее.compile_file/2- компилирует файл без отслеживания его имени. Компилирует файл многократно при каждом вызове.eval_file/2- оценивает содержимое файла без отслеживания его имени. Возвращает результат последнего выражения в файле, вместо определённых в нём модулей. Оцениваемые файлы не вызывают отслеживатели компиляции, описанные в следующем разделе.
Вкратце, первую функцию нужно использовать, когда требуется отслеживать файлы, обрабатываемые системой, чтобы избежать повторной компиляции одного и того же файла. Это часто используется в скриптах.
compile_file/2 нужно использовать, когда вы заинтересованы в определённых в файле модулях без отслеживания. eval_file/2 следует использовать, когда вы заинтересованы в результате оценки файла, а не в определённых в нём модулях.
Перечисленные выше функции работают с исходным кодом Elixir. Если вы хотите работать с модулями, скомпилированными в байткод, имеющими расширение .beam и обычно находящимися в каталоге _build проекта Mix, см. функции в Erlang's :code модуле.
Загрузка кода в Erlang VM
Erlang имеет два режима загрузки кода: интерактивный и встроенный.
По умолчанию, Erlang VM работает в интерактивном режиме, где модули загружаются по мере необходимости. Во встроенном режиме происходит обратное, так как все модули должны быть загружены заранее или явно.
Вы можете использовать ensure_loaded/1 (а также ensure_loaded?/1 и ensure_loaded!/1), чтобы проверить, загружен ли модуль перед его использованием и выполнить действия.
ensure_compiled/1 и ensure_compiled!/1
Elixir также включает ensure_compiled/1 и ensure_compiled!/1 функции, которые являются надмножеством ensure_loaded/1.
Поскольку компиляция в Elixir происходит параллельно, в некоторых ситуациях вам может потребоваться использовать модуль, который ещё не был скомпилирован, поэтому его даже нельзя загрузить.
При вызове ensure_compiled/1 и ensure_compiled!/1 приостанавливается компиляция вызывающего элемента до тех пор, пока модуль не станет доступным. Обратите внимание на важное различие между ensure_compiled/1 и ensure_compiled!/1: если вы используете ensure_compiled!/1, вы указываете компилятору, что можете продолжить только в том случае, если указанный модуль доступен.
Если вы используете Code.ensure_compiled/1, вы предполагаете, что можете продолжить без модуля, и поэтому Elixir может вернуть {:error, :unavailable} в случаях, когда модуль ещё не доступен (но может стать доступным позже).
По этим причинам разработчики обычно используют Code.ensure_compiled!/1. В частности, не делайте этого:
case Code.ensure_compiled(module) do
{:module, _} -> module
{:error, _} -> raise ...
end
Наконец, обратите внимание, что вам нужна только ensure_compiled!/1, чтобы проверить определение модулей в рамках того же проекта. Она не применяется к модулям из зависимостей, так как зависимости всегда компилируются заранее.
В большинстве случаев ensure_loaded/1 достаточно. ensure_compiled!/1 нужно использовать в редких случаях, обычно связанных с макросами, которые требуют вызова модуля для информации о обратных вызовах. Использование ensure_compiled/1 ещё реже.
Отслеживатели компиляции
Elixir поддерживает отслеживатели компиляции, которые позволяют модулям наблюдать за конструкциями, обрабатываемыми компилятором Elixir при компиляции файлов. Отслеживатель — это модуль, реализующий функцию trace/2. Функция получает имя события в качестве первого аргумента и Macro.Env в качестве второго и должна вернуть :ok. Очень важно, чтобы отслеживатель выполнял как можно меньше работы синхронно и передавал основную работу в отдельный процесс. Медленные отслеживатели замедлять компиляцию.
Вы можете настроить список отслеживателей с помощью put_compiler_option/2. Следующие события доступны для отслеживателей:
-
:start- (с версии v1.11.0) вызывается всякий раз, когда компилятор начинает отслеживать новый лексический контекст. Лексический контекст запускается при компиляции нового файла или определении модуля внутри функции. Обратите внимание, что код оценки не запускает новый лексический контекст (потому что они не отслеживают неиспользуемые псевдонимы, импорты и т.д.), но определение модуля внутри оцениваемого кода будет.Обратите внимание, что это событие может быть отправлено параллельно, где несколько файлов/модулей вызывают
:startи работают одновременно. Значениеlexical_trackerсреды макроса, хотя и неявное, может использоваться для уникальной идентификации среды. :stop- (с версии v1.11.0) вызывается всякий раз, когда компилятор прекращает отслеживание нового лексического контекста, например, нового файла.{:import, meta, module, opts}- отслеживается при импортеmodule.meta— метаданные импорта AST, аopts— опции импорта.{:imported_function, meta, module, name, arity}и{:imported_macro, meta, module, name, arity}- отслеживаются всякий раз, когда вызывается импортированная функция или макрос.meta— метаданные вызова AST,module— модуль, откуда происходит импорт, за которым следуютnameиarityимпортированной функции/макроса. Событие :remote_function/:remote_macro может всё ещё быть отправлено для импортированного модуля/имени/арности.{:alias, meta, alias, as, opts}- отслеживается всякий раз, когдаaliasалиасируется наas.meta— метаданные псевдонима AST, аopts— опции псевдонима.{:alias_expansion, meta, as, alias}отслеживается всякий раз, когда происходит расширение псевдонима для ранее определённогоalias, т.е. когда пользователь пишетas, которое расширяется доalias.meta— метаданные расширения псевдонима AST.{:alias_reference, meta, module}- отслеживается всякий раз, когда в коде используется псевдоним, т.е. когда пользователь пишетMyModule.Foo.Barв коде, независимо от того, расширялся он или нет.{:require, meta, module, opts}- отслеживается при запросеmodule.meta— метаданные запроса AST, аopts— опции запроса. Если опцияmetaсодержит:from_macro, то модуль был вызван изнутри макроса и поэтому должен обрабатываться как зависимость времени компиляции.{:struct_expansion, meta, module, keys}- отслеживается всякий раз, когда расширяется структураmodule.meta— метаданные структуры AST, аkeys— ключи, используемые расширением.{:remote_function, meta, module, name, arity}и{:remote_macro, meta, module, name, arity}- отслеживаются всякий раз, когда ссылаются на удалённую функцию или макрос.meta— метаданные вызова AST,module— вызываемый модуль, за которым следуютnameиarity.{:local_function, meta, name, arity}и{:local_macro, meta, name, arity}- отслеживаются всякий раз, когда ссылаются на локальную функцию или макрос.meta— метаданные вызова AST, за которыми следуютnameиarity.{:compile_env, app, path, return}- отслеживается всякий раз, когда вызываютсяApplication.compile_env/3илиApplication.compile_env!/2.app— атом,path— список ключей для обхода в среде приложения, аreturn— либо{:ok, value}, либо:error.{:on_module, bytecode, _ignore}- (с версии v1.13.0) отслеживается всякий раз, когда определён модуль. Это эквивалентно обратной функции@after_compileи вызывается после любого@after_compileв данном модуле. Третий элемент в настоящее время:none, но в будущем он может предоставить больше метаданных. Лучше всего его игнорировать на данный момент. Обратите внимание, что функцииModule, ожидающие ещё не скомпилированные модули (например,Module.definitions_in/1), всё ещё доступны на момент выдачи этого события.
Опция компилятора :tracers может быть объединена с опцией компилятора :parser_options для обогащения метаданных отслеживаемых событий выше.
Новые события могут быть добавлены в любое время в будущем, поэтому рекомендуется, чтобы функция trace/2 имела «универсальный» условный оператор.
Ниже приведён пример отслеживателя, который выводит все вызовы удалённых функций:
defmodule MyTracer do
def trace({:remote_function, _meta, module, name, arity}, env) do
IO.puts "#{env.file}:#{env.line} #{inspect(module)}.#{name}/#{arity}"
:ok
end
def trace(_event, _env) do
:ok
end
end Типы
- binding()
Список со всеми переменными и их значениями.
- diagnostic(severity)
Диагностика, возвращаемая компилятором и оценкой кода.
- line()
Номер строки. 0 указывает отсутствие строки.
Функции
- append_path(path, opts \\ [])
Добавляет путь в список путей кода Erlang VM.
- append_paths(paths, opts \\ [])
Добавляет список
pathsв список путей кода Erlang VM.- available_compiler_options()
Возвращает список всех доступных опций компилятора.
- can_await_module_compilation?()
Возвращает true, если текущий процесс может ожидать компиляции модуля.
- 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.
- delete_paths(paths)
Удаляет список путей из списка путей кода Erlang VM.
- ensure_all_loaded(modules)
Убеждается, что указанные модули загружены.
- ensure_all_loaded!(modules)
То же, что и
ensure_all_loaded/1, но генерирует исключение, если какой-либо модуль не может быть загружен.- ensure_compiled(module)
Аналогично
ensure_compiled!/1, но указывает, что можно продолжить без данного модуля.- ensure_compiled!(module)
Убеждается, что указанный модуль скомпилирован и загружен.
- ensure_loaded(module)
Убеждается, что указанный модуль загружен.
- ensure_loaded!(module)
То же, что и
ensure_loaded/1, но генерирует исключение, если модуль не может быть загружен.- ensure_loaded?(module)
Убеждается, что указанный модуль загружен.
- env_for_eval(env_or_opts)
Возвращает среду для оценки.
- eval_file(file, relative_to \\ nil)
Оценивает указанный файл.
- eval_quoted(quoted, binding \\ [], env_or_opts \\ [])
Оценивает содержимое в кавычках.
- eval_quoted_with_env(quoted, binding, env, opts \\ [])
Оценивает указанное
quotedсодержимое сbindingиenv.- eval_string(string, binding \\ [], opts \\ [])
Оценивает содержимое, заданное
string.- fetch_docs(module_or_path)
Возвращает документацию для указанного модуля или пути к
.beamфайлу.- format_file!(file, opts \\ [])
Форматирует файл.
- format_string!(string, opts \\ [])
Форматирует данный код
string.- get_compiler_option(key)
Возвращает значение заданной опции компилятора.
- loaded?(module)
Возвращает
true, если модуль загружен.- prepend_path(path, opts \\ [])
Вставляет путь в начало списка путей кода Erlang VM.
- prepend_paths(paths, opts \\ [])
Вставляет список
pathsв начало списка путей кода Erlang VM.- print_diagnostic(diagnostic)
Выводит диагностику в стандартный поток ошибок.
- purge_compiler_modules()
Очистка модулей компилятора.
- put_compiler_option(key, value)
Сохраняет опцию компиляции.
- quoted_to_algebra(quoted, opts \\ [])
Преобразует выражение в кавычках в документ алгебры, используя правила форматирования Elixir.
- require_file(file, relative_to \\ nil)
Требует указанный
file.- required_files()
Список всех требуемых файлов.
- string_to_quoted(string, opts \\ [])
Преобразует заданную строку в её кавычковое представление.
- string_to_quoted!(string, opts \\ [])
Преобразует заданную строку в её кавычковое представление.
- string_to_quoted_with_comments(string, opts \\ [])
Преобразует заданную строку в её кавычковое представление и список комментариев.
- string_to_quoted_with_comments!(string, opts \\ [])
Преобразует заданную строку в её кавычковое представление и список комментариев.
- unrequire_files(files)
Удаляет файлы из списка требуемых файлов.
- with_diagnostics(opts \\ [], fun)
Выполняет заданную
funи захватывает всю диагностику.
binding()Source
@type binding() :: [{atom() | tuple(), any()}] Список всех переменных и их значений.
Ключи связывания обычно атомы, но могут быть кортежами для переменных, определённых в другом контексте.
diagnostic(severity)Source
@type diagnostic(severity) :: %{
:file => Path.t(),
:severity => severity,
:message => String.t(),
:position => position(),
:stacktrace => Exception.stacktrace(),
optional(any()) => any()
} Диагностика, возвращаемая компилятором и оценкой кода.
line()Source
@type line() :: non_neg_integer()
Номер строки. 0 указывает на отсутствие строки.
position()Source
@type position() :: line() | {pos_integer(), column :: non_neg_integer()} append_path(path, opts \\ [])Source
@spec append_path(Path.t(), [{:cache, boolean()}]) :: true | false Добавляет путь в список путей к коду Erlang VM.
Это список каталогов, используемых Erlang VM для поиска модулей. Список файлов управляется для каждого узла Erlang VM.
Путь расширяется с помощью Path.expand/1 перед добавлением. Путь должен существовать. Возвращает булево значение, указывающее, был ли путь успешно добавлен.
Примеры
Code.append_path(".")
#=> true
Code.append_path("/does_not_exist")
#=> false
Параметры
-
:cache- (с версии v1.15.0) если истинно, путь к коду кэшируется при первом проходе, чтобы сократить операции с файловой системой. Требуется Erlang/OTP 26, в противном случае это пустая операция.
append_paths(paths, opts \\ [])Source
@spec append_paths([Path.t()], [{:cache, boolean()}]) :: :ok Добавляет список путей к списку путей к коду Erlang VM.
Это список каталогов, используемых Erlang VM для поиска модулей. Список файлов управляется для каждого узла Erlang VM.
Все пути расширяются с помощью Path.expand/1 перед добавлением. Добавляются только существующие пути. Эта функция всегда возвращает :ok, независимо от того, сколько путей было добавлено. Используйте append_path/1, если вам нужен больший контроль.
Примеры
Code.append_paths([".", "/does_not_exist"]) #=> :ok
Параметры
-
:cache- если истинно, путь к коду кэшируется при первом проходе, чтобы сократить операции с файловой системой. Требуется Erlang/OTP 26, в противном случае это пустая операция.
available_compiler_options()Source
@spec available_compiler_options() :: [atom()]
Возвращает список всех доступных параметров компилятора.
Описание всех параметров см. в put_compiler_option/2.
Примеры
Code.available_compiler_options() #=> [:docs, :debug_info, ...]
can_await_module_compilation?()Source
@spec can_await_module_compilation?() :: boolean()
Возвращает true, если текущий процесс может ожидать компиляции модуля.
При компиляции кода Elixir через Kernel.ParallelCompiler, который используется Mix и elixirc, вызов модуля, который еще не скомпилирован, заблокирует вызывающий процесс, пока модуль не станет доступен. Выполнение скриптов Elixir, например, передача имени файла в elixir, не ожидает.
compile_file(file, relative_to \\ nil)Source
@spec compile_file(binary(), nil | binary()) :: [{module(), binary()}] Компилирует указанный файл.
Принимает relative_to в качестве аргумента, чтобы указать расположение файла.
Возвращает список кортежей, где первый элемент - имя модуля, а второй - его байткод (в виде двоичных данных). В отличие от require_file/2, он не отслеживает имя файла скомпилированного файла.
Если вы хотите получить результат вычисления файла, а не модулей, определенных в нем, см. eval_file/2.
Для одновременной компиляции многих файлов см. Kernel.ParallelCompiler.compile/2.
compile_quoted(quoted, file \\ "nofile")Source
@spec compile_quoted(Macro.t(), binary()) :: [{module(), binary()}] Компилирует выражение в виде котировки.
Возвращает список кортежей, где первый элемент - имя модуля, а второй - его байткод (в виде двоичных данных). В качестве второго аргумента может быть передан file, который будет использоваться для отчётов о предупреждениях и ошибках.
compile_string(string, file \\ "nofile")Source
@spec compile_string(List.Chars.t(), binary()) :: [{module(), binary()}] Компилирует заданную строку.
Возвращает список кортежей, где первый элемент - имя модуля, а второй - его байткод (в виде двоичных данных). В качестве второго аргумента может быть передан file, который будет использоваться для отчётов о предупреждениях и ошибках.
Предупреждение: string может быть любым кодом Elixir, и код может быть выполнен с теми же привилегиями, что и Erlang VM: это означает, что такой код может представлять угрозу для системы (например, выполняя системные команды). Не используйте compile_string/2 с ненадежными входными данными (например, строками, полученными из сети).
compiler_options()Source
@spec compiler_options() :: map()
Получает все параметры компиляции из сервера кода.
Для получения отдельных параметров см. get_compiler_option/1. Описание всех параметров см. в put_compiler_option/2.
Примеры
Code.compiler_options()
#=> %{debug_info: true, docs: true, ...} compiler_options(opts)Source
@spec compiler_options(Enumerable.t({atom(), term()})) :: %{
optional(atom()) => term()
} Сохраняет все заданные параметры компиляции.
Изменение параметров компиляции влияет на все процессы, выполняемые на узле Erlang VM. Для сохранения отдельных параметров и описание всех параметров см. put_compiler_option/2.
Возвращает карту с предыдущими значениями.
Примеры
Code.compiler_options(warnings_as_errors: true)
#=> %{warnings_as_errors: false} delete_path(path)Source
@spec delete_path(Path.t()) :: boolean()
Удаляет путь из списка путей к коду Erlang VM.
Это список каталогов, используемых Erlang VM для поиска модулей. Список файлов управляется для каждого узла Erlang VM.
Путь расширяется с помощью Path.expand/1 перед удалением. Если путь не существует, эта функция возвращает false.
Примеры
Code.prepend_path(".")
Code.delete_path(".")
#=> true
Code.delete_path("/does_not_exist")
#=> false delete_paths(paths)Source
@spec delete_paths([Path.t()]) :: :ok
Удаляет список путей из списка путей к коду Erlang VM.
Это список каталогов, используемых Erlang VM для поиска модулей. Список файлов управляется для каждого узла Erlang VM.
Путь расширяется с помощью Path.expand/1 перед удалением. Если путь не существует, эта функция возвращает false.
ensure_all_loaded(modules)Source
@spec ensure_all_loaded([module()]) :: :ok | {:error, [{module(), reason}]}
when reason: :badfile | :nofile | :on_load_failure Убеждается, что указанные модули загружены.
Аналогично ensure_loaded/1, но принимает список модулей вместо одного модуля и загружает все из них.
Если все модули загружаются успешно, возвращает :ok. В противном случае возвращает {:error, errors}, где errors - список кортежей, содержащих модуль и причину его неудачи при загрузке.
Примеры
iex> Code.ensure_all_loaded([Atom, String])
:ok
iex> Code.ensure_all_loaded([Atom, DoesNotExist])
{:error, [{DoesNotExist, :nofile}]} ensure_all_loaded!(modules)Source
@spec ensure_all_loaded!([module()]) :: :ok
То же, что и ensure_all_loaded/1, но выбрасывает исключение, если какой-либо из модулей не может быть загружен.
ensure_compiled(module)Source
@spec ensure_compiled(module()) ::
{:module, module()}
| {:error, :embedded | :badfile | :nofile | :on_load_failure | :unavailable} Аналогично ensure_compiled!/1, но указывает, что вы можете продолжить без указанного модуля.
В то время как ensure_compiled!/1 указывает компилятору Elixir, что вы можете продолжить только при наличии указанного модуля, эта функция указывает, что вы можете продолжить компиляцию без указанного модуля.
Если модуль успешно загружается, возвращается {:module, module}. В противном случае возвращается {:error, reason} с причиной ошибки. Если проверяемый модуль в настоящее время находится в тупике компиляции, эта функция возвращает {:error, :unavailable}. Отсутствие доступности не обязательно означает, что модуль не существует, просто он в настоящее время недоступен, но может (или не может) стать доступным в будущем.
Поэтому, если вы можете продолжить только в случае наличия модуля, используйте ensure_compiled!/1 вместо него. В частности, не делайте так:
case Code.ensure_compiled(module) do
{:module, _} -> module
{:error, _} -> raise ...
end
См. документацию по модулю для получения дополнительной информации о загрузке кода.
ensure_compiled!(module)Source
@spec ensure_compiled!(module()) :: module()
Обеспечивает компиляцию и загрузку заданного модуля.
Если модуль уже загружен, он работает как пустая операция. Если модуль еще не был скомпилирован, ensure_compiled!/1 приостанавливает компиляцию вызывающего модуля, пока модуль, переданный ensure_compiled!/1, не станет доступным или пока все файлы текущего проекта не будут скомпилированы. Если компиляция завершится, а модуль не будет доступен или находится в тупике, генерируется ошибка.
Поскольку эта функция приостанавливает компиляцию, используйте ее осторожно. В частности, избегайте использования ее для угадывания, какие модули находятся в системе. Чрезмерное использование этой функции также может привести к тупикам, когда два модуля одновременно проверяют, скомпилирован ли другой. Это возвращает конкретный код недоступности, когда мы не можем успешно проверить, доступен ли модуль или нет.
См. документацию по модулю для получения дополнительной информации о загрузке кода.
ensure_loaded(module)Source
@spec ensure_loaded(module()) ::
{:module, module()}
| {:error, :embedded | :badfile | :nofile | :on_load_failure} Обеспечивает загрузку данного модуля.
Если модуль уже загружен, это работает как пустая операция. Если модуль еще не загружен, он пытается загрузить его.
Если модуль успешно загружен, возвращается {:module, module}. В противном случае возвращается {:error, reason} с причиной ошибки.
См. документацию по модулю для получения дополнительной информации о загрузке кода.
Примеры
iex> Code.ensure_loaded(Atom)
{:module, Atom}
iex> Code.ensure_loaded(DoesNotExist)
{:error, :nofile} ensure_loaded!(module)Source
@spec ensure_loaded!(module()) :: module()
То же, что и ensure_loaded/1, но генерирует исключение, если модуль не может быть загружен.
ensure_loaded?(module)Source
@spec ensure_loaded?(module()) :: boolean()
Обеспечивает загрузку данного модуля.
Аналогично ensure_loaded/1, но возвращает true если модуль уже загружен или был успешно загружен. В противном случае возвращает false.
Примеры
iex> Code.ensure_loaded?(String) true
env_for_eval(env_or_opts)Source
Возвращает среду для вычисления.
Принимает либо Macro.Env, который затем обрезается и подготавливается, либо список параметров. Возвращает среду, готовую к вычислению.
Большинство функций в этом модуле автоматически подготовят заданную среду для вычисления, поэтому вам не нужно явно вызывать эту функцию, за исключением eval_quoted_with_env/3, которая была разработана именно для вызова в цикле, для реализации таких функций, как интерактивные оболочки или что-либо ещё с несколькими вычислениями.
Параметры
Если среда не задана, параметры могут быть:
:file- файл, который будет рассматриваться при вычислении:line- строка, с которой начинается скрипт
eval_file(file, relative_to \\ nil)Source
@spec eval_file(binary(), nil | binary()) :: {term(), binding()} Вычисляет указанный файл.
Принимает relative_to в качестве аргумента, чтобы указать, где находится файл.
В то время как require_file/2 и compile_file/2 возвращают загруженные модули и их байткод, eval_file/2 просто вычисляет содержимое файла и возвращает результат вычисления и его привязку (точно такой же возвращаемый результат, как у eval_string/3).
eval_quoted(quoted, binding \\ [], env_or_opts \\ [])Source
@spec eval_quoted(Macro.t(), binding(), Macro.Env.t() | keyword()) ::
{term(), binding()} Вычисляет цитируемое содержимое.
Предупреждение: Вызов этой функции внутри макроса считается плохой практикой, так как она попытается оценить значения времени выполнения во время компиляции. Аргументы макросов обычно преобразуются путем их извлечения из цитирования в возвращаемых цитируемых выражениях (вместо оценки).
См. eval_string/3 для описания binding и opts.
Примеры
iex> contents = quote(do: var!(a) + var!(b))
iex> {result, binding} = Code.eval_quoted(contents, [a: 1, b: 2], file: __ENV__.file, line: __ENV__.line)
iex> result
3
iex> Enum.sort(binding)
[a: 1, b: 2]
Для удобства вы можете передать __ENV__/0 в качестве аргумента opts и все параметры будут автоматически извлечены из текущей среды:
iex> contents = quote(do: var!(a) + var!(b))
iex> {result, binding} = Code.eval_quoted(contents, [a: 1, b: 2], __ENV__)
iex> result
3
iex> Enum.sort(binding)
[a: 1, b: 2] eval_quoted_with_env(quoted, binding, env, opts \\ [])Source
Вычисляет данные quoted с binding и env.
Эта функция предназначена для вызова в цикле, для реализации таких функций, как интерактивные оболочки или что-либо ещё с несколькими вычислениями. Поэтому в первый раз, когда вы вызываете эту функцию, вы должны вычислить начальную среду с помощью env_for_eval/1. Остальные вызовы должны передать среду, которая была возвращена этой функцией.
Параметры
-
:prune_binding- (с версии v1.14.2) обрезать привязку, сохраняя только переменные, считываемые или записываемые вычисляемым кодом. Обратите внимание, что переменные, используемые модулями, всегда обрезаются, даже если используются модулями позже. Вы можете отправить событие отслеживания:on_moduleи получить доступ к переменным, используемым модулем, из его среды.
eval_string(string, binding \\ [], opts \\ [])Source
@spec eval_string(List.Chars.t(), binding(), Macro.Env.t() | keyword()) ::
{term(), binding()} Вычисляет содержимое, заданное string.
Аргумент binding — список всех переменных и их значений. Аргумент opts — список параметров среды в виде ключевых слов.
Предупреждение: string может быть любым кодом Elixir и будет выполняться с теми же правами, что и виртуальная машина Erlang: это означает, что такой код может нанести ущерб машине (например, выполнив системные команды). Не используйте eval_string/3 с недоверенными данными (например, строками, поступающими из сети).
Параметры
Параметры могут быть:
:file- файл, который будет рассматриваться при вычислении:line- строка, с которой начинается скрипт
Кроме того, вы также можете передать среду в качестве второго аргумента, чтобы вычисление происходило в этой среде.
Возвращает кортеж вида {value, binding}, где value — значение, возвращенное из вычисления string. Если при вычислении string произошла ошибка, будет поднято исключение.
binding — список с именами всех переменных и их значениями после вычисления string. Ключи привязки обычно атомы, но они могут быть кортежем для переменных, определенных в другом контексте. Имена расположены в произвольном порядке.
Примеры
iex> {result, binding} = Code.eval_string("a + b", [a: 1, b: 2], file: __ENV__.file, line: __ENV__.line)
iex> result
3
iex> Enum.sort(binding)
[a: 1, b: 2]
iex> {result, binding} = Code.eval_string("c = a + b", [a: 1, b: 2], __ENV__)
iex> result
3
iex> Enum.sort(binding)
[a: 1, b: 2, c: 3]
iex> {result, binding} = Code.eval_string("a = a + b", [a: 1, b: 2])
iex> result
3
iex> Enum.sort(binding)
[a: 3, b: 2]
Для удобства вы можете передать __ENV__/0 в качестве аргумента opts и все импорты, require и алиасы, определенные в текущей среде, будут автоматически перенесены:
iex> {result, binding} = Code.eval_string("a + b", [a: 1, b: 2], __ENV__)
iex> result
3
iex> Enum.sort(binding)
[a: 1, b: 2] fetch_docs(module_or_path)Source
@spec 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 | 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)
"Atoms are constants whose values are their own name."
# A module that doesn't exist
iex> Code.fetch_docs(ModuleNotGood)
{:error, :module_not_found} format_file!(file, opts \\ [])Source
@spec format_file!( binary(), keyword() ) :: iodata()
Форматирует файл.
См. format_string!/2 для получения дополнительной информации о форматировании кода и доступных параметрах.
format_string!(string, opts \\ [])Source
@spec format_string!( binary(), keyword() ) :: iodata()
Форматирует предоставленный код string.
Форматтер получает строку, представляющую код Elixir, и возвращает iodata, представляющую отформатированный код в соответствии с предварительно определёнными правилами.
Параметры
:file- файл, содержащий строку, используется для отчёта об ошибках:line- строка, с которой начинается строка, используется для отчёта об ошибках:line_length- длина строки, к которой следует стремиться при форматировании документа. По умолчанию 98. Обратите внимание, что это значение используется как руководство, но в некоторых ситуациях оно не применяется. См. раздел «Длина строки» ниже для получения дополнительной информации:locals_without_parens- список ключевых слов со парами имя-арность, которые следует сохранять без скобок по возможности. Арность может быть атомом:*, что подразумевает все арности этого имени. Форматтер уже включает список функций, и этот параметр дополняет этот список.:force_do_end_blocks(с версии v1.9.0) - когдаtrue, преобразует все встроенные использованияdo: ...,else: ...и аналогичных в блокиdo-end. По умолчаниюfalse. Обратите внимание, что этот параметр является конвергентным: после того, как вы установите его вtrue, все ключевые слова будут преобразованы. Если вы позже установите его вfalse, блокиdo-endне будут преобразованы обратно в ключевые слова.:normalize_bitstring_modifiers(с версии v1.14.0) - приtrue, удаляет ненужные скобки в известных модификаторах битовых строк модификаторов, например,<<foo::binary()>>становится<<foo::binary>>, или добавляет скобки для пользовательских модификаторов, где<<foo::custom_type>>становится<<foo::custom_type()>>. По умолчаниюtrue. Этот параметр изменяет AST.:normalize_charlists_as_sigils(с версии v1.15.0) - приtrue, форматирует charlist как~cсигилы, например,'foo'становится~c"foo". По умолчаниюtrue. Этот параметр изменяет AST.
Принципы проектирования
Форматтер был разработан на основе трёх принципов.
Во-первых, форматтер никогда не изменяет семантику кода. Это означает, что входное и выходное AST почти всегда эквивалентны. Единственные случаи, когда форматтер изменит AST, - это когда входное AST вызовет предупреждения компилятора, а выходное AST их не вызовет. В таких случаях изменения AST можно отключить с помощью параметров форматирования, если это необходимо.
Второй принцип состоит в обеспечении минимальной конфигурации. Это упрощает принятие форматтера, устраняя точки разногласий, при этом гарантируя, что весь сообщество будет придерживаться единого стиля.
Форматтер не жёстко кодирует имена. Форматтер не будет вести себя особым образом, потому что функция называется defmodule, def или подобным образом. Этот принцип отражает цель Elixir как расширяемого языка, где разработчики могут расширять язык с помощью новых конструкций так, как будто они являются частью языка. Когда абсолютно необходимо изменить поведение на основе имени, это поведение должно быть настраиваемым, например, параметр :locals_without_parens.
Запуск форматтера
Форматтер пытается разместить как можно больше на одной строке и вставляет переводы строк, где это возможно, когда этого нельзя сделать.
В некоторых случаях это может привести к нежелательному форматированию. Поэтому некоторый код, сгенерированный форматтером, может быть не эстетичным и может потребовать явного вмешательства разработчика. Вот почему мы не рекомендуем слепо запускать форматтер в существующей кодовой базе. Вместо этого необходимо отформатировать и проверить каждый отформатированный файл.
Например, форматтер может разбить длинное определение функции на несколько частей:
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
Подводя итог: поскольку форматтер не может изменить семантику вашего кода, иногда необходимо настроить или переработать код, чтобы получить оптимальное форматирование. Чтобы лучше понять, как контролировать форматтер, в следующих разделах мы опишем случаи, когда форматтер сохраняет кодировку пользователя и как контролировать многострочные выражения.
Длина строки
Ещё одним моментом в работе форматтера является то, что конфигурация :line_length является руководством. Во многих случаях форматтер не может разбить ваш код, что означает, что он превысит длину строки. Например, если у вас есть длинная строка:
"this is a very long string that will go over the line length"
Форматтер не знает, как разбить её, не изменив подлежащую синтаксическую структуру кода, поэтому вам необходимо вмешаться:
"this is a very long string " <> "that will go over the line length"
Конкатенация строк позволяет коду уместиться на одной строке и предоставляет форматтеру больше возможностей.
Это также может происходить в блоках do/end, где ключевое слово do (или ->) может превысить длину строки, поскольку форматтер не имеет возможности вставить перевод строки читабельным способом. Например, если вы сделаете:
case very_long_expression() do end
И только ключевое слово do находится выше длины строки, Elixir не будет генерировать:
case very_long_expression() do end
Поэтому он предпочитает не трогать строку и оставить do выше предела длины строки.
Сохранение форматирования пользователя
Форматтер сохраняет входной формат в некоторых случаях. Они перечислены ниже:
Незначительные цифры в числах сохраняются как есть. Однако форматтер всегда вставляет нижние подчёркивания для десятичных чисел с более чем 5 цифрами и преобразует шестнадцатеричные цифры в верхний регистр
Строки, charlist, атомы и сигилы сохраняются как есть. Ни один символ не экранируется или убирается автоматически. Выбор разделителя также сохраняется из входных данных
-
Пробелы внутри блоков сохраняются как в входных данных, за исключением:
- выражений, занимающих несколько строк, перед которыми и после которых всегда будет пустая строка, и 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
считаются эквивалентными (вложенность отбрасывается вместе с большей частью форматирования пользователя). В таких случаях форматтер всегда будет форматировать в последнем стиле.
Новые строки
Форматтер преобразует все новые строки в коде из \r\n в \n.
get_compiler_option(key)Source
@spec get_compiler_option(atom()) :: term()
Возвращает значение заданного параметра компиляции.
Описание всех параметров см. в put_compiler_option/2.
Примеры
Code.get_compiler_option(:debug_info) #=> true
loaded?(module)Source
@spec loaded?(module()) :: boolean()
Возвращает true, если модуль загружен.
Эта функция не пытается загрузить модуль. Для такого поведения можно использовать ensure_loaded?/1.
Примеры
iex> Code.loaded?(Atom) true iex> Code.loaded?(NotYetLoaded) false
prepend_path(path, opts \\ [])Source
@spec prepend_path(Path.t(), [{:cache, boolean()}]) :: boolean() Добавляет путь в начало списка путей к коду Erlang VM.
Это список директорий, используемых Erlang VM для поиска модулей. Список файлов управляется на узел Erlang VM.
Путь расширяется с помощью Path.expand/1 перед добавлением в начало. Требуется, чтобы путь существовал. Возвращает boolean, указывающий, был ли путь успешно добавлен.
Примеры
Code.prepend_path(".")
#=> true
Code.prepend_path("/does_not_exist")
#=> false
Параметры
-
:cache- (с версии v1.15.0) если true, путь к коду кешируется при первом проходе, чтобы уменьшить операции с файловой системой. Требуется Erlang/OTP 26, в противном случае это бесполезно.
prepend_paths(paths, opts \\ [])Source
@spec prepend_paths([Path.t()], [{:cache, boolean()}]) :: :ok Добавляет список путей в начало списка путей к коду Erlang VM.
Это список директорий, используемых Erlang VM для поиска модулей. Список файлов управляется на узел Erlang VM.
Все пути расширяются с помощью Path.expand/1 перед добавлением в начало. Добавляются только существующие пути. Функция всегда возвращает :ok, независимо от того, сколько путей было добавлено. Используйте prepend_path/1, если вам нужен больший контроль.
Примеры
Code.prepend_paths([".", "/does_not_exist"]) #=> :ok
Параметры
-
:cache- если true, путь к коду кешируется при первом проходе, чтобы уменьшить операции с файловой системой. Требуется Erlang/OTP 26, в противном случае это бесполезно.
print_diagnostic(diagnostic)Source
@spec print_diagnostic(diagnostic(:warning | :error)) :: :ok
Выводит диагностическое сообщение в стандартный поток ошибок.
Диагностическое сообщение возвращается либо функцией Kernel.ParallelCompiler, либо Code.with_diagnostics/2.
purge_compiler_modules()Source
@spec purge_compiler_modules() :: {:ok, non_neg_integer()} Очистка модулей компилятора.
Компилятор использует временные модули для компиляции кода. Например, elixir_compiler_1, elixir_compiler_2, и так далее. В случае, если скомпилированный код хранит ссылки на анонимные функции или подобное, компилятор Elixir может не смочь освободить эти модули, оставляя в памяти лишний код и, в конечном итоге, приводя к таким модулям, как elixir_compiler_12345.
Эта функция очищает все модули, которые в данный момент хранит компилятор, позволяя повторно использовать старые имена модулей компилятора. Если какие-либо процессы выполняют код из таких модулей, они также будут завершены.
Эту функцию следует вызывать только в том случае, если у вас есть узел с длительной работой, который постоянно оценивает код.
Она возвращает {:ok, number_of_modules_purged}.
put_compiler_option(key, value)Source
@spec put_compiler_option(atom(), term()) :: :ok
Сохраняет параметр компиляции.
Изменение параметров компиляции влияет на все процессы, работающие на данном узле Erlang VM.
Доступные параметры:
:docs- еслиtrue, сохраняет документацию в скомпилированном модуле. По умолчаниюtrue.:debug_info- еслиtrue, сохраняет отладочную информацию в скомпилированном модуле. По умолчаниюtrue. Это позволяет инструментам статического анализа частично восстановить исходный код. Поэтому отключение:debug_infoне рекомендуется, так как это лишает компилятор Elixir и других инструментов возможности предоставлять обратную связь. Если вы хотите удалить:debug_infoпри развертывании, такие инструменты, какmix releaseуже делают это по умолчанию. Кроме того,mix testотключает его через параметр конфигурации проекта:test_elixirc_options. Этот параметр также может быть переопределен для каждого модуля с помощью директивы@compile.:ignore_already_consolidated(с версии v1.10.0) - еслиtrue, не предупреждает, когда протокол уже объединен, и добавляется новое реализация. По умолчаниюfalse.:ignore_module_conflict- еслиtrue, не предупреждает, когда модуль уже определен. По умолчаниюfalse.:relative_paths- еслиtrue, использует относительные пути в цитируемых узлах, предупреждениях и ошибках, генерируемых компилятором. Отключение этого параметра не повлияет на предупреждения и ошибки во время выполнения. По умолчаниюtrue.:warnings_as_errors- заставляет компиляцию завершиться ошибкой при генерации предупреждений. По умолчаниюfalse.:no_warn_undefined(с версии v1.10.0) - список модулей и кортежей{Mod, fun, arity}, которые не будут генерировать предупреждения о том, что модуль или функция не существует во время компиляции. Передайте атом:all, чтобы пропустить предупреждение для всех неопределенных функций. Это может быть полезно при динамической компиляции. По умолчанию[].:tracers(с версии v1.10.0) - список трейсеров (модулей), которые будут использоваться во время компиляции. Смотрите документацию модуля для получения дополнительной информации. По умолчанию[].:parser_options(с версии v1.10.0) - ключевое слово с параметрами, которые будут переданы парсеру при компиляции файлов. Принимает те же параметры, что иstring_to_quoted/2(за исключением параметров, изменяющих сам AST). Это можно использовать в сочетании с трейсером для получения локализованной информации о событиях, происходящих во время компиляции. По умолчанию[]. Этот параметр влияет только на функции компиляции кода, такие какcompile_string/2иcompile_file/2, но не наstring_to_quoted/2и аналогичные, так как последний используется для других целей, помимо компиляции.:on_undefined_variable(с версии v1.15.0) - либо:raise, либо:warn. При:raise(по умолчанию) неопределенные переменные вызывают ошибку компиляции. Вы можете установить его в:warn, если вы хотите, чтобы неопределенные переменные генерировали предупреждение и расширялись в локальный вызов функции с нулевой арностью с тем же именем (например,nodeрасширялось какnode()). Такое поведение:warnсуществует только по соображениям совместимости при работе со старыми зависимостями.
Она всегда возвращает :ok. Вызывает ошибку для неверных параметров.
Примеры
Code.put_compiler_option(:debug_info, true) #=> :ok
quoted_to_algebra(quoted, opts \\ [])Source
@spec quoted_to_algebra( Macro.t(), keyword() ) :: Inspect.Algebra.t()
Преобразует цитируемое выражение в документ алгебры, используя правила форматирования Elixir.
Документ алгебры можно преобразовать в строку, вызвав:
doc |> Inspect.Algebra.format(:infinity) |> IO.iodata_to_binary()
Для высокоуровневой функции, выполняющей то же самое, см. Macro.to_string/1.
Учитываемые при форматировании моменты
AST Elixir не содержит метаданных для литералов, таких как строки, списки или кортежи с двумя элементами, что означает, что сгенерированный документ алгебры не будет учитывать все пользовательские настройки, а комментарии могут быть неправильно размещены. Для достижения лучших результатов можно использовать опции :token_metadata, :unescape и :literal_encoder для string_to_quoted/2, чтобы предоставить форматировщику дополнительную информацию:
[
literal_encoder: &{:ok, {:__block__, &2, [&1]}},
token_metadata: true,
unescape: false
]
Это создаст AST, содержащий информацию, такую как do начало и конец строки или разделители сигила, и путем обертывания литералов в блоки они теперь могут хранить метаданные, такие как номер строки, разделитель строки и экранированные последовательности, или форматирование целых чисел (например, 0x2a вместо 47). Однако, обратите внимание, что этот AST некорректен. Если вы его оцените, он не будет иметь тех же семантических свойств, что и обычный AST Elixir, из-за опций :unescape и :literal_encoder. Однако эти опции полезны, если вы занимаетесь манипулированием исходного кода, где важно сохранить пользовательские варианты и расположение комментариев.
Опции
:comments- список комментариев, связанных с цитируемым выражением. Значение по умолчанию[]. Рекомендуется передать обе опции:token_metadataи:literal_encoderфункцииstring_to_quoted_with_comments/2для правильного размещения комментариев:escape- когдаtrue, экранированные последовательности, такие как\n, будут экранированы в\\n. Если опция:unescapeбыла установлена вfalseпри использованииstring_to_quoted/2, установка этой опции вfalseпредотвратит двойное экранирование последовательностей. Значение по умолчаниюtrue.:locals_without_parens- список пар «имя-арность» в виде ключевых слов, которые следует сохранять без скобок по возможности. Арность может быть атомом:*, что подразумевает все арности этого имени. Форматировщик уже содержит список функций, а эта опция дополняет этот список.:syntax_colors- список цветов, используемых для цветного вывода. См.Inspect.Optsдля получения дополнительной информации.
require_file(file, relative_to \\ nil)Source
@spec 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. Список требуемых файлов управляется на узле Erlang VM.
См. 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()Source
@spec 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 \\ [])Source
@spec string_to_quoted(
List.Chars.t(),
keyword()
) ::
{:ok, Macro.t()}
| {:error, {location :: keyword(), binary() | {binary(), binary()}, binary()}} Преобразует данную строку в ее цитируемую форму.
Возвращает {:ok, quoted_form} в случае успеха, {:error, {meta, message_info, token}} в противном случае.
Опции
:file- имя файла, которое будет сообщено в случае ошибок при разборе. Значение по умолчанию"nofile".:line- начальная строка анализируемой строки. Значение по умолчанию 1.:column- (с версии 1.11.0) начальная колонка анализируемой строки. Значение по умолчанию 1.:columns- еслиtrue, добавить ключ:columnк метаданным цитирования. Значение по умолчаниюfalse.:unescape(с версии 1.10.0) - еслиfalse, сохраняет экранированные последовательности. Например,"null byte\\t\\x00"сохранится без изменений вместо преобразования в битовую строку. Обратите внимание, что если вы установите эту опцию в false, результирующий AST больше не будет действительным, но может быть полезен при анализе/преобразовании исходного кода, обычно в сочетании сquoted_to_algebra/2. Значение по умолчаниюtrue.:existing_atoms_only- еслиtrue, вызывать ошибку при обнаружении несуществующих атомов токенизатором. Значение по умолчаниюfalse.:token_metadata(с версии 1.10.0) - еслиtrue, включает метаданные, относящиеся к токенам, в AST выражения, такие как метаданные для токеновdoиend, для закрывающих токенов, конца выражений, а также разделителей для сигилов. См.Macro.metadata/0. Значение по умолчаниюfalse.:literal_encoder(с версии 1.10.0) - как кодировать литералы в AST. Это должна быть функция, которая принимает два аргумента, литерал и его метаданные, и возвращает{:ok, ast :: Macro.t}или{:error, reason :: binary}. Если вы возвращаете что-либо, кроме самого литерала в качествеterm, AST больше не будет действительным. Эта опция всё ещё может быть полезной для текстового анализа исходного кода.:static_atoms_encoder- функция кодирования статических атомов, см. раздел «Функция:static_atoms_encoder» ниже. Обратите внимание, что эта опция переопределяет поведение:existing_atoms_onlyдля статических атомов, но:existing_atoms_onlyпо-прежнему используется для динамических атомов, таких как атомы с интерполяцией.:warn_on_unnecessary_quotes- еслиfalse, не выводит предупреждение, когда у атомов, ключевых слов или вызовов есть лишние кавычки. Значение по умолчаниюtrue.
Macro.to_string/2
Обратная операция преобразования строки в её цитируемую форму - это Macro.to_string/2, которая преобразует цитируемую форму в строковое/двоичное представление.
Функция :static_atoms_encoder
Когда static_atoms_encoder: &my_encoder/2 передаётся как аргумент, my_encoder/2 вызывается всякий раз, когда токенизатор нуждается в создании «статического» атома. Статические атомы в AST работают как псевдонимы, удалённые вызовы, локальные вызовы, имена переменных, обычные атомы и списки ключевых слов.
Функция-кодировщик получит имя атома (как двоичную строку) и список ключевых слов с текущим файлом, строкой и столбцом. Она должна вернуть {:ok, token :: term} | {:error, reason :: binary}.
Функция-кодировщик должна создать атом из данной строки. Для создания корректного AST требуется вернуть {:ok, term}, где term - атом. Возвращение чего-либо помимо атома возможно, но в этом случае AST больше не будет «действительным», так как его нельзя использовать для компиляции или оценки кода Elixir. Сценарий применения - использование парсера Elixir в пользовательском интерфейсе без истощения таблицы атомов.
Функция кодирования атомов не вызывается для всех атомов, присутствующих в AST. Она не будет вызвана для следующих атомов:
операторы (
:+,:-, и т.д.)ключевые слова синтаксиса (
fn,do,else, и т.д.)атомы, содержащие интерполяцию (
:"#{1 + 1} is two"), так как эти атомы создаются во время выполненияатомы, используемые для представления сигилов с одной буквой, таких как
:sigil_X(но многобуквенные сигилы, такие как:sigil_XYZкодируются).
string_to_quoted!(строка, опции \\ [])Source
@spec string_to_quoted!( List.Chars.t(), keyword() ) :: Macro.t()
Преобразует заданную строку в её форматированную форму.
Возвращает AST, если преобразование успешно, в противном случае генерирует исключение. Исключение является TokenMissingError в случае отсутствия токена (обычно, из-за незаконченности выражения), SyntaxError в противном случае.
См. string_to_quoted/2 для информации об опциях.
string_to_quoted_with_comments(строка, опции \\ [])Source
@spec string_to_quoted_with_comments(
List.Chars.t(),
keyword()
) ::
{:ok, Macro.t(), [map()]} | {:error, {location :: keyword(), term(), term()}} Преобразует заданную строку в её форматированную форму и список комментариев.
Эта функция полезна при выполнении текстовых изменений в исходном коде, сохраняя при этом информацию о комментариях и позициях литералов.
Возвращает {:ok, quoted_form, comments} при успехе, {:error, {line, error, token}} в противном случае.
Комментарии являются картами со следующими полями:
:line- Номер строки исходного кода:text- Полный текст комментария, включая ведущий#:previous_eol_count- Количество символов конца строки между комментарием и предыдущим узлом AST или комментарием:next_eol_count- Количество символов конца строки между комментарием и следующим узлом AST или комментарием
См. string_to_quoted/2 для информации об опциях.
Примеры
iex> Code.string_to_quoted_with_comments("""
...> :foo
...>
...> # Hello, world!
...>
...>
...> # Some more comments!
...> """)
{:ok, :foo, [
%{line: 3, column: 1, previous_eol_count: 2, next_eol_count: 3, text: "# Hello, world!"},
%{line: 6, column: 1, previous_eol_count: 3, next_eol_count: 1, text: "# Some more comments!"},
]}
iex> Code.string_to_quoted_with_comments(":foo # :bar")
{:ok, :foo, [
%{line: 1, column: 6, previous_eol_count: 0, next_eol_count: 0, text: "# :bar"}
]} string_to_quoted_with_comments!(строка, опции \\ [])Source
@spec string_to_quoted_with_comments!(
List.Chars.t(),
keyword()
) :: {Macro.t(), [map()]} Преобразует заданную строку в её форматированную форму и список комментариев.
Возвращает AST и список комментариев при успехе, в противном случае генерирует исключение. Исключение является TokenMissingError в случае отсутствия токена (обычно, из-за незаконченности выражения), SyntaxError в противном случае.
См. string_to_quoted/2 для информации об опциях.
unrequire_files(файлы)Source
@spec unrequire_files([binary()]) :: :ok
Удаляет файлы из списка требуемых файлов.
Модули, определённые в файлах, не удаляются; вызов этой функции только удаляет их из списка, позволяя их повторно потребовать.
Список файлов управляется по узлу Erlang VM.
Примеры
# Require EEx test code
Code.require_file("../eex/test/eex_test.exs")
# Now unrequire all files
Code.unrequire_files(Code.required_files())
# Note that modules are still available
function_exported?(EExTest.Compiled, :before_compile, 0)
#=> true with_diagnostics(опции \\ [], функция)Source
@spec with_diagnostics(
keyword(),
(-> result)
) :: {result, [diagnostic(:warning | :error)]}
when result: term() Выполняет заданную fun и захватывает все диагностики.
Диагностики — это предупреждения и ошибки, выданные компилятором и функциями, такими как IO.warn/2.
Опции
-
:log- если диагностики должны регистрироваться по мере их появления. По умолчаниюfalse.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.15.4/Code.html