Spec-Zone.ru › Elixir 1.4

Модуль

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

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

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

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

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

@after_compile

Обработчик, который будет вызван сразу после компиляции текущего модуля. Принимает модуль или кортеж {<module>, <function atom>}. См. раздел «Обработчики компиляции» ниже.

@before_compile

Обработчик, который будет вызван перед компиляцией модуля. Принимает модуль или кортеж {<module>, <function/macro atom>}. См. раздел «Обработчики компиляции» ниже.

@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 не реализует один из образов обработки, будет выведено предупреждение.

@compile

Определяет параметры для компиляции модуля. Используется для настройки как Elixir, так и Erlang компиляторов, а также любых других этапов компиляции, добавленных сторонними инструментами. Например:

defmodule M do
  @compile {:inline, my_fun: 1}

  def my_fun(arg) do
    to_string(arg)
  end
end

Несколько применений @compile будут накапливаться, а не переписывать предыдущие. См. раздел «Параметры компиляции» ниже.

@doc

Предоставляет документацию для функции или макроса, следующего за атрибутом.

Принимает строку (часто heredoc) или false, где @doc false сделает функцию/макрос невидимой для инструментов извлечения документации, таких как ExDoc. Например:

defmodule M do
  @doc "Hello world"
  def hello do
    "world"
  end

  @doc """
  Sums `a` to `b`.
  """
  def sum(a, b) do
    a + b
  end
end

@dialyzer

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

Принимает атом, кортеж или список атомов и кортежей. Например:

defmodule M do
  @dialyzer {:nowarn_function, my_fun: 1}

  def my_fun(arg) do
    M.not_a_function(arg)
  end
end

Список поддерживаемых предупреждений см. на странице :dialyzer модуля.

Несколько применений @dialyzer будут накапливаться, а не переписывать предыдущие.

@external_resource

Указывает внешний ресурс для текущего модуля.

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

Инструменты, такие как Mix, могут использовать эту информацию для обеспечения повторной компиляции модуля в случае изменения внешних ресурсов.

@file

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

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

@moduledoc

Предоставляет документацию для текущего модуля, например:

defmodule M do
  @moduledoc """
  A very useful module
  """
end

Принимает строку (часто heredoc) или false, где @moduledoc false сделает модуль невидимым для инструментов извлечения документации, таких как ExDoc.

@on_definition

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

Принимает модуль или кортеж {<module>, <function atom>}. См. раздел «Обработчики компиляции» ниже.

@on_load

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

Принимает атом функции или функцию в текущем модуле. Функция должна иметь арность 0 (без аргументов) и должна возвращать :ok, в противном случае загрузка модуля будет прервана. Например:

defmodule M 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 M do
  @vsn "1.0"
end

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

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

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

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

Помимо встроенных атрибутов, перечисленных выше, также можно добавить пользовательские атрибуты. Пользовательский атрибут — это любой допустимый идентификатор, начинающийся с @ и за которым следует допустимое значение Elixir:

defmodule M do
  @custom_attr [some: "stuff"]
end

Для более продвинутых вариантов определения пользовательских атрибутов, см. register_attribute/3.

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

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

@after_compile

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

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

Пример

defmodule M do
  @after_compile __MODULE__

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

@before_compile

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

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

Если указан только модуль, функция/макрос предполагается __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

@on_definition

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

Принимает модуль или кортеж {<module>, <function atom>}. Функция должна принимать 6 аргументов:

  • среда модуля
  • тип: :def, :defp, :defmacro, или :defmacrop
  • имя функции/макроса
  • список процитированных аргументов
  • список процитированных условий
  • процитированное тело функции

Обратите внимание, что обработчик получает процитированные аргументы, и он вызывается до того, как функция сохраняется в модуле. Таким образом, Module.defines?/2 вернёт false для первого пункта каждой функции.

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

В отличие от других обработчиков, @on_definition будет вызывать только функции и никогда не макросы. Это связано с тем, что обработчик вызывается в контексте функции (и вложенные определения функций в Elixir запрещены).

Если указан только модуль, функция предполагается __on_definition__/6.

Пример

