How can I pass a switch before the command in a Thor app?

137 Views Asked by At

I have a Thor app that requires many of the same parameters for all the commands. The universal parameters are declared with class_option. But I want users to put those before the command.

For example, my users may need to type this sequence...

mycli cmd1 arg1 arg2 --switch1 --switch2=value
mycli cmd2 arg3 arg4 --switch1 --switch2=value
mycli cmd3 arg5 arg6 --switch1 --switch2=value

Each time my user needs to retype or backspace significantly to edit the command line. It would be easier to do this...

mycli --switch1 --switch2=value cmd1 arg1 arg2
mycli --switch1 --switch2=value cmd2 arg3 arg4
mycli --switch1 --switch2=value cmd3 arg5 arg6

In this way, the part that needs to change for each invocation is at the end of the command line, and the parameters that are likely to remain the same are at the start. Command line editing becomes really easy.

Is there any way to support this in Thor?

1

There are 1 best solutions below

0
lacostenycoder On

A brief look at the documentation and examples along with standard ruby conventions would indicate options should be passed last. But here's how you can use a ruby script to "sort" your command line, here's a basic example:

#test.thor

class Test < Thor
  method_option :demo, :aliases => "-d", :desc => "demo"
  method_option :foo, :aliases => "-f", :desc => "foo"
  method_option :bar, :aliases => "-b", :desc => "bar"
  desc "example", "an example task"
  def example
    puts "option switches passed: #{options.to_s}"
  end
end

And your ruby script which you can make exec, alias etc:

#hack.rb

#!/usr/bin/env ruby
args = ARGV
cmd = args.reject{|a| a[0] == '-'}.first
switches = args.select{|a| a[0] == '-'}
cmd_args = args[1..-1] - switches
system_cmd = ['thor', cmd, args, switches].join(' ')
system(system_cmd)

And you could for test purpose invoke it like this:

thor test:example -f -d -b
#=>option switches passed: {"foo"=>"foo", "demo"=>"demo", "bar"=>"bar"}

ruby hack.rb -f -b -d test:example
#=> option switches passed: {"foo"=>"foo", "bar"=>"bar", "demo"=>"demo"}