From 8bc59333c217ebe007daa28cbbfb8530518d56d2 Mon Sep 17 00:00:00 2001 From: Gustavo Ribeiro Date: Sat, 14 Dec 2024 14:28:07 -0300 Subject: [PATCH] Fix arguments with `values` allowing any value --- lib/dry/cli/errors.rb | 4 ++++ lib/dry/cli/option.rb | 13 +++++++++++++ lib/dry/cli/parser.rb | 17 +++++++++++------ spec/support/fixtures/foo | 2 +- spec/support/fixtures/shared_commands.rb | 2 +- spec/support/shared_examples/commands.rb | 7 +++++++ 6 files changed, 37 insertions(+), 8 deletions(-) diff --git a/lib/dry/cli/errors.rb b/lib/dry/cli/errors.rb index e9ca3809..8db8271e 100644 --- a/lib/dry/cli/errors.rb +++ b/lib/dry/cli/errors.rb @@ -9,6 +9,10 @@ class CLI class Error < StandardError end + # @since 1.3.0 + class UnknownValueError < Error + end + # @since 0.2.1 class UnknownCommandError < Error # @since 0.2.1 diff --git a/lib/dry/cli/option.rb b/lib/dry/cli/option.rb index 710de980..5f4a8a7a 100644 --- a/lib/dry/cli/option.rb +++ b/lib/dry/cli/option.rb @@ -121,6 +121,19 @@ def alias_names .map { |name| name.size == 1 ? "-#{name}" : "--#{name}" } .map { |name| boolean? || flag? ? name : "#{name} VALUE" } end + + # @since 1.3.0 + # @api private + def valid_value?(value) + available_values = values + return true if available_values.nil? + + if array? + (value - available_values).empty? + else + available_values.map(&:to_s).include?(value.to_s) + end + end end # Command line argument diff --git a/lib/dry/cli/parser.rb b/lib/dry/cli/parser.rb index aac127f0..778e2298 100644 --- a/lib/dry/cli/parser.rb +++ b/lib/dry/cli/parser.rb @@ -31,7 +31,7 @@ def self.call(command, arguments, prog_name) parsed_options = command.default_params.merge(parsed_options) parse_required_params(command, arguments, prog_name, parsed_options) - rescue ::OptionParser::ParseError + rescue ::OptionParser::ParseError, UnknownValueError Result.failure("ERROR: \"#{prog_name}\" was called with arguments \"#{original_arguments.join(" ")}\"") # rubocop:disable Layout/LineLength end @@ -40,8 +40,8 @@ def self.call(command, arguments, prog_name) # # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity def self.parse_required_params(command, arguments, prog_name, parsed_options) - parsed_params = match_arguments(command.arguments, arguments) - parsed_required_params = match_arguments(command.required_arguments, arguments) + parsed_params = match_arguments(command.arguments, arguments, parsed_options) + parsed_required_params = match_arguments(command.required_arguments, arguments, parsed_options) all_required_params_satisfied = command.required_arguments.all? { |param| !parsed_required_params[param.name].nil? } # rubocop:disable Layout/LineLength unused_arguments = arguments.drop(command.required_arguments.length) @@ -69,15 +69,20 @@ def self.parse_required_params(command, arguments, prog_name, parsed_options) end # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity - def self.match_arguments(command_arguments, arguments) + def self.match_arguments(command_arguments, arguments, default_values) result = {} + arg = nil command_arguments.each_with_index do |cmd_arg, index| if cmd_arg.array? - result[cmd_arg.name] = arguments[index..] + arg = arguments[index..] || default_values[cmd_arg.name] + raise UnknownValueError unless cmd_arg.valid_value?(arg) + result[cmd_arg.name] = arg break else - result[cmd_arg.name] = arguments.at(index) + arg = arguments.at(index) || default_values[cmd_arg.name] + raise UnknownValueError unless cmd_arg.valid_value?(arg) + result[cmd_arg.name] = arg end end diff --git a/spec/support/fixtures/foo b/spec/support/fixtures/foo index bf37e0f0..1bf41ddc 100755 --- a/spec/support/fixtures/foo +++ b/spec/support/fixtures/foo @@ -91,7 +91,7 @@ module Foo class Rollback < Dry::CLI::Command desc "Rollback the database" - argument :steps, desc: "Number of versions to rollback", default: 1 + argument :steps, desc: "Number of versions to rollback", default: 1, values: [1, 2, 3] def call(steps:, **) puts steps diff --git a/spec/support/fixtures/shared_commands.rb b/spec/support/fixtures/shared_commands.rb index f694cd93..00afd387 100644 --- a/spec/support/fixtures/shared_commands.rb +++ b/spec/support/fixtures/shared_commands.rb @@ -82,7 +82,7 @@ def call(*); end class Rollback < Dry::CLI::Command desc "Rollback the database" - argument :steps, desc: "Number of versions to rollback", default: 1 + argument :steps, desc: "Number of versions to rollback", default: 1, values: [1, 2, 3] def call(steps:, **) puts steps diff --git a/spec/support/shared_examples/commands.rb b/spec/support/shared_examples/commands.rb index 45222010..133ffa06 100644 --- a/spec/support/shared_examples/commands.rb +++ b/spec/support/shared_examples/commands.rb @@ -106,6 +106,13 @@ expect(error).to eq("ERROR: \"rspec console\" was called with arguments \"--engine=unknown\"\n") end end + + context "with an unknown argument" do + it "prints error" do + error = capture_error { cli.call(arguments: %w[db rollback 4]) } + expect(error).to eq("ERROR: \"rspec db rollback\" was called with arguments \"4\"\n") + end + end end it "with help param" do