I'm working on a Ruby gem that should be used as a CLI utility.
I've decided to use Thor, that is used by the rails
command and seems to be very flexible (on the differences with rake
: link).
The problem is I can't find how to handle input error. For example, if I type in a wrong option, Thor automatically returns a nice warning:
$ myawesomescript blabla
Could not find command "blabla".
But, if I use a command that can't be resolved, things get ugly. For example, there is a "help" default command and I have defined a "hello" command. If I type just "h" this is what I get:
$ myawesomescript h
/Users/Tom/.rvm/gems/ruby-2.0.0-p0/gems/thor-0.18.1/lib/thor.rb:424:in `normalize_command_name': Ambiguous command h matches [hello, help] (ArgumentError)
from /Users/Tom/.rvm/gems/ruby-2.0.0-p0/gems/thor-0.18.1/lib/thor.rb:340:in `dispatch'
from /Users/Tom/.rvm/gems/ruby-2.0.0-p0/gems/thor-0.18.1/lib/thor/base.rb:439:in `start'
from /Users/Tom/Documents/ruby/myawesomescript/bin/myawesomescript:9:in `<top (required)>'
from /Users/Tom/.rvm/gems/ruby-2.0.0-p0/bin/myawesomescript:23:in `load'
from /Users/Tom/.rvm/gems/ruby-2.0.0-p0/bin/myawesomescript:23:in `<main>'
from /Users/Tom/.rvm/gems/ruby-2.0.0-p0/bin/ruby_noexec_wrapper:14:in `eval'
from /Users/Tom/.rvm/gems/ruby-2.0.0-p0/bin/ruby_noexec_wrapper:14:in `<main>'
myawesomescript $
Now, I know that just typing "h" is stupid, and that I could just rename my commands, but I don't want users to see these kind of error messages.
I tried to override that method with:
def normalize_command_name(meth)
super(meth)
rescue ArgumentError => e
puts "print something useful"
end
...but it doesn't work
New details:
OK, I noticed that that method was declared on the class, not the instances. I tried the following and seems to work nicely, but it's not ideal and a bit hacky:
file: lib/myawesomescript/thor_overrides.rb
require 'thor'
class Thor
class << self
protected
def normalize_command_name(meth)
return default_command.to_s.gsub('-', '_') unless meth
possibilities = find_command_possibilities(meth)
if possibilities.size > 1
raise ArgumentError, "Ambiguous command #{meth} matches [#{possibilities.join(', ')}]"
elsif possibilities.size < 1
meth = meth || default_command
elsif map[meth]
meth = map[meth]
else
meth = possibilities.first
end
meth.to_s.gsub('-','_') # treat foo-bar as foo_bar
rescue ArgumentError => e
# do nothing
end
alias normalize_task_name normalize_command_name
end
end
There I added the lines:
rescue ArgumentError => e
# do nothing
And it does the trick, as it seems that somewhere else some piece of code takes care of the error message:
$ myawesomescript h
Could not find command "h".
Anyway, is there a better way?