2016-03-01:
Using Ruby rbenv with tcsh / csh - A Complete Solution
tcsh? |
The Problem |
The Solution |
Installation |
Updates |
Bugs/Errata
tcsh? Really?
Like many people, I use tcsh for my interactive shell.
And I know many of you are prepared to go into a rant now about how
tcsh is a terrible scripting language. I actually agree. But it's
also a fantastic interactive shell. I have no need for my
interactive shell to be a scripting language as well. In fact, I'm
unclear why anyone would use sh/bash as a scripting language.
Yes, bash is better than than tcsh for scripting, but it's inferior to perl/ruby/python/etc..
And regardless of your religious beliefs regarding tcsh, there
are many people who are required to use tcsh. So bash
lovers can hit the "Back" button now, this page is not for you.
The Problem
rbenv is a great system for
managing multiple ruby versions and multiple gemsets.
Unfortunately, rbenv requires bash heavily, it uses a combinations of
"shims" (effectively wrappers to the ruby executables) as well as
some bash functions and evals.
We can partially make use of rbenv by only using the shims, by simply setting
the $PATH variable accordingly, as shown by
HPLOGSDON.
Unfortunately this breaks:
- 'rbenv shell ...'
- 'rbenv rehash'
- 'rbenv init'
- The shell completion settings for rbenv
But that info inspired me to come up with a complete solution.
The Solution
I solved all of this with a wrapper which is eval'd for all rbenv calls, this
is done with an alias that is set when they call the init. So now all you
need to do is put the wrapper in your path as 'rbenvWrap' and then add this
to your .tcshrc:
eval `rbenvWrap init -`
Source your .tcshrc (or logout and login again) and you're done (assuming you've
also installed rbenv). You don't need to worry about the wrapper anymore, all
of your rbenv commands will work just like they do on bash. Example:
tcsh% echo $RBENV_VERSION
RBENV_VERSION: Undefined variable
tcsh% rbenv versions
* system (set by /home/dave/.rbenv/version)
2.1.2
tcsh% ruby -v
ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux]
tcsh% rbenv shell 2.1.2
tcsh% rbenv versions
system
* 2.1.2 (set by RBENV_VERSION environment variable)
tcsh% echo $RBENV_VERSION
2.1.2
Command completion also works, so for example if you hit tab:
tcsh% rbenv sh<tab>
shell shims
tcsh% rbenv shell <tab>
2.1.2 system --unset
tcsh% rbenv shell -<tab>
tcsh% rbenv shell --unset
Magic!
The completion setup happens in the .tcshrc eval and may slow down
some older machines (it takes less than half a second on my 2.5GHz quad core).
It also only works with tcsh, it will give "complete: command not found"
errors with csh. It should detect csh as your shell, but if you want
to be sure to avoid using the completions, then you can just change
the eval line in your .cshrc to: (add 'csh' to the end)
eval `rbenvWrap init - csh`
You can see how long it takes in both cases by timing the commands:
% time rbenvWrap init - > /dev/null
% time rbenvWrap init - csh > /dev/null
For serious power-users you could also take the full complete command
that 'rbenvWrap init -' generates and put it in your .tcshrc and then
not generate it each time, but this also means that future changes
to rbenv completion will not get updated on your system.
Installation
To install:
- Download the 'rbenvWrap' script (it's ruby, of course) and install it in your path.
- Install rbenv. There are simple instructions at the top
of the script as well as available directly from the rbenv
maintainers - just ignore their bash suggestions unless you
wish to use bash as well - they will both work).
- Add the eval `rbenvWrap init -`
to your .tcshrc
I've also included an optional 'gem' wrapper because, much to my
surprise, doing system (root) installs of gems will break unless your
umask is set properly, this is the wrapper I use to make sure the
umask is set to 22. It needs to be extra clever with rbenv so that
it doesn't interfere with the rbenv 'gem' wrapper.
These scripts are licensed under the Creative Commons Attribution 4.0
International for freedom of usability.
Updates
Updated May 2020: The 'rbenv shell' command was now outputting things like:
RBENV_VERSION_OLD="$RBENV_VERSION"
setenv RBENV_VERSION "2.6.0"
So I updated it to handle multiline commands, as well as the fact that
we might have a 'var=$othervar' where $othervar was not defined, something
tcsh does not handle very well.
Bugs/Errata
None that I know of.
If you find any, please feel free to contact me
rbenvWrap is prone to failure on future rbenv versions if the
output of the rbenv eval'd commands changes to something it can't
translate. If that happens let me know and I'll update rbenvWrap (if
possible). Otherwise, this system should still work with general
updates to the rbenv system.
Back to Solutions.