Исходный код OptionParser
Функции для парсинга аргументов командной строки.
При вызове команды можно передавать опции командной строки для изменения её поведения. В этой документации они называются «флагами», в других ситуациях могут называться «переключателями» или просто «опциями». Флагу может быть задано значение, также называемое «аргументом».
Основной функцией в этом модуле является parse/2, которая парсит список опций и аргументов командной строки в список ключевых слов:
iex> OptionParser.parse(["--debug"], strict: [debug: :boolean])
{[debug: true], [], []}
OptionParser предоставляет некоторые удобства «из коробки», такие как псевдонимы и автоматическое управление отрицательными флагами.
Функция parse_head/2 является альтернативой parse/2, которая останавливает парсинг как только находит значение, которое не является флагом или значением для предыдущего флага.
Этот модуль также предоставляет функции низкого уровня, такие как next/2, для ручного парсинга флагов, а также split/1 и to_argv/1 для парсинга из строк и преобразования флагов в строки.
Краткое описание
Типы
Функции
- next(argv, opts \\ [])
Функция низкого уровня, которая парсит одну опцию.
- parse(argv, opts \\ [])
Парсит
argvв список ключевых слов.- parse!(argv, opts \\ [])
То же, что и
parse/2, но вызывает исключениеOptionParser.ParseError, если заданы какие-либо недопустимые опции.- parse_head(argv, opts \\ [])
Аналогично
parse/2, но парсит только началоargv; как только находит не-флаг, парсинг останавливается.- parse_head!(argv, opts \\ [])
То же, что и
parse_head/2, но вызывает исключениеOptionParser.ParseError, если заданы какие-либо недопустимые опции.- split(string)
Разделяет строку на куски
argv/0.- to_argv(enum, options \\ [])
Принимает перечислимый ключ-значение и преобразует его в
argv/0.
Типы
argv()Source
@type argv() :: [String.t()]
errors()Source
@type errors() :: [{String.t(), String.t() | nil}] options()Source
@type options() :: [ switches: keyword(), strict: keyword(), aliases: keyword(), allow_nonexistent_atoms: boolean(), return_separator: boolean() ]
parsed()Source
@type parsed() :: keyword()
Функции
next(argv, opts \\ [])Source
@spec next(argv(), options()) ::
{:ok, key :: atom(), value :: term(), argv()}
| {:invalid, String.t(), String.t() | nil, argv()}
| {:undefined, String.t(), String.t() | nil, argv()}
| {:error, argv()} Функция низкого уровня, которая анализирует один параметр.
Она принимает те же параметры, что и parse/2 и parse_head/2, так как обе функции построены на основе этой функции. Эта функция может вернуть:
{:ok, key, value, rest}- параметрkeyсvalueбыл успешно проанализирован{:invalid, key, value, rest}- параметрkeyнекорректен сvalue(возвращается, когда значение не может быть проанализировано в соответствии с типом переключателя){:undefined, key, value, rest}- параметрkeyне определён (возвращается в строгом режиме, когда переключатель неизвестен или отсутствует){:error, rest}- нет переключателей в начале заданногоargv
parse(argv, opts \\ [])Source
@spec parse(argv(), options()) :: {parsed(), argv(), errors()} Анализирует argv в список ключевых слов.
Возвращает кортеж из трёх элементов со структурой {parsed, args, invalid}, где:
-
parsed— список ключевых слов проанализированных переключателей со вложенными кортежами{switch_name, value};switch_name— атом, представляющий имя переключателя, аvalue— значение этого переключателя, проанализированное в соответствии сopts(подробнее в разделе «Примеры») -
args— список оставшихся аргументов вargvв виде строк -
invalid— список некорректных параметров в виде{option_name, value}, гдеoption_name— исходный параметр, аvalue—nil, если параметр не ожидался, или строковое значение, если значение не имело ожидаемого типа для соответствующего параметра
Elixir преобразует переключатели в атомы с нижним подчеркиванием, например, --source-path преобразуется в :source_path. Это сделано для лучшего соответствия соглашениям Elixir. Однако это означает, что переключатели не могут содержать символы нижнего подчеркивания, а переключатели, которые содержат символы нижнего подчеркивания, всегда возвращаются в списке некорректных переключателей.
При анализе обычно указываются переключатели и их ожидаемые типы:
iex> OptionParser.parse(["--debug"], strict: [debug: :boolean])
{[debug: true], [], []}
iex> OptionParser.parse(["--source", "lib"], strict: [source: :string])
{[source: "lib"], [], []}
iex> OptionParser.parse(
...> ["--source-path", "lib", "test/enum_test.exs", "--verbose"],
...> strict: [source_path: :string, verbose: :boolean]
...> )
{[source_path: "lib", verbose: true], ["test/enum_test.exs"], []}
Далее мы рассмотрим допустимые переключатели и режимы работы парсера опций.
Параметры
Поддерживаются следующие параметры:
-
:switchesили:strict— см. раздел «Определения переключателей» ниже -
:allow_nonexistent_atoms— см. раздел «Анализ неизвестных переключателей» ниже -
:aliases— см. раздел «Псевдонимы» ниже -
:return_separator— см. раздел «Разделитель возвращаемых значений» ниже
Определения переключателей
Переключатели могут быть заданы с помощью одного из двух параметров:
:strict— определяет строгие переключатели и их типы. Любой переключатель вargv, который не указан в списке, возвращается в списке некорректных параметров. Это предпочтительный способ анализа параметров.:switches— определяет переключатели и их типы. Функция всё ещё пытается проанализировать переключатели, которые не входят в этот список.
Оба этих параметра принимают список ключевых слов, где ключ — атом, определяющий имя переключателя, а значение — type переключателя (подробнее о типах см. раздел «Типы» ниже).
Обратите внимание, что вы должны указать только параметр :switches или параметр :strict. Если вы укажете оба, будет возбуждено исключение ArgumentError.
Типы
Переключатели, анализируемые с помощью OptionParser, могут принимать ноль или один аргумент.
Следующие типы переключателей не принимают аргументов:
-
:boolean— устанавливает значение вtrueпри задании (см. также раздел «Отрицающие переключатели» ниже) -
:count— подсчитывает количество раз, когда переключатель задан
Следующие переключатели принимают один аргумент:
-
:integer— анализирует значение как целое число -
:float— анализирует значение как число с плавающей запятой -
:string— анализирует значение как строку
Если переключатель не может быть проанализирован в соответствии с заданным типом, он возвращается в списке некорректных параметров.
Модификаторы
Переключатели могут быть заданы с модификаторами, которые изменяют их поведение. Поддерживаются следующие модификаторы:
-
:keep— сохраняет дублирующиеся элементы вместо их перезаписи; работает со всеми типами, кроме:count. Указаниеswitch_name: :keepпредполагает, что тип:switch_nameбудет:string.
Чтобы использовать :keep с типом, отличным от :string, используйте список в качестве типа переключателя. Например: [foo: [:integer, :keep]].
Отрицающие переключатели
Если переключатель SWITCH задан с типом :boolean, его можно передать как --no-SWITCH, что установит параметр в false:
iex> OptionParser.parse(["--no-op", "path/to/file"], switches: [op: :boolean])
{[op: false], ["path/to/file"], []}
Анализ неизвестных переключателей
При указании параметра :switches OptionParser будет пытаться проанализировать неизвестные переключатели.
Переключатели без аргументов будут установлены в true:
iex> OptionParser.parse(["--debug"], switches: [key: :string])
{[debug: true], [], []}
Несмотря на то, что мы не указали --debug в списке переключателей, он входит в возвращаемые параметры. То же самое происходит для переключателей, за которыми следует другой переключатель:
iex> OptionParser.parse(["--debug", "--ok"], switches: [])
{[debug: true, ok: true], [], []}
Переключатели, за которыми следует значение, будут присвоены это значение как строка:
iex> OptionParser.parse(["--debug", "value"], switches: [key: :string])
{[debug: "value"], [], []}
Поскольку мы не можем утверждать тип значения переключателя, предпочтительно использовать параметр :strict, который принимает только известные переключатели и всегда проверяет их типы.
Если вы всё же хотите проанализировать неизвестные переключатели, помните, что Elixir преобразует переключатели в атомы. Поскольку атомы не подлежат утилизации, для избежания создания новых атомов, OptionParser по умолчанию анализирует только переключатели, которые переводятся в существующие атомы. Приведённый ниже код отбрасывает переключатель --option-parser-example, потому что атом :option_parser_example нигде не используется:
iex> OptionParser.parse(["--option-parser-example"], switches: [])
{[], [], []}
Если переключатель соответствует существующему атому Elixir, будь то из вашего кода, зависимости или самого Elixir, он будет принят. Однако лучше не полагаться на внешний код и всегда определять атомы, которые вы хотите проанализировать, в том же модуле, что и вызов OptionParser, в качестве непосредственных аргументов к параметрам :switches или :strict.
Если вы хотите проанализировать все переключатели, независимо от их существования, вы можете принудительно создать атомы, передав allow_nonexistent_atoms: true в качестве параметра. Используйте этот параметр с осторожностью. Он полезен только при создании командных приложений, которые получают динамически названные аргументы, и его следует избегать в долгоживущих системах.
Псевдонимы
Набор псевдонимов может быть задан в параметре :aliases:
iex> OptionParser.parse(["-d"], aliases: [d: :debug], strict: [debug: :boolean])
{[debug: true], [], []}
Примеры
Ниже приведены примеры работы с различными типами и модификаторами:
iex> OptionParser.parse(["--unlock", "path/to/file"], strict: [unlock: :boolean])
{[unlock: true], ["path/to/file"], []}
iex> OptionParser.parse(
...> ["--unlock", "--limit", "0", "path/to/file"],
...> strict: [unlock: :boolean, limit: :integer]
...> )
{[unlock: true, limit: 0], ["path/to/file"], []}
iex> OptionParser.parse(["--limit", "3"], strict: [limit: :integer])
{[limit: 3], [], []}
iex> OptionParser.parse(["--limit", "xyz"], strict: [limit: :integer])
{[], [], [{"--limit", "xyz"}]}
iex> OptionParser.parse(["--verbose"], switches: [verbose: :count])
{[verbose: 1], [], []}
iex> OptionParser.parse(["-v", "-v"], aliases: [v: :verbose], strict: [verbose: :count])
{[verbose: 2], [], []}
iex> OptionParser.parse(["--unknown", "xyz"], strict: [])
{[], ["xyz"], [{"--unknown", nil}]}
iex> OptionParser.parse(
...> ["--limit", "3", "--unknown", "xyz"],
...> switches: [limit: :integer]
...> )
{[limit: 3, unknown: "xyz"], [], []}
iex> OptionParser.parse(
...> ["--unlock", "path/to/file", "--unlock", "path/to/another/file"],
...> strict: [unlock: :keep]
...> )
{[unlock: "path/to/file", unlock: "path/to/another/file"], [], []}
Разделитель возвращаемых значений
Разделитель -- подразумевает, что обработка параметров больше не должна производиться. По умолчанию разделитель не возвращается как часть аргументов, но это можно изменить с помощью параметра :return_separator:
iex> OptionParser.parse(["--", "lib"], return_separator: true, strict: [])
{[], ["--", "lib"], []}
iex> OptionParser.parse(["--no-halt", "--", "lib"], return_separator: true, switches: [halt: :boolean])
{[halt: false], ["--", "lib"], []}
iex> OptionParser.parse(["script.exs", "--no-halt", "--", "foo"], return_separator: true, switches: [halt: :boolean])
{[{:halt, false}], ["script.exs", "--", "foo"], []} parse!(argv, opts \\ [])Source
@spec parse!(argv(), options()) :: {parsed(), argv()} То же, что и parse/2, но возбуждает исключение OptionParser.ParseError, если заданы какие-либо некорректные параметры.
В случае отсутствия ошибок возвращает кортеж {parsed, rest}, где:
-
parsed— список проанализированных переключателей (совпадает со списком вparse/2) -
rest— список аргументов (совпадает со списком вparse/2)
Примеры
iex> OptionParser.parse!(["--debug", "path/to/file"], strict: [debug: :boolean])
{[debug: true], ["path/to/file"]}
iex> OptionParser.parse!(["--limit", "xyz"], strict: [limit: :integer])
** (OptionParser.ParseError) 1 error found!
--limit : Expected type integer, got "xyz"
iex> OptionParser.parse!(["--unknown", "xyz"], strict: [])
** (OptionParser.ParseError) 1 error found!
--unknown : Unknown option
iex> OptionParser.parse!(
...> ["-l", "xyz", "-f", "bar"],
...> switches: [limit: :integer, foo: :integer],
...> aliases: [l: :limit, f: :foo]
...> )
** (OptionParser.ParseError) 2 errors found!
-l : Expected type integer, got "xyz"
-f : Expected type integer, got "bar" parse_head(argv, opts \\ [])Source
@spec parse_head(argv(), options()) :: {parsed(), argv(), errors()} Аналогично parse/2, но анализирует только начало argv; как только он находит непереключатель, он прекращает анализ.
См. parse/2 для получения дополнительной информации.
Пример
iex> OptionParser.parse_head(
...> ["--source", "lib", "test/enum_test.exs", "--verbose"],
...> switches: [source: :string, verbose: :boolean]
...> )
{[source: "lib"], ["test/enum_test.exs", "--verbose"], []}
iex> OptionParser.parse_head(
...> ["--verbose", "--source", "lib", "test/enum_test.exs", "--unlock"],
...> switches: [source: :string, verbose: :boolean, unlock: :boolean]
...> )
{[verbose: true, source: "lib"], ["test/enum_test.exs", "--unlock"], []} parse_head!(argv, opts \\ [])Source
@spec parse_head!(argv(), options()) :: {parsed(), argv()} То же, что и parse_head/2, но возбуждает исключение OptionParser.ParseError, если заданы какие-либо некорректные параметры.
В случае отсутствия ошибок возвращает кортеж {parsed, rest}, где:
-
parsed— список проанализированных переключателей (совпадает со списком вparse_head/2) -
rest— список аргументов (совпадает со списком вparse_head/2)
Примеры
iex> OptionParser.parse_head!(
...> ["--source", "lib", "path/to/file", "--verbose"],
...> switches: [source: :string, verbose: :boolean]
...> )
{[source: "lib"], ["path/to/file", "--verbose"]}
iex> OptionParser.parse_head!(
...> ["--number", "lib", "test/enum_test.exs", "--verbose"],
...> strict: [number: :integer]
...> )
** (OptionParser.ParseError) 1 error found!
--number : Expected type integer, got "lib"
iex> OptionParser.parse_head!(
...> ["--verbose", "--source", "lib", "test/enum_test.exs", "--unlock"],
...> strict: [verbose: :integer, source: :integer]
...> )
** (OptionParser.ParseError) 2 errors found!
--verbose : Missing argument of type integer
--source : Expected type integer, got "lib" split(string)Source
@spec split(String.t()) :: argv()
Разделяет строку на argv/0 части.
Эта функция разделяет заданную string на список строк аналогично тому, как это делают многие оболочки.
Примеры
iex> OptionParser.split("foo bar")
["foo", "bar"]
iex> OptionParser.split("foo \"bar baz\"")
["foo", "bar baz"] to_argv(enum, options \\ [])Source
@spec to_argv(Enumerable.t(), options()) :: argv()
Принимает перечислимое значение с парами ключ-значение и преобразует его в argv/0.
Ключи должны быть атомами. Ключи с nil значением отбрасываются, булевы значения преобразуются в --key или --no-key (если значение соответственно true или false ), а все остальные значения преобразуются с помощью to_string/1.
Рекомендуется передавать в to_argv/2 тот же набор options , что и в parse/2. Некоторые переключатели могут быть правильно реконструированы только с :switches информацией.
Примеры
iex> OptionParser.to_argv(foo_bar: "baz") ["--foo-bar", "baz"] iex> OptionParser.to_argv(bool: true, bool: false, discarded: nil) ["--bool", "--no-bool"]
Некоторые переключатели выводят разные значения в зависимости от типа переключателей:
iex> OptionParser.to_argv([number: 2], switches: []) ["--number", "2"] iex> OptionParser.to_argv([number: 2], switches: [number: :count]) ["--number", "--number"]
© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.17.2/OptionParser.html