File: ruby.md

package info (click to toggle)
direnv 2.37.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 872 kB
  • sloc: sh: 1,499; csh: 83; makefile: 7
file content (96 lines) | stat: -rw-r--r-- 3,572 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# Manage your rubies with direnv and ruby-install

direnv is just a shell extension that manages your environment variables
depending on the folder you live in. In this article we will explore how it
can be used in combination with
[ruby-install](https://github.com/postmodern/ruby-install) to manage and
select the version of ruby that you want to use in a project.

## The setup

First install direnv. This is the quick version on OSX + Bash:

```bash
brew install direnv
echo 'eval $(direnv hook bash)' >> .bashrc
exec $0
```

Then use [ruby-install](https://github.com/postmodern/ruby-install) to
install a couple of ruby versions. We're also creating a couple of aliases
for convenience.

```
brew install ruby-install
ruby-install ruby 1.9
ruby-install ruby 2.0
cd ~/.rubies
ln -s 1.9.3-p448 1.9.3
ln -s 1.9.3-p448 1.9
ln -s 2.0.0-p247 2.0.0
ln -s 2.0.0-p247 2.0
```

The end goal is that each project will have an `.envrc` file that contains
a descriptive syntax like `use ruby 1.9.3` to selects the right ruby version
for the project.

For that regard we are going to use a couple of commands available in the
[direnv stdlib](/man/direnv-stdlib.1.md) and expand it a bit in the `~/.config/direnv/direnvrc`
file.

Add this to the `~/.config/direnv/direnvrc` file (you have to create it if it doesn't exist):

```bash
# Usage: use ruby <version>
#
# Loads the specified ruby version into the environment
#
use_ruby() {
  local ruby_dir=$HOME/.rubies/$1
  load_prefix $ruby_dir
  layout ruby
}
```

That's it. Now in any project you can run `direnv edit .` and add
`use ruby 1.9.3` or `use ruby 2.0` in the file like you want and direnv will
select the right ruby version when you enter the project's folder.

## A bit of explanation

The last part probably needs a bit more explanation. We make use of a couple
of commands that are part of the [stdlib](/man/direnv-stdlib.1.md) which is available in
the execution context of an envrc.

`use` is a command dispatch that's just there to build the
`use something something` dsl so that `use ruby <version>` will translate into
`use_ruby <version>`.

`load_prefix` will add a couple of things into the environment, notably add
`<prefix>/bin` into the PATH. This is what makes the specified ruby available.

And finally `layout ruby` who like `use` translates into the `layout_ruby`
function call. It's used to describe common project layouts. In the stdlib, the
ruby layout will configure rubygems (with the `GEM_HOME` environment variable)
to install all the gems into the .direnv/ruby/RUBY_VERSION folder under the
project root. This is a bit similar to rvm's gemsets except that they live
inside your project's folder. It also configures bundler to install wrapper
shims into the .direnv/bin folder which allows you to invoke the commands
directly instead of prefixing your ruby programs with `bundle exec` all the
time.

## Conclusion

As you see this approach is not restricted to ruby. You could have various
versions of python installed under ~/.pythons and a `use_python` defined in
your ~/.direnvrc. Or perl, php, ...  This is the good thing about direnv, it's
not restricted to a single language.

Actually, wouldn't it be great to have all your project's dependencies
available when you enter the project folder ? Not only your ruby version but
also the exact redis or mysql or ... version that you want to use, without
having to start a VM. I think that's definitely possible using something like
the [Nix package manager](http://nixos.org/nix/), something that still needs
to be explored in a future post.