Spec-Zone.ru › Elixir 1.14

Изменения в Elixir v1.14

Elixir v1.14 содержит множество улучшений в опыте отладки в Elixir и инспекции типов данных. Он также включает новую абстракцию для простого разбиения процессов, называемую PartitionSupervisor, а также улучшенные времена компиляции и сообщения об ошибках.

Elixir v1.14 — последняя версия, поддерживающая Erlang/OTP 23. Рассмотрите обновление до Erlang/OTP 24 или Erlang/OTP 25.

dbg

Kernel.dbg/2 — новая макрокоманда, которая чем-то похожа на IO.inspect/2, но специально разработана для отладки.

При вызове она выводит значение того, что вы ей передаёте, а также отлаживаемый код и его расположение. Этот код:

# In my_file.exs
feature = %{name: :dbg, inspiration: "Rust"}
dbg(feature)
dbg(Map.put(feature, :in_version, "1.14.0"))

Выводит это:

$ elixir my_file.exs
[my_file.exs:2: (file)]
feature #=> %{inspiration: "Rust", name: :dbg}

[my_file.exs:3: (file)]
Map.put(feature, :in_version, "1.14.0") #=> %{in_version: "1.14.0", inspiration: "Rust", name: :dbg}

dbg/2 может сделать больше. Это макрокоманда, поэтому она понимает код Elixir. Вы можете увидеть это, передавая последовательность |> конвейеров ей. dbg/2 выведет значение для каждого шага конвейера. Этот код:

# In dbg_pipes.exs
__ENV__.file
|> String.split("/", trim: true)
|> List.last()
|> File.exists?()
|> dbg()

Выводит это:

$ elixir dbg_pipes.exs
[dbg_pipes.exs:5: (file)]
__ENV__.file #=> "/home/myuser/dbg_pipes.exs"
|> String.split("/", trim: true) #=> ["home", "myuser", "dbg_pipes.exs"]
|> List.last() #=> "dbg_pipes.exs"
|> File.exists?() #=> true

IEx и отладка

dbg/2 поддерживает настраиваемые бэкэнды. IEx автоматически заменяет стандартный бэкэнд на бэкэнд, который останавливает выполнение кода с помощью IEx.Pry, предоставляя разработчикам возможность доступа к локальным переменным, импортам и другим данным. Это также работает с конвейерами: если вы передадите серию |> вызовов конвейера dbg (или передадите в него в конце, как |> dbg()), вы сможете шаг за шагом проходить через каждую строку конвейера.

Вы можете сохранить стандартное поведение, передав параметр --no-pry в IEx.

PartitionSupervisor

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

Например, представьте, что у вас есть процесс ErrorReporter, который вы используете для отчётности об ошибках в службу мониторинга.

# Application supervisor:
children = [
  # ...,
  ErrorReporter
]

Supervisor.start_link(children, strategy: :one_for_one)

По мере увеличения конкуретности вашей программы, процесс ErrorReporter может получать запросы от многих других процессов и, в конечном итоге, стать узким местом. В таком случае может помочь запустить несколько копий процесса ErrorReporter под PartitionSupervisor.

# Application supervisor
children = [
  {PartitionSupervisor, child_spec: ErrorReporter, name: Reporters}
]

Супервайзер PartitionSupervisor запустит количество процессов, равное System.schedulers_online() по умолчанию (чаще всего по одному на ядро). Теперь, когда маршрутизируются запросы к процессам ErrorReporter, мы можем использовать кортеж :via и направлять запросы через супервайзер разделения.

partitioning_key = self()
ErrorReporter.report({:via, PartitionSupervisor, {Reporters, partitioning_key}}, error)

Использование self() в качестве ключа разбиения означает, что один и тот же процесс всегда будет сообщать об ошибках одному и тому же процессу ErrorReporter, обеспечивая форму обратной связи. Вы можете использовать любой термин в качестве ключа разбиения.

Общий пример

Общий и практический пример использования PartitionSupervisor — разбиение чего-то вроде DynamicSupervisor. При запуске большого количества процессов под ним динамический супервайзер может стать узким местом, особенно если этим процессам требуется длительное время для инициализации. Вместо запуска одного DynamicSupervisor, можно запустить несколько:

children = [
  {PartitionSupervisor, child_spec: DynamicSupervisor, name: MyApp.DynamicSupervisors}
]

Supervisor.start_link(children, strategy: :one_for_one)

