Spec-Zone.ru › Elixir 1.17

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

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

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

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

Принимает модуль или {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 - (с версии v1.14.0) если модуль определяет структуру, и если да, то каждый поле в порядке

Функции

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, имея приоритет.

END_OF_DOCUMENT_MARKER

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 (с версии 1.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.34.1) для программного языка Elixir

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

Spec-Zone.ru

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