Spec-Zone.ru › Elixir 1.6

Модуль

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

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

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

@deprecated

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

defmodule Keyword do
  @deprecated "Use Kernel.length/1 instead"
  def size(keyword) do
    length(keyword)
  end
end

Компилятор mix автоматически ищет вызовы устаревших модулей и выдает предупреждения во время компиляции, вычисленные с помощью mix xref warnings.

Рекомендуется использовать эту функцию с осторожностью, особенно авторам библиотек. Устаревание кода всегда увеличивает нагрузку на пользователей библиотеки. Мы также рекомендуем поддерживать устаревшую функциональность в течение длительного периода времени даже после устаревания, что даст разработчикам достаточно времени для обновления (за исключением случаев, когда сохранение устаревшего API нежелательно, например, при наличии проблем с безопасностью).

@doc (и @since)

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

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

defmodule MyModule do
  @doc "Hello world"
  @since "1.1.0"
  def hello do
    "world"
  end

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

@since — это необязательный атрибут, который указывает, в какой версии функция была представлена.

@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

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

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

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

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
  | :functions
  | :macros
  | :md5
  | :module
  | :deprecated
) :: any()

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

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

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

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

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

  • :md5 - MD5 модуля

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

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

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

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

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

Возвращает кортеж вида {: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?(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(), module()) :: :ok
make_overridable(module(), [definition()]) :: :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. Обрабатывает списки символов, бинарные данные и атомы.

Примеры

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. Обрабатывает списки символов, бинарные данные и атомы.

Примеры

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

Spec-Zone.ru

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