Модуль поведение
Предоставляет функции для работы с модулями во время компиляции.
Это позволяет разработчику динамически добавлять, удалять и регистрировать атрибуты, прикреплять документацию и так далее.
После компиляции модуля использование многих функций в этом модуле приведет к ошибкам, так как они не предназначены для проверки данных во время выполнения. Большинство данных во время выполнения можно проверить с помощью функции __info__/1, прикрепленной к каждому скомпилированному модулю.
Атрибуты модуля
Каждый модуль может быть снабжен одним или несколькими атрибутами. Следующие атрибуты в настоящее время определены Elixir:
@after_compile
Обработчик, который будет вызван сразу после компиляции текущего модуля. Принимает модуль или {module, function_name}. См. раздел "Обработчики компиляции" ниже.
@after_verify (с версии v1.14.0)
Обработчик, который будет вызван сразу после проверки текущего модуля на наличие неопределенных функций, устаревших функций и т. п. Принимает модуль или {module, function_name}. См. раздел "Обработчики компиляции" ниже.
@before_compile
Обработчик, который будет вызван перед компиляцией модуля. Принимает модуль или кортеж {module, function_or_macro_name}. См. раздел "Обработчики компиляции" ниже.
@behaviour
Обратите внимание на британское написание!
Модули могут ссылаться на поведения, чтобы гарантировать, что они реализуют требуемые функции с определенными сигнатурами, определенными @callback.
Например, вы можете указать поведение URI.Parser, как показано ниже:
defmodule URI.Parser do @doc "Defines a default port" @callback default_port() :: integer @doc "Parses the given URL" @callback parse(uri_info :: URI.t()) :: URI.t() end
А затем модуль может использовать его, как:
defmodule URI.HTTP do @behaviour URI.Parser def default_port(), do: 80 def parse(info), do: info end
Если поведение изменится или URI.HTTP не реализует один из обращений, будет выведено предупреждение.
Для подробной документации см. документацию по спецификациям поведения.
@impl
Для помощи в правильной реализации поведения, вы можете необязательно объявить @impl для реализованных обращений поведения. Это делает обратные вызовы явными и может помочь вам в поиске ошибок в вашем коде. Компилятор выдаст предупреждение в таких случаях:
если вы отмечаете функцию с
@impl, когда эта функция не является обратным вызовом.если вы не отмечаете функцию с
@impl, когда другие функции отмечены@impl. Если вы отметили одну функцию с@impl, вы должны отметить все остальные обратные вызовы для этого поведения как@impl.
@impl работает на основе контекста. Если вы генерируете функцию с помощью макроса и отмечаете её @impl, это не повлияет на модуль, в котором эта функция генерируется.
@impl также помогает в поддержании, делая понятным для других разработчиков, что функция реализует обратный вызов.
Используя @impl, вышеприведённый пример можно переписать так:
defmodule URI.HTTP do @behaviour URI.Parser @impl true def default_port(), do: 80 @impl true def parse(info), do: info end
Вы можете передать либо false, true, или конкретное поведение в @impl.
defmodule Foo do @behaviour Bar @behaviour Baz # Will warn if neither Bar nor Baz specify a callback named bar/0. @impl true def bar(), do: :ok # Will warn if Baz does not specify a callback named baz/0. @impl Baz def baz(), do: :ok end
Код теперь более удобочитаем, так как теперь ясно, какие функции являются частью вашего API, а какие — реализациями обратных вызовов. Для усиления этой идеи, @impl true автоматически отмечает функцию как @doc false, отключая документацию, если @doc не задан явно.
@compile
Определяет параметры для компиляции модуля. Это используется для настройки как Elixir, так и Erlang компиляторов, а также любых других компиляционных этапов, добавленных внешними инструментами. Например:
defmodule MyModule do
@compile {:inline, my_fun: 1}
def my_fun(arg) do
to_string(arg)
end
end
Несколько применений @compile будут накапливаться, а не перезаписывать предыдущие. См. раздел "Параметры компиляции" ниже.
@deprecated (с версии v1.6.0)
Предоставляет причину устаревания функции. Например:
defmodule Keyword do
@deprecated "Use Kernel.length/1 instead"
def size(keyword) do
length(keyword)
end
end
Компилятор Mix автоматически ищет вызовы устаревших модулей и выводит предупреждения во время компиляции.
Использование атрибута @deprecated также будет отражено в документации данной функции и макроса. Вы можете выбирать между атрибутом @deprecated и метаданными документации для предоставления жёсткой (с предупреждениями) и мягкой (без предупреждений) устарелости:
Это мягкое устаревание, поскольку оно просто помечает документацию как устаревшую:
@doc deprecated: "Use Kernel.length/1 instead" def size(keyword)
Это жёсткое устаревание, так как оно выводит предупреждения и помечает документацию как устаревшую:
@deprecated "Use Kernel.length/1 instead" def size(keyword)
В настоящее время @deprecated поддерживает только функции и макросы. Однако вы можете использовать ключ :deprecated в метаданных аннотации, чтобы также аннотировать документы модулей, типов и обратных вызовов.
Мы рекомендуем использовать эту функцию с осторожностью, особенно авторам библиотек. Устаревание кода всегда увеличивает нагрузку на пользователей библиотек. Мы также рекомендуем поддерживать устаревшую функциональность в течение длительного времени, даже после устаревания, давая разработчикам достаточно времени для обновления (за исключением случаев, когда сохранение устаревшего API нежелательно, например, в случае наличия проблем безопасности).
@doc и @typedoc
Предоставляет документацию для сущности, следующей за атрибутом. @doc используется с функцией, макросом, обратным вызовом или макрообратным вызовом, а @typedoc с типом (публичным или неявным).
Принимает один из следующих вариантов:
- строка (часто heredoc)
-
false, что сделает сущность невидимой для инструментов извлечения документации, таких какExDoc - список ключевых слов, начиная с Elixir 1.7.0
Например:
defmodule MyModule do
@typedoc "This type"
@typedoc since: "1.1.0"
@type t :: term
@doc "Hello world"
@doc since: "1.1.0"
def hello do
"world"
end
@doc """
Sums `a` to `b`.
"""
def sum(a, b) do
a + b
end
end
Как видно из примера, начиная с Elixir 1.7.0 @doc и @typedoc также принимают список ключевых слов, который служит способом предоставления произвольных метаданных о сущности. Инструменты, такие как ExDoc и IEx, могут использовать эту информацию для отображения аннотаций. Распространённым случаем использования является ключ :since, который можно использовать для аннотирования, в какой версии функция была представлена.
Как показано в примере, можно использовать эти атрибуты несколько раз перед сущностью. Однако компилятор выдаст предупреждение, если они будут использованы дважды с двоичными данными, так как это заменяет текст документации, использованный в предыдущем применении. Несколько применений со списками ключевых слов объединят списки в один.
Обратите внимание, что, поскольку компилятор также определяет некоторые дополнительные метаданные, существуют некоторые зарезервированные ключи, которые будут проигнорированы и выдадут предупреждение при использовании. В настоящее время это: :opaque и :defaults.
После компиляции этого модуля эта информация станет доступна через функцию Code.fetch_docs/1.
@dialyzer
Определяет предупреждения для запроса или подавления при использовании :dialyzer.
Принимает атом, кортеж или список атомов и кортежей. Например:
defmodule MyModule do
@dialyzer {:nowarn_function, my_fun: 1}
def my_fun(arg) do
M.not_a_function(arg)
end
end
Список поддерживаемых предупреждений см. в :dialyzer модуле.
Несколько применений @dialyzer будут накапливаться, а не перезаписывать предыдущие.
@external_resource
Указывает внешний ресурс для текущего модуля.
Иногда модуль встраивает информацию из внешнего файла. Этот атрибут позволяет модулю аннотировать, какие внешние ресурсы были использованы.
Инструменты могут использовать эту информацию для обеспечения повторной компиляции модуля в случае изменения каких-либо внешних ресурсов, см., например: mix compile.elixir.
Если внешний ресурс не существует, модуль всё равно имеет зависимость от него, что приводит к повторной компиляции модуля как только файл будет добавлен.
@file
Изменяет имя файла, используемое в трассировках стека для функции или макроса, за которым следует атрибут, например:
defmodule MyModule do
@doc "Hello world"
@file "hello.ex"
def hello do
"world"
end
end
@moduledoc
Предоставляет документацию для текущего модуля.
defmodule MyModule do @moduledoc """ A very useful module. """ @moduledoc authors: ["Alice", "Bob"] end
Принимает строку (часто heredoc) или false, где @moduledoc false сделает модуль невидимым для инструментов извлечения документации, таких как ExDoc.
Аналогично @doc также принимает список ключевых слов для предоставления метаданных о модуле. Для получения более подробной информации см. документацию по @doc выше.
После компиляции этого модуля эта информация станет доступна через функцию Code.fetch_docs/1.
@on_definition
Обработчик, который будет вызван при определении каждой функции или макроса в текущем модуле. Полезно при аннотировании функций.
Принимает модуль или кортеж {module, function_name}. Функция должна принимать 6 аргументов:
- среда модуля
- тип функции/макроса:
:def,:defp,:defmacro, или:defmacrop - имя функции/макроса
- список процитированных аргументов
- список процитированных ограничений
- процитированный тело функции
Если определяемая функция/макрос имеет несколько разделов, обработчик будет вызван для каждого раздела.
В отличие от других обработчиков, @on_definition будет вызывать только функции и никогда не макросы. Это для предотвращения обратных вызовов @on_definition от переопределения функций, которые только что были определены в пользу более явных подходов.
Если предоставлен только модуль, функция предполагается __on_definition__/6.
Пример
defmodule Hooks do
def on_def(_env, kind, name, args, guards, body) do
IO.puts("Defining #{kind} named #{name} with args:")
IO.inspect(args)
IO.puts("and guards")
IO.inspect(guards)
IO.puts("and body")
IO.puts(Macro.to_string(body))
end
end
defmodule MyModule do
@on_definition {Hooks, :on_def}
def hello(arg) when is_binary(arg) or is_list(arg) do
"Hello" <> to_string(arg)
end
def hello(_) do
:ok
end
end
@on_load
Обработчик, который будет вызван при каждой загрузке модуля.
Принимает имя функции (как атом) функции в текущем модуле. Функция должна иметь арность 0 (без аргументов). Если функция не возвращает :ok, загрузка модуля будет прервана. Например:
defmodule MyModule do
@on_load :load_check
def load_check do
if some_condition() do
:ok
else
:abort
end
end
def some_condition do
false
end
end
@vsn
Указывает версию модуля. Принимает любое допустимое значение Elixir, например:
defmodule MyModule do @vsn "1.0" end
Атрибуты структуры
@derive- выводит реализацию для заданного протокола для структуры, определенной в текущем модуле@enforce_keys- гарантирует, что заданные ключи всегда устанавливаются при построении структуры, определенной в текущем модуле
См. defstruct/1 для получения дополнительной информации о построении и использовании структур.
Атрибуты typespec
Следующие атрибуты являются частью типовpec и также встроенными в Elixir:
-
@type- определяет тип, используемый в@spec -
@typep- определяет закрытый тип, используемый в@spec -
@opaque- определяет неявный тип, используемый в@spec -
@spec- предоставляет спецификацию для функции -
@callback- предоставляет спецификацию для обратного вызова поведения -
@macrocallback- предоставляет спецификацию для обратного вызова поведения макроса -
@optional_callbacks- указывает, какие обратные вызовы поведения и обратные вызовы поведения макроса являются необязательными -
@impl- объявляет реализацию функции обратного вызова или макроса
Для подробной документации см. документацию по typespec.
Пользовательские атрибуты
В дополнение к встроенным атрибутам, перечисленным выше, можно добавить пользовательские атрибуты. Пользовательские атрибуты выражаются с использованием оператора @/1, за которым следует допустимое имя переменной. Значение, присваиваемое пользовательскому атрибуту, должно быть допустимым значением Elixir:
defmodule MyModule do @custom_attr [some: "stuff"] end
Для более расширенных вариантов при определении пользовательских атрибутов, см. register_attribute/3.
Обратные вызовы компиляции
Существует три обратных вызова компиляции, вызываемых в таком порядке: @before_compile, @after_compile, и @after_verify. Они описаны ниже.
@before_compile
Обратный вызов, который будет вызван перед компиляцией модуля. Он часто используется для изменения способа компиляции текущего модуля.
Принимает модуль или кортеж {module, function_or_macro_name}. Функция/макрос должна принимать один аргумент: среду модуля. Если это макрос, возвращаемое значение будет вставлено в конец определения модуля перед началом компиляции.
Если предоставлен только модуль, функция/макрос предполагается __before_compile__/1.
Обратные вызовы будут выполняться в порядке их регистрации. Любое переопределяемое определение будет сделано конкретным до запуска первого обратного вызова. Определение может быть сделано переопределяемым снова в другом обратном вызове до компиляции, и оно будет окончательно сделано конкретным после выполнения всех обратных вызовов.
Примечание: функция/макрос обратного вызова должен быть размещен в отдельном модуле (потому что когда обратный вызов вызывается, текущий модуль еще не существует).
Пример
defmodule A do
defmacro __before_compile__(_env) do
quote do
def hello, do: "world"
end
end
end
defmodule B do
@before_compile A
end
B.hello()
#=> "world"
@after_compile
Обратный вызов, который будет вызван сразу после компиляции текущего модуля.
Принимает модуль или кортеж {module, function_name}. Функция должна принимать два аргумента: среду модуля и его байткод. Если предоставлен только модуль, функция предполагается __after_compile__/2.
Обратные вызовы будут выполняться в порядке их регистрации.
Module функции, ожидающие еще не скомпилированные модули (например, definitions_in/1) все еще доступны во время вызова @after_compile.
Пример
defmodule MyModule do
@after_compile __MODULE__
def __after_compile__(env, _bytecode) do
IO.inspect(env)
end
end
@after_verify
Обратный вызов, который будет вызван сразу после проверки текущего модуля на неопределенные функции, устаревания и т. д. Модуль всегда проверяется после компиляции. В проектах Mix, модуль также проверяется при изменении любых его зависимостей времени выполнения. Поэтому это полезно для проверки текущего модуля, избегая зависимостей времени компиляции.
Принимает модуль или кортеж {module, function_name}. Функция должна принимать один аргумент: имя модуля. Если предоставлен только модуль, функция предполагается __after_verify__/2.
Обратные вызовы будут выполняться в порядке их регистрации.
Module функции, ожидающие еще не скомпилированные модули, больше недоступны во время вызова @after_verify.
Пример
defmodule MyModule do
@after_verify __MODULE__
def __after_verify__(module) do
IO.inspect(module)
:ok
end
end
Параметры компиляции
Атрибут @compile принимает различные параметры, используемые как компиляторами Elixir, так и Erlang. Некоторые распространенные случаи использования документированы ниже:
@compile :debug_info- включает:debug_infoнезависимо от соответствующей настройки вCode.get_compiler_option/1@compile {:debug_info, false}- отключает:debug_infoнезависимо от соответствующей настройки вCode.get_compiler_option/1. Отключение:debug_infoне рекомендуется, так как это лишает компилятор Elixir и другие инструменты возможности статического анализа кода. Если вы хотите убрать:debug_infoпри развертывании, инструменты, такие какmix release, уже делают это по умолчанию.@compile {:inline, some_fun: 2, other_fun: 3}- встраивает заданные пары имя/арность. Встраивание применяется локально, вызовы из другого модуля не затрагиваются этим параметром@compile {:autoload, false}- отключает автоматическую загрузку модулей после компиляции. Вместо этого модуль будет загружен после его отправки@compile {:no_warn_undefined, Mod}или@compile {:no_warn_undefined, {Mod, fun, arity}}- не предупреждает, если заданный модуль или заданныйMod.fun/arityне определены
Краткое описание
Типы
Обработчики
- __info__(atom)
Предоставляет информацию о времени выполнения о функциях, макросах и другой информации, определённой модулем.
Функции
- attributes_in(module)
Возвращает все имена атрибутов модуля, определённые в
module.- concat(list)
Объединяет список псевдонимов и возвращает новый псевдоним.
- concat(left, right)
Объединяет два псевдонима и возвращает новый псевдоним.
- create(module, quoted, opts)
Создаёт модуль с заданным именем и определённый заданными выражениями.
- defines?(module, tuple)
Проверяет, определяет ли модуль заданную функцию или макрос.
- defines?(module, tuple, def_kind)
Проверяет, определяет ли модуль функцию или макрос заданного
kind.- defines_type?(module, definition)
Проверяет, определяет ли текущий модуль заданный тип (приватный, неявный или нет).
- definitions_in(module)
Возвращает все функции и макросы, определённые в
module.- definitions_in(module, kind)
Возвращает все функции, определённые в
module, в соответствии с их типом.- delete_attribute(module, key)
Удаляет запись (или записи) для заданного атрибута модуля.
- delete_definition(module, arg)
Удаляет определение из модуля.
- eval_quoted(module_or_env, quoted, binding \\ [], opts \\ [])
Вычисляет содержимое с котировкой в контексте данного модуля.
- get_attribute(module, key, default \\ nil)
Получает заданный атрибут из модуля.
- get_definition(module, arg, options \\ [])
Возвращает определение для заданной пары имя-арность.
- has_attribute?(module, key)
Проверяет, определён ли заданный атрибут.
- make_overridable(module, tuples)
Делает заданные функции в
moduleпереопределяемыми.- open?(module)
Проверяет, открыт ли модуль.
- overridable?(module, tuple)
Возвращает
true, еслиtupleвmoduleбыл помечен как переопределяемый в какой-то момент.- overridables_in(module)
Возвращает все переопределяемые определения в
module.- put_attribute(module, key, value)
Добавляет атрибут модуля с
keyиvalueв заданномmodule.- register_attribute(module, attribute, options)
Регистрирует атрибут.
- reserved_attributes()
Возвращает информацию об атрибутах модулей, используемых Elixir.
- safe_concat(list)
Объединяет список псевдонимов и возвращает новый псевдоним только в том случае, если псевдоним уже был использован.
- safe_concat(left, right)
Объединяет два псевдонима и возвращает новый псевдоним только в том случае, если псевдоним уже был использован.
- spec_to_callback(module, definition)
Копирует заданный шаблон как обработчик.
- split(module)
Разделяет заданное имя модуля на бинарные части.
Типы
Обработчики
__info__(atom)Source
@callback __info__(:attributes) :: keyword()
@callback __info__(:compile) :: [term()]
@callback __info__(:functions) :: keyword()
@callback __info__(:macros) :: keyword()
@callback __info__(:md5) :: binary()
@callback __info__(:module) :: module()
@callback __info__(:struct) :: [%{field: atom(), required: boolean()}] | nil Предоставляет информацию о времени выполнения о функциях, макросах и другой информации, определённой модулем.
Каждый модуль получает функцию __info__/1, когда он компилируется. Функция принимает один из следующих элементов:
:attributes- список ключевых слов со всеми сохранёнными атрибутами:compile- список с метаданными компилятора:functions- список ключевых слов публичных функций и их арностей:macros- список ключевых слов публичных макросов и их арностей:md5- MD5 модуля:module- имя атома модуля:struct- если модуль определяет структуру, и если да, то каждое поле в порядке
Функции
attributes_in(модуль)Исходный код
@spec attributes_in(module()) :: [atom()]
Возвращает все имена атрибутов модуля, определенные в module.
Эта функция может использоваться только с модулями, которые еще не были скомпилированы.
Примеры
defmodule Example do @foo 1 Module.register_attribute(__MODULE__, :bar, accumulate: true) :foo in Module.attributes_in(__MODULE__) #=> true :bar in Module.attributes_in(__MODULE__) #=> true end
concat(список)Исходный код
@spec concat([binary() | atom()]) :: atom()
Конкатенирует список псевдонимов и возвращает новый псевдоним.
Обрабатывает двоичные данные и атомы.
Примеры
iex> Module.concat([Foo, Bar]) Foo.Bar iex> Module.concat([Foo, "Bar"]) Foo.Bar
concat(левый, правый)Исходный код
@spec concat(binary() | atom(), binary() | atom()) :: atom()
Конкатенирует два псевдонима и возвращает новый псевдоним.
Обрабатывает двоичные данные и атомы.
Примеры
iex> Module.concat(Foo, Bar) Foo.Bar iex> Module.concat(Foo, "Bar") Foo.Bar
create(модуль, скобки, опции)Исходный код
@spec create(module(), Macro.t(), Macro.Env.t() | keyword()) ::
{:module, module(), binary(), term()} Создает модуль с заданным именем, определенный заданными скобочными выражениями.
Строка, где определяется модуль, и его файл обязательны в качестве параметров.
Возвращает кортеж вида {:module, module, binary, term}, где module — имя модуля, binary — байткод модуля, а term — результат последнего выражения в quoted.
Аналогично Kernel.defmodule/2, двоичные данные будут записаны на диск только как файл .beam, если Module.create/3 вызывается в файле, который в данный момент компилируется.
Примеры
contents =
quote do
def world, do: true
end
Module.create(Hello, contents, Macro.Env.location(__ENV__))
Hello.world()
#=> true
Отличия от defmodule
Module.create/3 работает аналогично Kernel.defmodule/2 и возвращает те же результаты. Хотя можно также использовать Kernel.defmodule/2 для динамического определения модулей, эта функция предпочтительнее, когда тело модуля задаётся скобочным выражением.
Ещё одно важное различие заключается в том, что Module.create/3 позволяет управлять переменными окружения, используемыми при определении модуля, тогда как Kernel.defmodule/2 автоматически использует окружение, в котором оно вызывается.
defines?(модуль, кортеж)Исходный код
@spec defines?(module(), definition()) :: boolean()
Проверяет, определяет ли модуль заданную функцию или макрос.
Используйте defines?/3 для проверки на определённый тип.
Эта функция может использоваться только с модулями, которые ещё не были скомпилированы. Используйте Kernel.function_exported?/3 и Kernel.macro_exported?/3, чтобы проверить наличие общедоступных функций и макросов соответственно в скомпилированных модулях.
Обратите внимание, что defines? возвращает false для функций и макросов, которые были определены, но затем помечены как переопределяемые, и никакая другая реализация не была предоставлена. Вы можете проверить статус переопределяемости, вызвав overridable?/2.
Примеры
defmodule Example do
Module.defines?(__MODULE__, {:version, 0}) #=> false
def version, do: 1
Module.defines?(__MODULE__, {:version, 0}) #=> true
end defines?(модуль, кортеж, вид_определения)Исходный код
@spec defines?(module(), definition(), def_kind()) :: boolean()
Проверяет, определяет ли модуль функцию или макрос заданного kind.
kind может быть любым из :def, :defp, :defmacro, или :defmacrop.
Эта функция может использоваться только с модулями, которые ещё не были скомпилированы. Используйте Kernel.function_exported?/3 и Kernel.macro_exported?/3, чтобы проверить наличие общедоступных функций и макросов соответственно в скомпилированных модулях.
Примеры
defmodule Example do
Module.defines?(__MODULE__, {:version, 0}, :def) #=> false
def version, do: 1
Module.defines?(__MODULE__, {:version, 0}, :def) #=> true
end defines_type?(модуль, определение)Исходный код
@spec defines_type?(module(), definition()) :: boolean()
Проверяет, определяет ли текущий модуль заданный тип (приватный, неявный или нет).
Эта функция доступна только для компилируемых модулей.
definitions_in(модуль)Исходный код
@spec definitions_in(module()) :: [definition()]
Возвращает все функции и макросы, определённые в module.
Возвращает список всех определённых функций и макросов, публичных и приватных, в формате [{name, arity}, ...].
Эта функция может использоваться только с модулями, которые ещё не были скомпилированы. Используйте обратный вызов Module.__info__/1 для получения публичных функций и макросов в скомпилированных модулях.
Примеры
defmodule Example do
def version, do: 1
defmacrop test(arg), do: arg
Module.definitions_in(__MODULE__) #=> [{:version, 0}, {:test, 1}]
end definitions_in(модуль, вид)Исходный код
@spec definitions_in(module(), def_kind()) :: [definition()]
Возвращает все функции, определённые в module, в соответствии с его видом.
Эта функция может использоваться только с модулями, которые ещё не были скомпилированы. Используйте обратный вызов Module.__info__/1 для получения публичных функций и макросов в скомпилированных модулях.
Примеры
defmodule Example do
def version, do: 1
Module.definitions_in(__MODULE__, :def) #=> [{:version, 0}]
Module.definitions_in(__MODULE__, :defp) #=> []
end delete_attribute(модуль, ключ)Исходный код
@spec delete_attribute(module(), atom()) :: term()
Удаляет запись (или записи) для данного атрибута модуля.
Возвращает удалённое значение атрибута. Если атрибут не был задан и не был настроен для накопления, возвращает nil.
Если атрибут настроен для накопления, эта функция всегда возвращает список. Удаление атрибута удаляет существующие записи, но атрибут всё ещё будет накапливать.
Примеры
defmodule MyModule do Module.put_attribute(__MODULE__, :custom_threshold_for_lib, 10) Module.delete_attribute(__MODULE__, :custom_threshold_for_lib) end
delete_definition(модуль, аргумент)Исходный код
@spec delete_definition(module(), definition()) :: boolean()
Удаляет определение из модуля.
Возвращает true, если определение существует и было удалено, иначе — false.
eval_quoted(модуль_или_окружение, скобки, связывание \\ [], опции \\ [])Исходный код
@spec eval_quoted( module() | Macro.Env.t(), Macro.t(), list(), keyword() | Macro.Env.t() ) :: term()
Вычисляет содержимое в скобках в контексте данного модуля.
В качестве аргумента также может быть передан список параметров среды. Подробнее см. Code.eval_string/3.
Вызывает ошибку, если модуль уже был скомпилирован.
Примеры
defmodule Foo do
contents =
quote do
def sum(a, b), do: a + b
end
Module.eval_quoted(__MODULE__, contents)
end
Foo.sum(1, 2)
#=> 3
Для удобства можно передать любую структуру Macro.Env, например, __ENV__/0, в качестве первого аргумента или в качестве опций. И модуль, и все опции будут автоматически извлечены из окружения:
defmodule Foo do
contents =
quote do
def sum(a, b), do: a + b
end
Module.eval_quoted(__ENV__, contents)
end
Foo.sum(1, 2)
#=> 3
Обратите внимание, что если вы передаёте структуру Macro.Env в качестве первого аргумента, а также передаёте opts, они будут объединены с opts с приоритетом последнего.
get_attribute(модуль, ключ, значение_по_умолчанию \\ nil)Исходный код
@spec get_attribute(module(), atom(), term()) :: term()
Получает заданный атрибут из модуля.
Если атрибут был помечен с помощью accumulate с Module.register_attribute/3, всегда возвращается список. nil возвращается, если атрибут не был помечен с помощью accumulate и не был задан в какое-либо значение.
Макрос @ компилируется в вызов этой функции. Например, следующий код:
@foo
Расширяется примерно до:
Module.get_attribute(__MODULE__, :foo)
Эта функция может использоваться только с модулями, которые ещё не были скомпилированы. Используйте обратный вызов Module.__info__/1 для получения всех сохранённых атрибутов или Code.fetch_docs/1 для получения всех атрибутов документации в скомпилированных модулях.
Примеры
defmodule Foo do Module.put_attribute(__MODULE__, :value, 1) Module.get_attribute(__MODULE__, :value) #=> 1 Module.get_attribute(__MODULE__, :value, :default) #=> 1 Module.get_attribute(__MODULE__, :not_found, :default) #=> :default Module.register_attribute(__MODULE__, :value, accumulate: true) Module.put_attribute(__MODULE__, :value, 1) Module.get_attribute(__MODULE__, :value) #=> [1] end
get_definition(module, arg, options \\ [])Source
@spec get_definition(module(), definition(), keyword()) ::
{:v1, def_kind(), meta :: keyword(),
[
{meta :: keyword(), arguments :: [Macro.t()], guards :: [Macro.t()],
Macro.t()}
]}
| nil Возвращает определение для заданной пары имя-арность.
Возвращает кортеж с version, kind, определением metadata, и списком каждой из клаузул. Каждая клауза — кортеж из четырёх элементов: метаданные, аргументы, гварды и AST-представление клаузы.
Клаузы возвращаются в формате Elixir AST, но уже с расширенными и нормализованными элементами. Это делает их удобными для анализа кода, но их нельзя вставить обратно в модуль, так как будет утеряна часть контекста. Учитывая, что данное представление AST в основном внутреннее, оно имеет версию и может изменяться в любое время. Поэтому используйте этот API с осторожностью.
Параметры
-
:skip_clauses(с версии v1.14.0) — возвращает[]вместо клаузул. Это полезно, когда требуется только получить тип и метаданные.
has_attribute?(module, key)Source
@spec has_attribute?(module(), atom()) :: boolean()
Проверяет, определён ли данный атрибут.
Атрибут считается определённым, если он был зарегистрирован с помощью register_attribute/3 или ему было присвоено значение. Если атрибут был удалён с помощью delete_attribute/2, он больше не считается определённым.
Эта функция может быть использована только с модулями, которые ещё не скомпилированы.
Примеры
defmodule MyModule do @value 1 Module.register_attribute(__MODULE__, :other_value) Module.put_attribute(__MODULE__, :another_value, 1) Module.has_attribute?(__MODULE__, :value) #=> true Module.has_attribute?(__MODULE__, :other_value) #=> true Module.has_attribute?(__MODULE__, :another_value) #=> true Module.has_attribute?(__MODULE__, :undefined) #=> false Module.delete_attribute(__MODULE__, :value) Module.has_attribute?(__MODULE__, :value) #=> false end
make_overridable(module, tuples)Source
@spec make_overridable(module(), [definition()]) :: :ok
@spec make_overridable(module(), module()) :: :ok
Делает перечисленные функции в module переопределяемыми.
Переопределяемая функция определяется лениво, позволяя разработчику настраивать её. Подробнее см. Kernel.defoverridable/1.
После того, как функция или макрос помечены как переопределяемые, они больше не будут отображаться в definitions_in/1 и не будут возвращать true при передаче в defines?/2, пока не будет предоставлено другое реализация.
open?(module)Source
@spec open?(module()) :: boolean()
Проверяет, открыт ли модуль.
Модуль считается "открытым", если он в данный момент определяется и его атрибуты и функции могут быть изменены.
overridable?(module, tuple)Source
@spec overridable?(module(), definition()) :: boolean()
Возвращает true, если tuple в module был помечен как переопределяемый в какой-то момент.
Обратите внимание, что overridable?/2 возвращает true, даже если определение уже было переопределено. Для проверки существования определения или наличия ожидаемого определения можно использовать defines?/2.
overridables_in(module)Source
@spec overridables_in(module()) :: [atom()]
Возвращает все переопределяемые определения в module.
Обратите внимание, что определение включается, даже если оно было переопределено. Для проверки существования определения или наличия ожидаемого определения можно использовать defines?/2.
Эта функция может быть использована только с модулями, которые ещё не скомпилированы.
Примеры
defmodule Example do def foo, do: 1 def bar, do: 2 defoverridable foo: 0, bar: 0 def foo, do: 3 [bar: 0, foo: 0] = Module.overridables_in(__MODULE__) |> Enum.sort() end
put_attribute(module, key, value)Source
@spec put_attribute(module(), atom(), term()) :: :ok
Устанавливает атрибут модуля с key и value в заданном module.
Примеры
defmodule MyModule do Module.put_attribute(__MODULE__, :custom_threshold_for_lib, 10) end
register_attribute(module, attribute, options)Source
@spec register_attribute(module(), atom(), accumulate: boolean(), persist: boolean()) :: :ok
Регистрирует атрибут.
Регистрация атрибута позволяет разработчику настроить, как Elixir будет хранить и накапливать значения атрибутов.
Параметры
При регистрации атрибута можно указать два параметра:
:accumulate— несколько вызовов с тем же атрибутом будут накапливаться, а не перезаписывать предыдущее значение. Новые атрибуты всегда добавляются в начало накопленного списка.:persist— атрибут будет сохранён в формате Erlang Abstract Format. Полезно при взаимодействии с Erlang-библиотеками.
По умолчанию оба параметра false. После того, как атрибут установлен на накопление или сохранение, поведение изменить нельзя.
Примеры
defmodule MyModule do Module.register_attribute(__MODULE__, :custom_threshold_for_lib, accumulate: true) @custom_threshold_for_lib 10 @custom_threshold_for_lib 20 @custom_threshold_for_lib #=> [20, 10] end
reserved_attributes()Source
Возвращает информацию об атрибутах модуля, используемых Elixir.
Подробную информацию об каждом атрибуте см. в разделе "Атрибуты модуля" в документации модуля.
Примеры
iex> map = Module.reserved_attributes() iex> Map.has_key?(map, :moduledoc) true iex> Map.has_key?(map, :doc) true
safe_concat(list)Source
@spec safe_concat([binary() | atom()]) :: atom()
Конкатенирует список псевдонимов и возвращает новый псевдоним только в том случае, если псевдоним уже упоминался.
Если псевдоним ещё не упоминался, возникает ошибка ArgumentError. Обрабатывает двоичные данные и атомы.
Примеры
iex> Module.safe_concat([List, Chars]) List.Chars
safe_concat(left, right)Source
@spec safe_concat(binary() | atom(), binary() | atom()) :: atom()
Конкатенирует два псевдонима и возвращает новый псевдоним только в том случае, если псевдоним уже упоминался.
Если псевдоним ещё не упоминался, возникает ошибка ArgumentError. Обрабатывает двоичные данные и атомы.
Примеры
iex> Module.safe_concat(List, Chars) List.Chars
spec_to_callback(module, definition)Source
@spec spec_to_callback(module(), definition()) :: boolean()
Копирует заданный спецификацию как обратный вызов.
Возвращает true, если такой спецификацию существует и была скопирована как обратный вызов. Если функция, связанная со спецификацией, имеет документацию, определённую до вызова этой функции, то документация тоже копируется.
split(module)Source
@spec split(module() | String.t()) :: [String.t(), ...]
Разделяет имя данного модуля на двоичные части.
module должен быть модулем Elixir, так как split/1 не будет работать с модулями в стиле Erlang (например, split(:lists) вызывает ошибку).
split/1 также поддерживает разделение строкового представления модулей Elixir (то есть результат вызова Atom.to_string/1 с именем модуля).
Примеры
iex> Module.split(Very.Long.Module.Name.And.Even.Longer)
["Very", "Long", "Module", "Name", "And", "Even", "Longer"]
iex> Module.split("Elixir.String.Chars")
["String", "Chars"]
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.14.1/Module.html