Теперь вы запускаете процессы в динамическом супервайзере для соответствующего раздела. Например, вы можете разделить по PID, как в предыдущем примере:

DynamicSupervisor.start_child(
  {:via, PartitionSupervisor, {MyApp.DynamicSupervisors, self()}},
  my_child_specification
)

Улучшенные сообщения об ошибках при работе с двоичными данными и оценке

Erlang/OTP 25 улучшил сообщения об ошибках при построении и оценке двоичных данных. Эти улучшения применяются и к Elixir. До версии v1.14 сообщения об ошибках при построении двоичных данных часто были неотлаживаемыми общими «ошибками аргументов». С Erlang/OTP 25 и Elixir v1.14 предоставляется более подробная информация для более лёгкой отладки. Эта работа является частью EEP 54.

Ранее:

int = 1
bin = "foo"
int <> bin
#=> ** (ArgumentError) argument error

Сейчас:

int = 1
bin = "foo"
int <> bin
#=> ** (ArgumentError) construction of binary failed:
#=>    segment 1 of type 'binary':
#=>    expected a binary but got: 1

Нарезка с шагом

В Elixir v1.12 были представлены диапазоны с шагом, которые являются диапазонами, где вы можете указать «шаг»:

Enum.to_list(1..10//3)
#=> [1, 4, 7, 10]

Диапазоны с шагом особенно полезны для числовых операций, включающих векторы и матрицы (например, см. Nx). Однако стандартная библиотека Elixir не использовала диапазоны с шагом в своих API. Elixir v1.14 начинает использовать шаги с поддержкой диапазонов с шагом в нескольких функциях. Одной из них является Enum.slice/2:

letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
Enum.slice(letters, 0..5//2)
#=> ["a", "c", "e"]

binary_slice/2 (и binary_slice/3 для полноты) была добавлена в модуль Kernel, которая работает с байтами и также поддерживает диапазоны с шагом:

binary_slice("Elixir", 1..5//2)
#=> "lxr"

Инспекция на основе выражений и улучшения Inspect

В Elixir принято реализовывать протокол Inspect для неявных структур, чтобы их инспектировали со специальной нотацией, напоминающей это:

MapSet.new([:apple, :banana])
#MapSet<[:apple, :banana]>

Это обычно делается, когда содержимое структуры или часть его является частной, и представление %name{...} раскрыло бы поля, которые не входят в общедоступный API.

Недостатком соглашения #name<...> является то, что инспектируемый вывод не является допустимым кодом Elixir. Например, вы не можете скопировать инспектируемый вывод и вставить его в сеанс IEx.

Elixir v1.14 изменяет соглашение для некоторых структур стандартной библиотеки. Реализация Inspect для этих структур теперь возвращает строку с допустимым выражением Elixir, которое воспроизводит структуру при её оценке. В примере MapSet выше это выглядит так:

fruits = MapSet.new([:apple, :banana])
MapSet.put(fruits, :pear)
#=> MapSet.new([:apple, :banana, :pear])

Выражение MapSet.new/1 оценивается точно так же, как и структура, которую мы инспектируем. Это позволяет нам скрыть внутренние детали MapSet, сохраняя при этом его как допустимый код Elixir. Эта инспекция на основе выражений была реализована для Version.Requirement, MapSet и Date.Range.

Наконец, мы улучшили протокол Inspect для структур, чтобы поля инспектировались в порядке их объявления в defstruct. Опция :optional также была добавлена при выводе протокола Inspect, что даёт разработчикам больше контроля над представлением структуры. Смотрите обновлённую документацию для Inspect для общего обзора доступных подходов и опций.

v1.14.1 (2022-10-10)

1. Улучшения

Elixir

  • [Kernel] Частичная обработка литералов в атрибутах модуля
  • [Kernel] Не добавлять зависимости от времени компиляции для литералов в качестве значений по умолчанию в Application.compile_env/3 внутри атрибутов модулей
  • [Macro] Добавить Macro.expand_literals/2 и Macro.expand_literals/3
  • [System] Добавить :close_stdin в System.shell/2

Mix

  • [mix test] Поддержка опции --all-warnings

2. Исправления ошибок

Elixir

  • [Kernel] Исправление вводящего в заблуждение предупреждения, когда :uniq указано в for-компрессиях, а результат не используется
  • [Kernel] Улучшение сообщения об ошибке, когда есть конфликтующая структура и игнорирование конфликта модулей
  • [Kernel] Не удалять атрибут @enforce_keys после объявления defstruct
  • [Kernel] Не завершать проверку модулей с отсутствующей частью :debug_info
  • [Macro] Исправление ошибки в Macro.to_string/2 при преобразовании AST с :erlang.binary_to_atom/2
  • [String] Исправление String.split/3 и String.next_grapheme/1, которые возвращали неверные результаты при неверном кодировании UTF-8
  • [System] Не закрывать stdin по умолчанию в System.shell/2
  • [URI] Не возвращать uri.port как :undefined в определённых случаях в URI.new/1

ExUnit

  • [ExUnit.DocTest] Не выводить ошибку при указании как :moduledoc , так и функций в :only

IEx

  • [CLI] Исправление обработки неверных аргументов, когда указан --no-pry

Mix

  • [mix format] Не кэшировать входные данные из .formatter.exs, чтобы они правильно переоценивались при каждом вызове

v1.14.0 (2022-09-01)

1. Улучшения

EEx

  • [EEx] Поддержка многострочных комментариев в EEx с помощью <%!-- --%>
  • [EEx] Добавление EEx.tokenize/2

Elixir

  • [Access] Добавить Access.slice/1
  • [Application] Добавить Application.compile_env/4 и Application.compile_env!/3 для чтения среды компиляции внутри макросов
  • [Calendar] Поддержка разбора базового формата ISO8601 с DateTime.from_iso8601/2
  • [Calendar] Добавить day/hour/minute в add/diff через разные модули календаря
  • [Code] Добавить :normalize_bitstring_modifiers в Code.format_string!/2
  • [Code] Выводить предупреждения о устаревании и типе для недопустимых опций в Code.compile_string/2 и Code.compile_quoted/2
  • [Code] Выводить предупреждение, если используется устаревленный лексический трекер в eval
  • [Code] Добавить Code.env_for_eval/1 и Code.eval_quoted_with_env/3
  • [Code] Улучшить трассировки стека из операций eval для Erlang/OTP 25+
  • [Code.Fragment] Добавить поддержку __MODULE__ в нескольких функциях
  • [Code.Fragment] Поддержка предложений окружения и контекста через несколько строк
  • [Enum] Разрешить срез с шагом в Enum.slice/2
  • [File] Поддержка dereference_symlinks: true в File.cp/3 и File.cp_r/3
  • [Float] Не отображать числа с плавающей точкой в экспоненциальной записи, если они меньше 1.0e16 и дробная часть точно равна нулю
  • [Float] Добавить Float.min_finite/0 и Float.max_finite/0
  • [Inspect] Улучшить вывод сообщений об ошибках, когда существует некорректная реализация протокола Inspect
  • [Inspect] Разрешить :optional при выводе протокола Inspect для скрытия полей, которые совпадают со своим значением по умолчанию
  • [Inspect] Выводить поля структуры в порядке их объявления в defstruct
  • [Inspect] Использовать инспекцию на основе выражений для Date.Range, MapSet и Version.Requirement
  • [IO] Поддержка Macro.Env и ключевых слов как определений трассировки стека в IO.warn/2
  • [IO] Добавить IO.ANSI.syntax_colors/0 и связанную конфигурацию, которая будет использоваться в IEx и dbg
  • [Kernel] Добавить новый dbg/0-2 макрос
  • [Kernel] Разрешить любое выражение-ограничение как размер битовой строки в совпадении с образцом
  • [Kernel] Разрешить составные типы с фиксаторами как ключ карты в совпадении с образцом
  • [Kernel] Выводить экранированный символ управления, когда он появляется как неожиданный токен
  • [Kernel] Выводить предупреждение о похожих идентификаторах, не являющихся ASCII
  • [Kernel] Добавить .. как нульарный оператор, возвращающий 0..-1//1
  • [Kernel] Реализовать рекомендации Unicode Technical Standard #39. В частности, мы выводим предупреждение о смежных сценариях и ограничиваем идентификаторы до одиночных сценариев или строго ограниченных смешанных сценариев
  • [Kernel] Автоматически выполнять преобразование NFC идентификаторов
  • [Kernel] Добавить binary_slice/2 и binary_slice/3
  • [Kernel] Лениво расширять атрибуты модулей, чтобы избежать зависимостей во время компиляции
  • [Kernel] Автоматически каскадировать generated: true аннотации при расширении макроса
  • [Keyword] Добавить Keyword.from_keys/2 и Keyword.replace_lazy/3
  • [List] Добавить List.keysort/3 с поддержкой функции sorter
  • [Macro] Добавить Macro.classify_atom/1 и Macro.inspect_atom/2
  • [Macro] Добавить Macro.path/2
  • [Macro.Env] Добавить Macro.Env.prune_compile_info/1
  • [Map] Добавить Map.from_keys/2 и Map.replace_lazy/3
  • [MapSet] Добавить MapSet.filter/2, MapSet.reject/2 и MapSet.symmetric_difference/2
  • [Node] Добавить Node.spawn_monitor/2 и Node.spawn_monitor/4
  • [Module] Поддержка нового атрибута @after_verify для выполнения кода при проверке модуля
  • [PartitionSupervisor] Добавить PartitionSupervisor, который запускает несколько изолированных разделов одного и того же дочернего элемента для масштабируемости
  • [Path] Добавить Path.safe_relative/1 и Path.safe_relative_to/2
  • [Registry] Добавить Registry.count_select/2
  • [Stream] Добавить Stream.duplicate/2 и Stream.transform/5
  • [String] Поддержка пустых списков поиска в String.replace/3, String.split/3 и String.splitter/3
  • [String] Разрешить срез с шагом в String.slice/2
  • [Task] Добавить опцию :zip_input_on_exit в Task.async_stream/3
  • [Task] Сохранить :mfa в структуре Task для целей рефлексии
  • [URI] Добавить URI.append_query/2
  • [Version] Добавить Version.to_string/1
  • [Version] Окрашивание Version.Requirement исходного кода в протоколе Inspect

ExUnit

  • [ExUnit] Добавить ExUnit.Callbacks.start_link_supervised!/2
  • [ExUnit] Добавить ExUnit.run/1 для повторного выполнения модулей тестов
  • [ExUnit] Окрашивание сводки в жёлтый цвет с сообщением, когда все тесты исключены
  • [ExUnit] Отображение понятной ошибки, когда имя теста слишком длинное

IEx

  • [IEx] Оценивание --dot-iex строки за строкой
  • [IEx] Добавить построчное оценивание IEx точек останова
  • [IEx.Autocomplete] Автодополнение модификаторов битовой строки (после :: внутри <<...>>)
  • [IEx.Helpers] Разрешить указание атома для pid/1
  • [IEx.Helpers] Поддержка сигилов в h/1

Logger

  • [Logger] Добавить Logger.put_process_level/2

Mix

  • [Mix] Добавить :config_path и :lockfile опции к Mix.install/2
  • [mix compile] Добавить --no-optional-deps для пропуска необязательных зависимостей, чтобы проверить, что компиляция работает без необязательных зависимостей
  • [mix compile] Включать информацию о столбце в диагностике ошибок, когда это возможно
  • [mix deps] Mix.Dep.Converger теперь указывает, какие зависимости образовали цикл
  • [mix do] Поддержка --app опции для ограничения рекурсивных задач в проектах типа «зонтик»
  • [mix do] Разрешить использование + в качестве разделителя задач вместо запятой
  • [mix format] Поддержка имени файла в mix format - при чтении из стандартного ввода
  • [mix format] Компилировать, если отсутствуют плагины mix format
  • [mix new] Не разрешать создание проектов с именами приложений, которые конфликтуют с параметрами командной строки многоаргументной виртуальной машины Erlang
  • [mix profile] Возвращать возвращаемое значение профилируемой функции
  • [mix release] Сделать сжатие BEAM опциональным
  • [mix release] Позволить :runtime_config_path принимать false для пропуска config/runtime.exs
  • [mix test] Улучшить сообщение об ошибке, когда пакет тестов завершается неудачно из-за покрытия кода
  • [mix test] Поддержка :test_elixirc_options и по умолчанию не генерировать документацию и фрагмент отладочной информации для тестов
  • [mix xref] Поддержка флага --group в mix xref graph

2. Исправления ошибок

Elixir

  • [Calendar] Обрабатывать ширины с "0" в них в Calendar.strftime/3
  • [CLI] Улучшить сообщения об ошибках при неправильном использовании --rpc-eval
  • [CLI] Возвращать правильный код выхода в Windows
  • [Code] Не выводить предупреждения при форматировании кода
  • [Enum] Разрешить срезам превышать начальную и конечную позиции
  • [Kernel] Не разрешать ограниченные символы в идентификаторах в соответствии с UTS39
  • [Kernel] Определить поле __exception__ как true при расширении исключений в типовредставлениях
  • [Kernel] Выводить предупреждение, если любой из псевдонимов True, False, и Nil используется
  • [Kernel] Выводить предупреждение об атрибутах @derive без вывода
  • [Kernel] Удалить зависимость во время компиляции от defimpl :for
  • [Kernel] Отслеживать все арности импортированных функций
  • [Kernel] Исправить равенство в ограничениях для динамических диапазонов без шагов
  • [Module] Исправить цикл при объединении переменных типов
  • [Protocol] Выводить предупреждение, если у протокола нет определений
  • [Regex] Отображать варианты списка при инспектировании вручную определённого Regex с Regex.compile/2
  • [String] Разрешить срезам превышать начальную и конечную позиции
  • [System] Вызывать негенерическое исключение при отсутствии переменной окружения в System.fetch_env!/1 для соответствия операциям с картами

ExUnit

  • [ExUnit] Не завершать работу при сравнении неизвестных связей в ограничениях
  • [ExUnit] Правильно отображать различия при сравнении некорректных списков со строками в хвостовой позиции
  • [ExUnit] Добавить короткий хеш в tmp_dir в ExUnit, чтобы избежать коллизий имён тестов
  • [ExUnit] Не сохранять логи в форматировщике командной строки (это снижает потребление памяти для пакетов тестов с capture_log)
  • [ExUnit] Выполнять обратный вызов ExUnit.after_suite/1 даже при отсутствии запущенных тестов
  • [ExUnit] Исправить сценарий, где setup с импортированной функцией изнутри describe не удалось скомпилировать

IEx

  • [IEx] Запретить краткий оператор конвейера после соответствий
  • [IEx] Исправить exports/1 в IEx для длинных имён функций

Mix

  • [mix compile.elixir] Исправить --warnings-as-errors при использовании с --all-warnings
  • [mix compile.elixir] Обеспечить каскадирование семантической перекомпиляции к зависимым путям
  • [mix compile.elixir] Заблокировать компилятор, чтобы избежать одновременного использования
  • [mix format] Не добавлять новые строки, если отформатированный файл пустой
  • [mix format] Правильно скомпилировать зависимости от mix format
  • [mix release] Установить RELEASE_MODE только после выполнения env.{sh,bat}
  • [mix release] Разрешить каскадирование конфигурации режима приложения к зависимостям
  • [mix xref] Не выводить уже сконсолидированные предупреждения во время mix xref trace
  • [Mix] Не запускать приложения с runtime: false при Mix.install/2

3. Мягкие устаревания (предупреждения не выведены)

Elixir

  • [File] Передача обратного вызова в качестве третьего аргумента в File.cp/3 и File.cp_r/3 устарело. Вместо этого передайте обратный вызов в качестве значения ключа :on_conflict в списке ключевых слов

EEx

  • [EEx] Использование <%# ... %> для комментариев устарело. Пожалуйста, используйте <% # ... %> или новые многострочные комментарии с <%!-- ... --%>

Logger

  • [Logger] Устарели Logger.enable/1 и Logger.disable/1 в пользу Logger.put_process_level/2

Mix

  • [mix cmd] Опция --app в mix cmd CMD устарела в пользу более эффективной mix do --app app cmd CMD

4. Жесткие устаревания

Elixir

  • [Application] Вызов Application.get_env/3 и аналогичных функций в теле модуля теперь не рекомендуется, используйте Application.compile_env/3 вместо этого
  • [Bitwise] use Bitwise устарело, используйте import Bitwise вместо этого
  • [Bitwise] ~~~ устарело в пользу bnot для ясности
  • [Kernel.ParallelCompiler] Возвращение списка или двухэлементной кортежи из :each_cycle устарело, вместо этого возвращайте кортеж {:compile | :runtime, modules, warnings}
  • [Kernel] Устарел оператор <|> для избежания неоднозначности с предстоящими расширенными числовыми операторами
  • [String] Устарело передача бинарного скомпилированного шаблона в String.starts_with?/2

Logger

  • [Logger] Устарело использование $levelpad для форматирования сообщений

Mix

  • [Mix] Mix.Tasks.Xref.calls/1 устарело в пользу трейсеров компиляции

5. Изменения, несовместимые с предыдущими версиями

Mix

  • [mix local.rebar] Удалена поддержка rebar2, которая не обновлялась 5 лет и больше не поддерживается в последних версиях Erlang/OTP

v1.13

Список изменений для релизов v1.13 можно найти в ветке v1.13.

← Предыдущая страница Написание документации

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

Spec-Zone.ru

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