Исходный код 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 будет пытаться проанализировать неизвестные переключатели:
iex> OptionParser.parse(["--debug"], switches: [key: :string])
{[debug: true], [], []}
Даже если мы не указали --debug в списке переключателей, он является частью возвращаемых параметров. Это также сработает:
iex> OptionParser.parse(["--debug", "value"], switches: [key: :string])
{[debug: "value"], [], []}
Переключатели, за которыми следует значение, будут назначены это значение в виде строки. Переключатели без аргументов будут автоматически установлены в true. Поскольку мы не можем определить тип значения переключателя, предпочтительно использовать параметр :strict, который принимает только известные переключатели и всегда проверяет их типы.
Если вы хотите проанализировать неизвестные переключатели, помните, что Elixir преобразует переключатели в атомы. Поскольку атомы не подлежат сборке мусора, OptionParser будет анализировать только переключатели, которые преобразуются в атомы, используемые временем выполнения, чтобы избежать утечки атомов. Например, следующий код отбросит переключатель --option-parser-example, потому что атом :option_parser_example нигде не используется:
OptionParser.parse(["--option-parser-example"], switches: [debug: :boolean]) # The :option_parser_example atom is not used anywhere below
Однако, следующий код сработает, если атом :option_parser_example используется где-то позже (или раньше) в том же модуле. Например:
{opts, _, _} = OptionParser.parse(["--option-parser-example"], switches: [debug: :boolean])
# ... then somewhere in the same module you access it ...
opts[:option_parser_example]
Другими словами, Elixir будет анализировать только те параметры, которые используются временем выполнения, игнорируя все остальные. Если вы хотите проанализировать все переключатели, независимо от их существования, вы можете принудительно создать атомы, передав 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.16.3/OptionParser.html