rails / thor

Thor is a toolkit for building powerful command-line interfaces.
http://whatisthor.com/
MIT License
5.11k stars 552 forks source link

Hash type is not supported by the repeatable option. #768

Open patrick-motard opened 2 years ago

patrick-motard commented 2 years ago

Here is an example to replicate the bug, as well as examples of running it, including the output and expected output. Repeatable options don't seem to work with the hash type.

#!/usr/bin/env ruby
# frozen_string_literal: true

require "thor"

class ExampleCLI < Thor
  desc "example", "shows how broken things are"
  option :doesnt,
    :required => false,
    :default => {},
    :repeatable => true,
    :type => :hash,
    :desc => "Should be repeatable but isn't"
  option :works,
    :repeatable => true,
    :required => false,
    :type => :string
  def create()
    puts options
  end

  def self.exit_on_failure?
    true
  end
end

ExampleCLI.start(ARGV)

You hand in two hashes and expect them to be set as two hashes in an array. What do you get? one hash, not in an array, with all key/vals merged into one hash.

./script/example create --works string1 --works string2 --doesnt key1:value1 key2:value2 --doesnt key3:val3 key4:val4
{"doesnt"=>{"key1"=>"value1", "key2"=>"value2", "key3"=>"val3", "key4"=>"val4"}, "works"=>["string1", "string2"]}

Instead, you should end up with an array of two different hashes:

{"doesnt"=>[{"key1"=>"value1", "key2"=>"value2"}, {"key3"=>"val3", "key4"=>"val4"}], "works"=>["string1", "string2"]}

Ordering doesn't seem to matter. It's still broken.

 ./script/example create --doesnt key3:val3 key4:val4 --works string1 --works string2 --doesnt key1:value1 key2:value2
{"doesnt"=>{"key3"=>"val3", "key4"=>"val4", "key1"=>"value1", "key2"=>"value2"}, "works"=>["string1", "string2"]}

if your keys in your objects are the same, youll end up with one object whos key values are the last ones you handed in.

./script/example create --works string1 --works string2 --doesnt key1:value1 key2:value2 --doesnt key1:dup1 key2:dup3
{"doesnt"=>{"key1"=>"dup1", "key2"=>"dup3"}, "works"=>["string1", "string2"]}

Instead, you should end up with an array of two different hashes:

{"doesnt"=>[{"key1"=>"value1", "key2"=>"value2"}, {"key1"=>"dup1", "key2"=>"dup3"}], "works"=>["string1", "string2"]}