Spec-Zone.ru › Elixir 1.5

Модуль

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

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

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

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

  @impl true # will warn if neither Bar nor Baz specify a callback named bar/0
  def bar(), do: :ok

  @impl Baz # Will warn if Baz does not specify a callback named baz/0
  def baz(), do: :ok
end

@compile

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

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

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

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

@doc

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

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

defmodule MyModule 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 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, могут использовать эту информацию, чтобы убедиться, что модуль перекомпилируется в случае изменения любого из внешних ресурсов.

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

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

@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

@vsn

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

defmodule MyModule do
  @vsn "1.0"
end

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

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

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

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

В дополнение к встроенным атрибутам, описанным выше, могут быть добавлены и пользовательские атрибуты. Пользовательский атрибут — это любой допустимый идентификатор, начинающийся с @ и последующий за допустимым значением 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
  • имя функции/макроса
  • список цитированных аргументов
  • список цитированных условий
  • тело функции в цитатах

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

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

В отличие от других обработчиков, @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.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, function_tuple, signature \\ [], doc)

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

concat(list)

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

concat(left, right)

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

create(module, quoted, opts)

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

defines?(module, tuple)

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

defines?(module, tuple, def_kind)

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

definitions_in(module)

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

definitions_in(module, def_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)

Записывает атрибут модуля со значениями key и value в заданном module.

register_attribute(module, attribute, options)

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

safe_concat(list)

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

safe_concat(left, right)

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

split(module)

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

Функции

__info__(kind)

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

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

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

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

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

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

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

Список поддерживаемых атрибутов и дополнительная информация приведены в Modules – Erlang Reference Manual.

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

add_doc(module(), non_neg_integer(), def_kind() | type_kind(), definition(), list(), String.t() | boolean() | nil) ::
  :ok |
  {:error, :private_doc}

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

Ожидается модуль, к которому принадлежит функция/тип, строка (неотрицательное целое число), тип (:def, :defmacro, :type, :opaque), кортеж {<function name>, <arity>}, сигнатура функции (сигнатура должна быть опущена для типов) и документация, которая должна быть либо двоичным значением, либо булевым.

Возвращает :ok или {:error, :private_doc}.

Примеры

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)

create(module(), Macro.t(), Macro.Env.t() | keyword()) :: {:module, module(), binary(), term()}

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

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

Примеры

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?(module(), definition()) :: boolean()

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

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

Эта функция может использоваться только для модулей, которые ещё не были скомпилированы. Используйте Kernel.function_exported?/3 для проверки скомпилированных модулей.

Примеры

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

defines?(module, tuple, def_kind)

defines?(module(), definition(), def_kind()) :: boolean()

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

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

Эта функция может использоваться только для модулей, которые ещё не были скомпилированы. Используйте Kernel.function_exported?/3 для проверки скомпилированных модулей.

Примеры

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)

definitions_in(module()) :: [definition()]

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

Примеры

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

definitions_in(module, def_kind)

definitions_in(module(), def_kind()) :: [definition()]

Возвращает все функции, определённые в 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(), atom()) :: 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 \\ [])

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

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)

make_overridable(module(), [definition()]) :: :ok
make_overridable(module(), module()) :: :ok

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

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

open?(module)

open?(module()) :: boolean()

Проверяет, открыт ли модуль.

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

overridable?(module, tuple)

overridable?(module(), definition()) :: boolean()

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

put_attribute(module, key, value)

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)

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

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

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

Примеры

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

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

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

Примеры

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

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

split(module)

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.5.3/Module.html

Spec-Zone.ru

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