Search code examples
rubycommand-line-interfacethor

ARGV processers: how to define command "foo" which is invoked by any unambiguous prefix


I'd like to define a command line app "cla" with commands "foo", "bar", and "find" such that:

./cla foo and ./cla fo both invoke the method defined for foo

./cla find and ./cla fi both invoke find

./cla bar and ./cla b both invoke the method defined for bar

./cla f throws an error

Or something reasonably similar. Hopefully this is clear.

It's not obvious that this can be done in Thor or Commander. I haven't looked at Slop. Do any of the ARGV processor libraries have this ability? Can somebody tell me which libraries, and point me to documentation of the feature?

EDIT: To be clear, I'm not asking for help solving the specific problem above. I'm asking whether it is possible (and not too difficult) to do it with one of the standard command line app builder libraries, which provide many useful features I want besides the ability to invoke a command by a prefix of its name.


Solution

  • Actually, it seems that thor automatically does what you want out of the box. Specifically, it executes the appropriate command if the shortened form unambiguously matches.

    Given this trivial example:

    #!/usr/bin/env ruby
    
    require "thor"
    
    class CLA < Thor
      desc "foo", 'Says "foo"'
      def foo
        puts "foo"
      end
    
      desc "find", 'Says "find"'
      def find
        puts "find"
      end
    
      desc "bar", 'Says "bar"'
      def bar
        puts "bar"
      end
    end
    
    CLA.start
    

    Then:

    $ ./cla fo
    foo
    $ ./cla f
    Ambiguous command f matches [find, foo]
    $ ./cla fi
    find
    $ ./cla b
    bar
    

    If you really want "f" to always map to "foo" and not give the ambiguous command error, use map like this:

    desc "foo", 'Says "foo"'
    def foo
      puts "foo"
    end
    map "f" => :foo
    

    And then this now works:

    $ ./cla f
    foo