Method_missing for command shell?

Hi all. My bash-fu is a little bit lacking, so here’s my question.

I’m wondering if anybody knows of a shell that can be programmed to
“guess” what you meant when you type in a command errantly, like (kind
of a bad example, but…)

$ git dif

(it runs git dif, fails, then, in method_missing style, I can tell it
“oh what I always means when I run git dif is git diff” so it correct
its for me and runs it).

Any pointers on where to go there?
Thanks.
-r

Try zsh
-Mario.


I want to change the world but they won’t give me the source code.

Mario C. wrote:

Try zsh

Interesting. Seeing the syntax that zsh uses makes me want to rewrite
the whole thing just so I can use ruby for command completions LOL :slight_smile:

-r

Roger P. wrote:

Mario C. wrote:

Try zsh

Interesting. Seeing the syntax that zsh uses makes me want to rewrite
the whole thing just so I can use ruby for command completions LOL :slight_smile:

-r

You’re welcome to write your own shell in Ruby :wink:

On Oct 5, 8:33 am, Roger P. [email protected] wrote:

its for me and runs it).

Any pointers on where to go there?

I’m writing a ruby command/task execution gem which could allow for
easy ruby wrapping of system commands and method_missing-fu for
subcommands: GitHub - cldwalker/boson: A command/task framework similar to rake and thor built with extendability in mind.

I already do subcommand method_missing with boson, not for guessing
but for smart aliasing:
http://github.com/cldwalker/irbfiles/blob/master/boson/commands/boson_method_missing.rb#L10-25

Here’s how you could define a simple Boson library that wraps git
subcommands:

module Git
%w{add checkout diff rm merge pull push}.each do |e|
define_method(e) do |*args|
system(‘git’, e, *args)
end
end
end

With boson you would be able to execute these subcommands from the
commandline or irb as follows:

bash> boson git.diff
irb>> git.diff

With the above method_missing library you could execute these as git.d
or git.dif

Unfortunately Boson isn’t ready yet. Hopefully within the week. In the
mean time you could take that example
module and use it within irb:

def git
@git ||= Object.new.extend Git
end

class << git
def method_missing(meth, *args, &block)
if !(meths = Git.instance_methods.sort.grep(/^#{meth}/)).empty?
send(meths[0].to_sym, *args, &block)
else
super
end
end
end

On Mon, Oct 5, 2009 at 11:28 AM, Aldric G. [email protected]
wrote:

Interesting. Seeing the syntax that zsh uses makes me want to rewrite
the whole thing just so I can use ruby for command completions LOL :slight_smile:

You’re welcome to write your own shell in Ruby :wink:

or start with http://rush.heroku.com/

Roger P. wrote:

Any pointers on where to go there?
Well, kind of. You might use PROMPT_COMMAND in bash to react if
the last command failed (as in the above case of a misspelled
second argument). Or you could use a command_not_found_handle
function (new in bash 4.0, see the manual) as a hook for a
misspelled binary name, and go from there. Maybe both.

Here’s something I hacked together using the first method. It
works a bit different from your suggestion in that it uses compgen
to guess the possible corrections for the second argument
(checking first if there is a completion function for this
command), then uses the builtin select command to query the user
for a correction, and then runs the corrected command. So it will
ask you if you meant “git diff” or “git difftool” in the case of
“git dif” failing. (Note that git’s completion already asks a “did
you mean” question, so it’s a little redundant here…)

Not exactly what you asked for (still fails for “git dfif”), and
probably not perfect, but maybe it’s a pointer to start from :wink:

So, here’s the code to source into bash:

last_commandline () {

fetch the last commandline from the history

local histtimeformat=$HISTTIMEFORMAT
unset HISTTIMEFORMAT

[[ $(history 1) =~ \ +[0-9]+?\ +(.+?) ]]
local commandline=${BASH_REMATCH[1]}

if [[ “$histtimeformat” != “” ]]; then
HISTTIMEFORMAT=$histtimeformat
fi
echo “$commandline”
}

correct () {
args=($*)
rest="${args[@]:2}" # third to last arg

if type -t “_$1” &>/dev/null; then
# there’s a completion function for this command
# get possible completions for the incomplete second argument
comps=($(compgen -W “$(compgen -F _$1 2>/dev/null)” – $2))

# let the user choose, then run the corrected command
select choice in ${comps[@]}; do
  echo "running corrected command: $1 $choice $rest";
  $1 $choice $rest
  break;
done

fi
}

we’ll use the prompt command as a hook for failed commands

PROMPT_COMMAND=’[[ ! $? -eq 0 ]] && correct $(last_commandline)’

Here’s something I hacked together using the first method. It

Not exactly what you asked for (still fails for “git dfif”), and
probably not perfect, but maybe it’s a pointer to start from :wink:

Nice.

yeah and let me know when it’s done and has the same feature set as Bash

what feature set would you require?

-r

yeah and let me know when it’s done and has the same feature set
as bash, then I’ll come over and kiss your feet and pay you a drink
:wink:

Greetz!