defmodule H 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 M do
  @on_definition {H, :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.compiler_options/1

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

  • @compile {:inline, some_fun: 2, other_fun: 3} - встраивает заданные пары имя/арность

  • @compile {:autoload, false} - отключает автоматическую загрузку модулей после компиляции. Вместо этого модуль будет загружен после его передачи

Вы можете ознакомиться с ещё несколькими опциями, используемыми компилятором Erlang, в документации модуля :compile.

Обзор

Функции

__info__(kind)

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

add_doc(module, line, kind, tuple, signature \\ [], doc)

Прикрепляет документацию к заданной функции или типу.

concat(list)

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

concat(left, right)

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

create(module, quoted, opts)

Создаёт модуль с заданным именем, определённый заданными выражениями в кавычках.

defines?(module, tuple)

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

defines?(module, tuple, kind)

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

definitions_in(module)

Возвращает все функции, определённые в module.

definitions_in(module, kind)

Возвращает все функции, определённые в module, соответствующие заданному типу.

delete_attribute(module, key)

Удаляет атрибут модуля, соответствующий заданному ключу.

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

Вычисляет выражения в кавычках в контексте заданного модуля.

get_attribute(module, key)

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

make_overridable(module, tuples)

Делает заданные функции в module переопределяемыми.

open?(module)

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

overridable?(module, tuple)

Возвращает true, если tuple в module помечен как переопределяемый.

put_attribute(module, key, value)

Устанавливает атрибут модуля с заданным ключом и значением в указанном модуле.

register_attribute(module, new, opts)

Регистрирует атрибут.

safe_concat(list)

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

safe_concat(left, right)

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

split(module)

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

Функции

__info__(kind)

__info__(:attributes | :compile | :exports | :functions | :macros | :md5 | :module | :native_addresses) ::
  atom() |
  [{atom(), any()} | {atom(), byte(), integer()}]

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

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

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

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

  • :module - имя модуля (Module == Module.__info__(:module))

В дополнение к вышесказанному, вы также можете передать в __info__/1 любой атом, поддерживаемый :erlang.module_info/0, который также определён для каждого скомпилированного модуля.

Для списка поддерживаемых атрибутов и дополнительной информации см. Модули — Справочное руководство по Erlang.

add_doc(module, line, kind, tuple, signature \\ [], doc)

Прикрепляет документацию к заданной функции или типу.

Ожидается модуль, к которому принадлежит функция/тип, строка (неотрицательное целое число), тип (def или defmacro), кортеж, представляющий функцию и её арность, подпись функции (подпись должна быть опущена для типов) и документация, которая должна быть либо двоичным значением, либо булевым.

Примеры

defmodule MyModule do
  Module.add_doc(__MODULE__, __ENV__.line + 1, :def, {:version, 0}, [], "Manually added docs")
  def version, do: 1
end

concat(list)

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

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

Примеры

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

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

concat(left, right)

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

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

Примеры

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

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

create(module, quoted, opts)

Создаёт модуль с заданным именем, определённый заданными выражениями в кавычках.

Строка, в которой определён модуль, и его файл должны быть переданы в качестве параметров.

Примеры

contents =
  quote do
    def world, do: true
  end

Module.create(Hello, contents, Macro.Env.location(__ENV__))

Hello.world #=> true

Отличия от defmodule

Module.create/3 работает аналогично defmodule и возвращает те же результаты. Хотя можно также использовать defmodule для динамического определения модулей, эта функция предпочтительнее, когда тело модуля задаётся выражением в кавычках.

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

defines?(module, tuple)

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

Используйте defines?/3 для проверки конкретного типа.

Примеры

defmodule Example do
  Module.defines? __MODULE__, {:version, 0} #=> false
  def version, do: 1
  Module.defines? __MODULE__, {:version, 0} #=> true
end

defines?(module, tuple, kind)

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

kind может быть любым из :def, :defp, :defmacro или :defmacrop.

Примеры

defmodule Example do
  Module.defines? __MODULE__, {:version, 0}, :defp #=> false
  def version, do: 1
  Module.defines? __MODULE__, {:version, 0}, :defp #=> false
end

definitions_in(module)

Возвращает все функции, определённые в module.

Примеры

defmodule Example do
  def version, do: 1
  Module.definitions_in __MODULE__ #=> [{:version, 0}]
end

definitions_in(module, kind)

Возвращает все функции, определённые в module, соответствующие заданному типу.

Примеры

defmodule Example do
  def version, do: 1
  Module.definitions_in __MODULE__, :def  #=> [{:version, 0}]
  Module.definitions_in __MODULE__, :defp #=> []
end

delete_attribute(module, key)

delete_attribute(module(), key :: atom()) :: value :: term()

Удаляет атрибут модуля, соответствующий заданному ключу.

Возвращает значение удалённого атрибута (или nil, если ничего не было установлено).

Примеры

defmodule MyModule do
  Module.put_attribute __MODULE__, :custom_threshold_for_lib, 10
  Module.delete_attribute __MODULE__, :custom_threshold_for_lib
end

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

Вычисляет выражения в кавычках в контексте заданного модуля.

Список параметров окружения также можно передать в качестве аргумента. Подробнее см. Code.eval_string/3.

Вызывает ошибку, если модуль уже был скомпилирован.

Примеры

defmodule Foo do
  contents = quote do: (def sum(a, b), do: a + b)
  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)
  Module.eval_quoted __ENV__, contents
