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