diff --git a/lib/dry/cli/banner.rb b/lib/dry/cli/banner.rb index bb1a474..b73f9ea 100644 --- a/lib/dry/cli/banner.rb +++ b/lib/dry/cli/banner.rb @@ -83,14 +83,13 @@ def self.command_options(command) # @since 0.1.0 # @api private def self.arguments(command) - required_arguments = command.required_arguments - optional_arguments = command.optional_arguments - - required = required_arguments.map { |arg| arg.name.upcase }.join(" ") if required_arguments.any? # rubocop:disable Layout/LineLength - optional = optional_arguments.map { |arg| "[#{arg.name.upcase}]" }.join(" ") if optional_arguments.any? # rubocop:disable Layout/LineLength - result = [required, optional].compact + args = command.arguments_sorted_by_usage_order + args.map! do |a| + name = a.required? ? a.name.to_s : "[#{a.name}]" + name.upcase! + end - " #{result.join(" ")}" unless result.empty? + " #{args.join(" ")}" unless args.empty? end # @since 0.1.0 diff --git a/lib/dry/cli/command.rb b/lib/dry/cli/command.rb index 3e6a601..d0147c4 100644 --- a/lib/dry/cli/command.rb +++ b/lib/dry/cli/command.rb @@ -340,6 +340,31 @@ def self.optional_arguments arguments.reject(&:required?) end + # @since 1.3.0 + # @api private + # rubocop:disable Metrics/PerceivedComplexity + def self.arguments_sorted_by_usage_order + args = required_arguments + optional_arguments + + args.sort! do |a1, a2| + a1_priority = a2_priority = 0 + + a1_priority += 2 unless a1.array? + a2_priority += 2 unless a2.array? + a1_priority += 1 if a1.required? + a2_priority += 1 if a2.required? + + if a1_priority > a2_priority + -1 + elsif a2_priority > a1_priority + 1 + else + 0 + end + end + end + # rubocop:enable Metrics/PerceivedComplexity + # @since 0.7.0 # @api private def self.subcommands @@ -377,6 +402,7 @@ def self.superclass_options default_params required_arguments optional_arguments + arguments_sorted_by_usage_order subcommands ] => "self.class" end diff --git a/lib/dry/cli/usage.rb b/lib/dry/cli/usage.rb index c547148..a645144 100644 --- a/lib/dry/cli/usage.rb +++ b/lib/dry/cli/usage.rb @@ -54,14 +54,13 @@ def self.commands_and_arguments(result) def self.arguments(command) return unless CLI.command?(command) - required_arguments = command.required_arguments - optional_arguments = command.optional_arguments - - required = required_arguments.map { |arg| arg.name.upcase }.join(" ") if required_arguments.any? # rubocop:disable Layout/LineLength - optional = optional_arguments.map { |arg| "[#{arg.name.upcase}]" }.join(" ") if optional_arguments.any? # rubocop:disable Layout/LineLength - result = [required, optional].compact + args = command.arguments_sorted_by_usage_order + args.map! do |a| + name = a.required? ? a.name.to_s : "[#{a.name}]" + name.upcase! + end - " #{result.join(" ")}" unless result.empty? + " #{args.join(" ")}" unless args.empty? end # @since 0.1.0 diff --git a/spec/integration/rendering_spec.rb b/spec/integration/rendering_spec.rb index 3b0209d..9c97ebf 100644 --- a/spec/integration/rendering_spec.rb +++ b/spec/integration/rendering_spec.rb @@ -13,7 +13,7 @@ foo console # Starts Foo console foo db [SUBCOMMAND] foo destroy [SUBCOMMAND] - foo exec TASK [DIRS] # Execute a task + foo exec TASK DIRS # Execute a task foo generate [SUBCOMMAND] foo greeting [RESPONSE] foo hello # Print a greeting diff --git a/spec/integration/spell_checker_spec.rb b/spec/integration/spell_checker_spec.rb index 30ab94a..0887fd2 100644 --- a/spec/integration/spell_checker_spec.rb +++ b/spec/integration/spell_checker_spec.rb @@ -14,7 +14,7 @@ foo console # Starts Foo console foo db [SUBCOMMAND] foo destroy [SUBCOMMAND] - foo exec TASK [DIRS] # Execute a task + foo exec TASK DIRS # Execute a task foo generate [SUBCOMMAND] foo greeting [RESPONSE] foo hello # Print a greeting diff --git a/spec/support/fixtures/foo b/spec/support/fixtures/foo index bf37e0f..4d35033 100755 --- a/spec/support/fixtures/foo +++ b/spec/support/fixtures/foo @@ -344,8 +344,8 @@ module Foo class Exec < Dry::CLI::Command desc "Execute a task" + argument :dirs, desc: "Directories", type: :array, required: true argument :task, desc: "Task to execute", type: :string, required: true - argument :dirs, desc: "Directories", type: :array, required: false def call(task:, dirs: [], **) puts "exec - Task: #{task} - Directories: #{dirs.inspect}"