Home Explore Blog Models CI



nixpkgs

2nd chunk of `doc/languages-frameworks/ruby.section.md`
dc0881500be40e2037d33ac6446ceb355acc8762b8f977b60000000100000fa0
1. We begin with importing the Nix Packages collections. `import <nixpkgs>` imports the `<nixpkgs>` function, `{}` calls it and the `with` statement brings all attributes of `nixpkgs` in the local scope. These attributes form the main package set.
2. Then we create a Ruby environment with the `withPackages` function.
3. The `withPackages` function expects us to provide a function as an argument that takes the set of all ruby gems and returns a list of packages to include in the environment. Here, we select the packages `nokogiri` and `pry` from the package set.

#### Execute command with `--run` {#execute-command-with---run}

A convenient flag for `nix-shell` is `--run`. It executes a command in the `nix-shell`. We can e.g. directly open a `pry` REPL:

```ShellSession
$ nix-shell -p "ruby.withPackages (ps: with ps; [ nokogiri pry ])" --run "pry"
```

Or immediately require `nokogiri` in pry:

```ShellSession
$ nix-shell -p "ruby.withPackages (ps: with ps; [ nokogiri pry ])" --run "pry -rnokogiri"
```

Or run a script using this environment:

```ShellSession
$ nix-shell -p "ruby.withPackages (ps: with ps; [ nokogiri pry ])" --run "ruby example.rb"
```

#### Using `nix-shell` as shebang {#using-nix-shell-as-shebang}

In fact, for the last case, there is a more convenient method. You can add a [shebang](<https://en.wikipedia.org/wiki/Shebang_(Unix)>) to your script specifying which dependencies `nix-shell` needs. With the following shebang, you can just execute `./example.rb`, and it will run with all dependencies.

```ruby
#! /usr/bin/env nix-shell
#! nix-shell -i ruby -p "ruby.withPackages (ps: with ps; [ nokogiri rest-client ])"

require 'nokogiri'
require 'rest-client'

body = RestClient.get('http://example.com').body
puts Nokogiri::HTML(body).at('h1').text
```

## Developing with Ruby {#developing-with-ruby}

### Using an existing Gemfile {#using-an-existing-gemfile}

In most cases, you'll already have a `Gemfile.lock` listing all your dependencies. This can be used to generate a `gemset.nix` which is used to fetch the gems and combine them into a single environment. The reason why you need to have a separate file for this, is that Nix requires you to have a checksum for each input to your build. Since the `Gemfile.lock` that `bundler` generates doesn't provide us with checksums, we have to first download each gem, calculate its SHA256, and store it in this separate file.

So the steps from having just a `Gemfile` to a `gemset.nix` are:

```ShellSession
$ bundle lock
$ bundix
```

If you already have a `Gemfile.lock`, you can run `bundix` and it will work the same.

To update the gems in your `Gemfile.lock`, you may use the `bundix -l` flag, which will create a new `Gemfile.lock` in case the `Gemfile` has a more recent time of modification.

Once the `gemset.nix` is generated, it can be used in a `bundlerEnv` derivation. Here is an example you could use for your `shell.nix`:

```nix
# ...
let
  gems = bundlerEnv {
    name = "gems-for-some-project";
    gemdir = ./.;
  };
in
mkShell {
  packages = [
    gems
    gems.wrappedRuby
  ];
}
```

With this file in your directory, you can run `nix-shell` to build and use the gems. The important parts here are `bundlerEnv` and `wrappedRuby`.

The `bundlerEnv` is a wrapper over all the gems in your gemset. This means that all the `/lib` and `/bin` directories will be available, and the executables of all gems (even of indirect dependencies) will end up in your `$PATH`. The `wrappedRuby` provides you with all executables that come with Ruby itself, but wrapped so they can easily find the gems in your gemset.

One common issue that you might have is that you have Ruby, but also `bundler` in your gemset. That leads to a conflict for `/bin/bundle` and `/bin/bundler`. You can resolve this by wrapping either your Ruby or your gems in a `lowPrio` call. So in order to give the `bundler` from your gemset priority, it would be used like this:

```nix
# ...
mkShell {
  buildInputs = [
    gems

Title: Nix for Ruby Development: Script Execution and Gemfile Integration
Summary
This chunk details advanced usage of Nix for Ruby development. It explains how to use the `nix-shell --run` flag to execute commands directly within a temporary Ruby environment, such as opening a REPL or running a script. A more convenient method for scripts is demonstrated using `nix-shell` as a shebang, allowing Ruby scripts to automatically load required dependencies. For projects with existing `Gemfile.lock` files, the `bundix` tool is introduced. `bundix` generates a `gemset.nix` file, which includes SHA256 checksums for all gems, enabling Nix to manage dependencies securely. This `gemset.nix` is then used with the `bundlerEnv` derivation within a `shell.nix` file to create a project-specific environment. The `bundlerEnv` makes gem executables available in the `$PATH`, and `wrappedRuby` ensures Ruby executables can find these gems. The section concludes by addressing a common conflict between Ruby's `bundler` and a `bundler` gem, suggesting the use of `lowPrio` to resolve it.