1<section xmlns="http://docbook.org/ns/docbook"
2 xmlns:xlink="http://www.w3.org/1999/xlink"
3 xml:id="sec-language-ruby">
4 <title>Ruby</title>
5
6 <para>
7 There currently is support to bundle applications that are packaged as Ruby
8 gems. The utility "bundix" allows you to write a
9 <filename>Gemfile</filename>, let bundler create a
10 <filename>Gemfile.lock</filename>, and then convert this into a nix
11 expression that contains all Gem dependencies automatically.
12 </para>
13
14 <para>
15 For example, to package sensu, we did:
16 </para>
17
18<screen>
19<![CDATA[$ cd pkgs/servers/monitoring
20$ mkdir sensu
21$ cd sensu
22$ cat > Gemfile
23source 'https://rubygems.org'
24gem 'sensu'
25$ $(nix-build '<nixpkgs>' -A bundix --no-out-link)/bin/bundix --magic
26$ cat > default.nix
27{ lib, bundlerEnv, ruby }:
28
29bundlerEnv rec {
30 name = "sensu-${version}";
31
32 version = (import gemset).sensu.version;
33 inherit ruby;
34 # expects Gemfile, Gemfile.lock and gemset.nix in the same directory
35 gemdir = ./.;
36
37 meta = with lib; {
38 description = "A monitoring framework that aims to be simple, malleable, and scalable";
39 homepage = http://sensuapp.org/;
40 license = with licenses; mit;
41 maintainers = with maintainers; [ theuni ];
42 platforms = platforms.unix;
43 };
44}]]>
45</screen>
46
47 <para>
48 Please check in the <filename>Gemfile</filename>,
49 <filename>Gemfile.lock</filename> and the <filename>gemset.nix</filename> so
50 future updates can be run easily.
51 </para>
52
53 <para>
54 Updating Ruby packages can then be done like this:
55 </para>
56
57<screen>
58<![CDATA[$ cd pkgs/servers/monitoring/sensu
59$ nix-shell -p bundler --run 'bundle lock --update'
60$ nix-shell -p bundix --run 'bundix'
61]]>
62</screen>
63
64 <para>
65 For tools written in Ruby - i.e. where the desire is to install a package and
66 then execute e.g. <command>rake</command> at the command line, there is an
67 alternative builder called <literal>bundlerApp</literal>. Set up the
68 <filename>gemset.nix</filename> the same way, and then, for example:
69 </para>
70
71<screen>
72<![CDATA[{ lib, bundlerApp }:
73
74bundlerApp {
75 pname = "corundum";
76 gemdir = ./.;
77 exes = [ "corundum-skel" ];
78
79 meta = with lib; {
80 description = "Tool and libraries for maintaining Ruby gems.";
81 homepage = https://github.com/nyarly/corundum;
82 license = licenses.mit;
83 maintainers = [ maintainers.nyarly ];
84 platforms = platforms.unix;
85 };
86}]]>
87</screen>
88
89 <para>
90 The chief advantage of <literal>bundlerApp</literal> over
91 <literal>bundlerEnv</literal> is the executables introduced in the
92 environment are precisely those selected in the <literal>exes</literal> list,
93 as opposed to <literal>bundlerEnv</literal> which adds all the executables
94 made available by gems in the gemset, which can mean e.g.
95 <command>rspec</command> or <command>rake</command> in unpredictable versions
96 available from various packages.
97 </para>
98
99 <para>
100 Resulting derivations for both builders also have two helpful attributes,
101 <literal>env</literal> and <literal>wrappedRuby</literal>. The first one
102 allows one to quickly drop into <command>nix-shell</command> with the
103 specified environment present. E.g. <command>nix-shell -A sensu.env</command>
104 would give you an environment with Ruby preset so it has all the libraries
105 necessary for <literal>sensu</literal> in its paths. The second one can be
106 used to make derivations from custom Ruby scripts which have
107 <filename>Gemfile</filename>s with their dependencies specified. It is a
108 derivation with <command>ruby</command> wrapped so it can find all the needed
109 dependencies. For example, to make a derivation <literal>my-script</literal>
110 for a <filename>my-script.rb</filename> (which should be placed in
111 <filename>bin</filename>) you should run <command>bundix</command> as
112 specified above and then use <literal>bundlerEnv</literal> like this:
113 </para>
114
115<programlisting>
116<![CDATA[let env = bundlerEnv {
117 name = "my-script-env";
118
119 inherit ruby;
120 gemfile = ./Gemfile;
121 lockfile = ./Gemfile.lock;
122 gemset = ./gemset.nix;
123};
124
125in stdenv.mkDerivation {
126 name = "my-script";
127 buildInputs = [ env.wrappedRuby ];
128 script = ./my-script.rb;
129 buildCommand = ''
130 install -D -m755 $script $out/bin/my-script
131 patchShebangs $out/bin/my-script
132 '';
133}]]>
134</programlisting>
135</section>