diff --git a/lib/tool_kit/cli/spec.ex b/lib/tool_kit/cli/spec.ex index a36093a..6009258 100644 --- a/lib/tool_kit/cli/spec.ex +++ b/lib/tool_kit/cli/spec.ex @@ -21,7 +21,7 @@ defmodule ToolKit.CLI.Spec do defstruct [:tool_name, :tool_summary, :option_catalog, :global_option_names, :commands] @type option_def :: %{ - type: :boolean | :string, + type: :boolean | :string | :integer, alias: atom() | nil, values: [String.t()] | nil, doc: String.t() @@ -78,7 +78,7 @@ defmodule ToolKit.CLI.Spec do end @doc "OptionParser の strict リスト(全オプションの和集合)" - @spec strict_switches(t()) :: [{atom(), :boolean | :string}] + @spec strict_switches(t()) :: [{atom(), :boolean | :string | :integer}] def strict_switches(%__MODULE__{option_catalog: catalog}) do Enum.map(catalog, fn {name, %{type: type}} -> {name, type} end) end @@ -206,7 +206,8 @@ defmodule ToolKit.CLI.Spec do end defp render_option_line(option) do - value = if option.type == :string, do: " #{render_values(option)}", else: "" + # 値を取る型(string / integer)には VALUE プレースホルダを表示する + value = if option.type == :boolean, do: "", else: " #{render_values(option)}" if single_char_name?(option.name) do " -#{option.name}#{value} #{option.doc}" diff --git a/test/tool_kit/cli/spec_test.exs b/test/tool_kit/cli/spec_test.exs index 3c554c6..458cdf4 100644 --- a/test/tool_kit/cli/spec_test.exs +++ b/test/tool_kit/cli/spec_test.exs @@ -1,6 +1,7 @@ defmodule ToolKit.CLI.SpecTest do use ExUnit.Case, async: true + alias ToolKit.CLI.Parser alias ToolKit.CLI.Spec alias ToolKit.Test.RegistryManagerSpecFixture, as: Fixture @@ -45,6 +46,37 @@ defmodule ToolKit.CLI.SpecTest do end end + test "integer options derive strict switches and render a VALUE placeholder" do + spec = %Spec{ + tool_name: "demo", + tool_summary: "demo tool", + option_catalog: %{ + help: %{type: :boolean, alias: :h, values: nil, doc: "help"}, + jobs: %{type: :integer, alias: nil, values: nil, doc: "並列数"} + }, + global_option_names: [:help], + commands: [ + %{ + name: "run", + aliases: [], + usage: ["run"], + summary: "run", + options: [:jobs], + examples: ["run --jobs 4"] + } + ] + } + + assert {:jobs, :integer} in Spec.strict_switches(spec) + assert Spec.render_command_help(spec, "run") =~ "--jobs VALUE" + assert Spec.validate_opts(spec, "run", jobs: 4) == :ok + + # 整数でない値の拒否は OptionParser(strict)の責務で、 + # Parser がパース段階のエラーに変換する + assert {:error, message} = Parser.parse(spec, ["run", "--jobs", "four"]) + assert message =~ "--jobs" + end + test "command option overrides replace values and doc", %{spec: spec} do list_command = Spec.find_command(spec, "list") sort = spec |> Spec.options_for(list_command) |> Enum.find(&(&1.name == :sort))