Did You Mean?
Ruby ships with a bunch of standard gems that act as a standard library of sorts. One of these gems is did_you_mean, which provides helpful error messages when you call a method that doesn't exist on an object, by suggesting similar method names that do exist:
"hello".upcasee
# NoMethodError: undefined method `upcasee' for "hello":String
# Did you mean? upcase
# upcase!
"hello".toUpperCasee();
// TypeError: "hello".toUpperCasee is not a function
A nice example of Ruby's attention to detail on the developer experience front.
But we can also make use of this gem manually in our own codebases, e.g. to improve the user experience of our CLI tools. Pop this code into a file called lovable-cli, chmod +x it, and try running it:
#!/usr/bin/env ruby # Commands are defined as plain methods non_commands = private_methods.dup def hello puts "Hello!" end def hello_world puts "Hello, world!" end commands = (private_methods - non_commands).map(&:to_s) # Show usage if no command is given if ARGV.empty? puts "Usage: lovable-cli" puts puts "Available commands:" puts commands.map { it.tr("_", ":") }.join("\n") exit end # Dispatch command command = ARGV.first method = command.tr(":", "_") if commands.include?(method) send(method) else did_you_mean = DidYouMean::SpellChecker.new(dictionary: commands) .correct(method) .map { |suggestion| suggestion.tr("_", ":") } puts "Error: no command called '#{command}'" puts "Did you mean #{did_you_mean.join(' or ')}?" unless did_you_mean.empty? abort end # Output: # $ lovable-cli hello:world # Hello, world! # $ lovable-cli hello:wrld # Error: no command called 'hello:wrld' # Did you mean hello:world?
Pretty neat, right?
I went all in on this approach when creating the heroku-like CLI tool for Reclaim The Stack. It's about 3,000 lines of code in a single file, with mostly self-contained methods as commands.
Call me crazy, but it's the most maintainable codebase I've ever worked on by far!
History
The did_you_mean gem was first published on RubyGems in 2014 and added as a standard gem, including integration to provide improved error messages, in Ruby 2.3 in 2015.