end

Foo.sum(1, 2) #=> 3

Обратите внимание, что если вы передаёте структуру Macro.Env в качестве первого аргумента, а также передаёте opts, они будут объединены с opts, при этом opts будет иметь приоритет.

get_attribute(module, key)

get_attribute(module(), atom()) :: term()

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

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

Макрос @ компилируется в вызов этой функции. Например, следующий код:

@foo

Расширяется до чего-то подобного:

Module.get_attribute(__MODULE__, :foo)

Примеры

defmodule Foo do
  Module.put_attribute __MODULE__, :value, 1
  Module.get_attribute __MODULE__, :value #=> 1

  Module.register_attribute __MODULE__, :value, accumulate: true
  Module.put_attribute __MODULE__, :value, 1
  Module.get_attribute __MODULE__, :value #=> [1]
end

make_overridable(module, tuples)

Делает заданные функции в module переопределяемыми.

Переопределяемая функция определяется лениво, что позволяет разработчику настроить её. Подробнее см. Kernel.defoverridable/1.

open?(module)

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

overridable?(module, tuple)

Возвращает true если tuple в module помечен как переопределяемый.

put_attribute(module, key, value)

put_attribute(module(), key :: atom(), value :: term()) :: :ok

Устанавливает атрибут модуля с ключом и значением в заданном модуле.

Примеры

defmodule MyModule do
  Module.put_attribute __MODULE__, :custom_threshold_for_lib, 10
end

register_attribute(module, new, opts)

Регистрирует атрибут.

Регистрируя атрибут, разработчик может настроить способ хранения и накопления Elixir значений атрибута.

Параметры

При регистрации атрибута можно указать два параметра:

  • :accumulate - несколько вызовов одного и того же атрибута будут накапливаться вместо переопределения предыдущего. Новые атрибуты всегда добавляются в начало накопленного списка.

  • :persist - атрибут будет сохранен в формате Erlang Abstract Format. Полезно при взаимодействии с библиотеками Erlang.

По умолчанию оба параметра false.

Примеры

defmodule MyModule do
  Module.register_attribute __MODULE__,
    :custom_threshold_for_lib,
    accumulate: true, persist: false

  @custom_threshold_for_lib 10
  @custom_threshold_for_lib 20
  @custom_threshold_for_lib #=> [20, 10]
end

safe_concat(list)

safe_concat([binary() | atom()]) :: atom() | no_return()

Конкатенирует список псевдонимов и возвращает новый псевдоним только в том случае, если псевдоним уже был сохранен.

Если псевдоним еще не был сохранен, происходит ошибка ArgumentError. Обрабатывает списки символов, двоичные данные и атомы.

Примеры

iex> Module.safe_concat([Module, Unknown])
** (ArgumentError) argument error

iex> Module.safe_concat([List, Chars])
List.Chars

safe_concat(left, right)

safe_concat(binary() | atom(), binary() | atom()) ::
  atom() |
  no_return()

Конкатенирует два псевдонима и возвращает новый псевдоним только в том случае, если псевдоним уже был сохранен.

Если псевдоним еще не был сохранен, происходит ошибка ArgumentError. Обрабатывает списки символов, двоичные данные и атомы.

Примеры

iex> Module.safe_concat(Module, Unknown)
** (ArgumentError) argument error

iex> Module.safe_concat(List, Chars)
List.Chars

split(module)

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

Примеры

iex> Module.split Very.Long.Module.Name.And.Even.Longer
["Very", "Long", "Module", "Name", "And", "Even", "Longer"]

© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.4.5/Module.html

Spec-Zone.ru

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