Spec-Zone.ru › Elixir 1.16

Исходный код Модуль поведение

Предоставляет функции для работы с модулями во время компиляции.

Это позволяет разработчику динамически добавлять, удалять и регистрировать атрибуты, прикреплять документацию и так далее.

После компиляции модуля использование многих функций в этом модуле вызовет ошибки, так как им не под силу проверять данные во время выполнения. Большинство данных во время выполнения можно проверить с помощью функции __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 (с версии v1.5.0)

Для помощи в правильной реализации поведения можно необязательно объявить @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.

Указанный путь к файлу интерпретируется как относительный к папке, содержащей проект mix.exs, которая является текущей рабочей директорией, а не файлом, где @external_resource объявлен.

Если внешнего ресурса не существует, модуль всё равно имеет зависимость от него, что приводит к перекомпиляции модуля, как только файл будет добавлен.

@file

Изменяет имя файла, используемое в трассировках стека для функции или макроса, которые следуют за атрибутом, например:

defmodule MyModule do
  @doc "Hello world"
  @file "hello.ex"
  def hello do
    "world"
  end
end

Обратите внимание, что это верно только для исключений/диагностики, которые исходят из внутреннего пространства определения (включая шаблоны и условия). Например:

defmodule MyModule do # <---- module definition
  @file "hello.ex"
  defp unused(a) do # <---- function definition
    "world" # <---- function scope
  end

  @file "bye.ex"
  def unused(_), do: true
end

Если вы запустите этот код со второй частью определения "unused" закомментированной, вы увидите, что hello.ex используется в трассировке стека при сообщении предупреждений, но если вы её раскомментируете, вы увидите, что ошибка не будет упоминать bye.ex, потому что это ошибка уровня модуля, а не уровня выражения.

@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.

@nifs (с версии v1.16.0)

Список функций и их арностей, которые будут переопределены с помощью нативного кода (NIF).

defmodule MyLibrary.MyModule do
  @nifs [foo: 1, bar: 2]

  def foo(arg1), do: :erlang.nif_error(:not_loaded)
  def bar(arg1, arg2), do: :erlang.nif_error(:not_loaded)
end

Для получения дополнительной информации см. документацию Erlang: https://www.erlang.org/doc/man/erl_nif

@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 для получения дополнительной информации о создании и использовании структур.

Атрибуты типов

Следующие атрибуты являются частью типов и также встроены в Elixir:

  • @type — определяет тип, используемый в @spec
  • @typep — определяет закрытый тип, используемый в @spec
  • @opaque — определяет неявный тип, используемый в @spec
  • @spec — предоставляет спецификацию для функции
  • @callback — предоставляет спецификацию для обратного вызова поведения
  • @macrocallback — предоставляет спецификацию для обратного вызова поведения макроса
  • @optional_callbacks — определяет, какие обратные вызовы поведения и обратные вызовы поведения макроса являются необязательными
  • @impl — объявляет реализацию функции обратного вызова или макроса

Для подробной документации см. документацию по типам.

Пользовательские атрибуты

В дополнение к встроенным атрибутам, описанным выше, можно добавить пользовательские атрибуты. Пользовательские атрибуты выражаются с использованием оператора @/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__/1.

Обратные вызовы будут выполняться в порядке их регистрации.

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 не определены

Краткое описание

Типы

def_kind()
definition()

Обработчики событий

__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 \\ [])

Возвращает определение для заданной пары имя-арность.

get_last_attribute(module, key, default \\ nil)

Получает последнее установленное значение заданного атрибута из модуля.

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)

Разделяет заданное имя модуля на бинарные части.

Типы

def_kind()Source

@type def_kind() :: :def | :defp | :defmacro | :defmacrop

definition()Source

@type definition() :: {atom(), arity()}

Обработчики событий

__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 - (с версии 1.14.0) если модуль определяет структуру, и если да, каждое поле в порядке

Функции

attributes_in(module)Source

@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(list)Source

@spec concat([binary() | atom()]) :: atom()

Конкатенирует список псевдонимов и возвращает новый псевдоним.

Обрабатывает бинарные данные и атомы.

Примеры

iex> Module.concat([Foo, Bar])
Foo.Bar

iex> Module.concat([Foo, "Bar"])
Foo.Bar

concat(left, right)Source

@spec concat(binary() | atom(), binary() | atom()) :: atom()

Конкатенирует два псевдонима и возвращает новый псевдоним.

Обрабатывает бинарные данные и атомы.

Примеры

iex> Module.concat(Foo, Bar)
Foo.Bar

iex> Module.concat(Foo, "Bar")
Foo.Bar

create(module, quoted, opts)Source

@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?(module, tuple)Source

@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?(module, tuple, def_kind)Source

@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?(module, definition)Source

@spec defines_type?(module(), definition()) :: boolean()

Проверяет, определяет ли текущий модуль заданный тип (приватный, неявный или нет).

Эта функция доступна только для модулей, которые находятся в процессе компиляции.

definitions_in(module)Source

@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(module, kind)Source

@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(module, key)Source

@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(module, arg)Source

@spec delete_definition(module(), definition()) :: boolean()

Удаляет определение из модуля.

Возвращает true если определение существует и было удалено, в противном случае возвращает false.

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

@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(module, key, default \\ nil)Source

@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) — возвращает [] вместо возвращения клауз. Это полезно, когда требуется только получить тип и метаданные

get_last_attribute(module, key, default \\ nil)Source

@spec get_last_attribute(module(), atom(), term()) :: term()

Получает последнее установленное значение заданного атрибута модуля.

Если атрибут был помечен accumulate с Module.register_attribute/3, будет возвращено предыдущее установленное значение. Если атрибут не накапливает значения, этот вызов эквивалентен вызову Module.get_attribute/3.

Эта функция может быть использована только для модулей, которые ещё не скомпилированы. Используйте обратный вызов Module.__info__/1, чтобы получить все сохранённые атрибуты, или Code.fetch_docs/1 для получения всех связанных с документацией атрибутов в скомпилированных модулях.

Примеры

defmodule Foo do
  Module.put_attribute(__MODULE__, :value, 1)
  Module.get_last_attribute(__MODULE__, :value) #=> 1

  Module.get_last_attribute(__MODULE__, :not_found, :default) #=> :default

  Module.register_attribute(__MODULE__, :acc, accumulate: true)
  Module.put_attribute(__MODULE__, :acc, 1)
  Module.get_last_attribute(__MODULE__, :acc) #=> 1
  Module.put_attribute(__MODULE__, :acc, 2)
  Module.get_last_attribute(__MODULE__, :acc) #=> 2
end

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

@spec reserved_attributes() :: map()

Возвращает информацию об атрибутах модулей, используемых 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"]

Скачать версию ePub

Создано с помощью ExDoc (v0.32.2) для язык программирования Elixir

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.16.3/Module.html

Spec-Zone.ru

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