Spec-Zone.ru › Elixir 1.13

Модуль поведение

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

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

После компиляции модуля, использование многих функций этого модуля вызовет ошибки, так как они не предназначены для проверки данных во время выполнения. Большинство данных во время выполнения можно проверить с помощью функции __info__/1, прикрепленной к каждому скомпилированному модулю.

Атрибуты модуля

Каждый модуль может быть снабжен одним или несколькими атрибутами. Следующие из них в настоящее время определены Elixir:

@after_compile

Обработчик, который будет вызван сразу после компиляции текущего модуля. Принимает модуль или {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

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

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, где @doc false сделает сущность невидимой для инструментов извлечения документации, таких как ExDoc. Например:

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

Как видно из примера выше, @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} кортеж. См. раздел «Обработчики компиляции» ниже.

@on_load

Обработчик, который будет вызван всякий раз, когда модуль загружается.

Принимает имя функции (в виде атома) функции в текущем модуле или {function_name, 0} кортеж, где function_name — имя функции в текущем модуле. Функция должна иметь арность 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

Модули, скомпилированные с HiPE, не вызовут этот обработчик.

@vsn

Укажите версию модуля. Принимает любое допустимое значение Elixir, например:

defmodule MyModule do
  @vsn "1.0"
end

Атрибуты структур

  • @derive — выводит реализацию для данного протокола для структуры, определенной в текущем модуле

  • @enforce_keys — гарантирует, что заданные ключи всегда устанавливаются при построении структуры, определенной в текущем модуле

См. Kernel.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.

Обратные вызовы компиляции

Существует три обратных вызова, которые вызываются при определении функций, а также до и сразу после генерации байткода модуля.

@after_compile

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

Принимает модуль или кортеж {module, function_name}. Функция должна принимать два аргумента: среду модуля и его байткод. Если предоставлен только модуль, функция предполагается __after_compile__/2.

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

Пример

defmodule MyModule do
  @after_compile __MODULE__

  def __after_compile__(env, _bytecode) do
    IO.inspect(env)
  end
end

@before_compile

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

Принимает модуль или кортеж {module, function_or_macro_name}. Функция/макрос должны принимать один аргумент: среду модуля. Если это макрос, возвращаемое им значение будет вставлено в конец определения модуля перед началом компиляции.

Если предоставлен только модуль, функция/макрос предполагается __before_compile__/1.

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

Примечание: в отличие от @after_compile, функция/макрос обратного вызова должен быть помещен в отдельный модуль (потому что при вызове обратного вызова текущий модуль еще не существует).

Пример

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"

@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

Опции компиляции

Атрибут @compile принимает различные параметры, которые используются как компиляторами Elixir, так и Erlang. Некоторые распространенные случаи использования описаны ниже:

  • @compile :debug_info - включает :debug_info независимо от соответствующего параметра в Code.get_compiler_option/1

  • @compile {:debug_info, false} - отключает :debug_info независимо от соответствующего параметра в Code.get_compiler_option/1

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

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

defines?(module, tuple)

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

defines?(module, tuple, def_kind)

Проверяет, определяет ли модуль функцию или макрос данного kind.

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

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

Каждый модуль получает функцию __info__/1, когда он компилируется. Функция принимает один из следующих элементов:

  • :attributes - список ключевых слов со всеми сохраненными атрибутами

  • :compile - список данных компилятора

  • :functions - список ключевых слов публичных функций и их арностей

  • :macros - список ключевых слов публичных макросов и их арностей

  • :md5 - MD5 модуля

  • :module - имя атома модуля

END_OF_DOCUMENT_MARKER

Функции

attributes_in(модуль)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(список)Source

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

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

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

Примеры

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

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

concat(левый, правый)Source

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

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

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

Примеры

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

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

create(модуль, цитированное, опции)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 и возвращает те же результаты. Хотя можно также использовать defmodule для динамического определения модулей, эта функция предпочтительнее, когда тело модуля задаётся цитированным выражением.

Другим важным отличием является то, что Module.create/3 позволяет управлять переменными среды, используемыми при определении модуля, в то время как Kernel.defmodule/2 автоматически использует среду, в которой он вызван.

defines_type?(модуль, определение)Source

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

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

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

defines?(модуль, кортеж)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?(модуль, кортеж, вид_определения)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

definitions_in(модуль)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(модуль, тип)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(модуль, ключ)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(модуль, аргумент)Source

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

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

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

eval_quoted(модуль_или_среда, цитированное, связывание \\ [], опции \\ [])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(модуль, ключ, значение_по_умолчанию \\ 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
END_OF_DOCUMENT_MARKER

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 клаузы.

Клаузы возвращаются в представлении AST Elixir, но уже в расширенном и нормализованном виде. Это полезно для анализа кода, но их нельзя повторно вставить в модуль, так как при этом будет потерян контекст. Поскольку представление AST в основном внутреннее, оно имеет версионность и может изменяться в любое время. Поэтому используйте этот API с осторожностью.

Параметры

  • :nillify_clauses (с версии v1.13.0) — возвращает nil вместо клаузул. Это полезно, когда требуется только получение типа и метаданных

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: 1, bar: 1
  def foo, do: 3

  [:bar, :foo] = 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.13.4/Module.html

Spec-Zone.ru

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