about summary refs log tree commit diff
path: root/pkgs/development
diff options
context:
space:
mode:
authorFrederik Rietdijk <fridh@fridh.nl>2017-07-29 13:08:11 +0200
committerFrederik Rietdijk <fridh@fridh.nl>2017-07-29 13:08:11 +0200
commitb2608b891062dcc95e50f00c304b297a727adf97 (patch)
tree8b5c8773a75724455e3b67cb563ea84b0f9ec5e5 /pkgs/development
parent55357de67a2acfb11ba1a3633454c20acc9b54e7 (diff)
parent140f47eb748f9b24a77fa40a1f1ffd2376a24b81 (diff)
downloadnixlib-b2608b891062dcc95e50f00c304b297a727adf97.tar
nixlib-b2608b891062dcc95e50f00c304b297a727adf97.tar.gz
nixlib-b2608b891062dcc95e50f00c304b297a727adf97.tar.bz2
nixlib-b2608b891062dcc95e50f00c304b297a727adf97.tar.lz
nixlib-b2608b891062dcc95e50f00c304b297a727adf97.tar.xz
nixlib-b2608b891062dcc95e50f00c304b297a727adf97.tar.zst
nixlib-b2608b891062dcc95e50f00c304b297a727adf97.zip
Merge remote-tracking branch 'upstream/master' into HEAD
Diffstat (limited to 'pkgs/development')
-rw-r--r--pkgs/development/haskell-modules/lib.nix2
-rw-r--r--pkgs/development/libraries/frei0r/default.nix4
-rw-r--r--pkgs/development/node-packages/node-packages-v6.json1
-rw-r--r--pkgs/development/node-packages/node-packages-v6.nix19
-rw-r--r--pkgs/development/python-modules/Cython/default.nix57
-rw-r--r--pkgs/development/python-modules/amqplib/default.nix8
-rw-r--r--pkgs/development/python-modules/blaze/default.nix75
-rw-r--r--pkgs/development/python-modules/cycler/default.nix37
-rw-r--r--pkgs/development/python-modules/sounddevice/default.nix34
-rw-r--r--pkgs/development/ruby-modules/bundled-common/default.nix156
-rw-r--r--pkgs/development/ruby-modules/bundled-common/functions.nix75
-rw-r--r--pkgs/development/ruby-modules/bundled-common/gen-bin-stubs.rb (renamed from pkgs/development/ruby-modules/bundler-env/gen-bin-stubs.rb)0
-rw-r--r--pkgs/development/ruby-modules/bundled-common/test.nix50
-rw-r--r--pkgs/development/ruby-modules/bundler-app/default.nix48
-rw-r--r--pkgs/development/ruby-modules/bundler-env/default.nix164
-rw-r--r--pkgs/development/ruby-modules/bundler-env/test.nix33
-rw-r--r--pkgs/development/ruby-modules/bundler-env/test/Gemfile0
-rw-r--r--pkgs/development/ruby-modules/bundler-env/test/Gemfile.lock0
-rw-r--r--pkgs/development/ruby-modules/bundler-env/test/gemset.nix10
-rw-r--r--pkgs/development/ruby-modules/gem/default.nix1
-rwxr-xr-xpkgs/development/ruby-modules/runtests.sh6
-rw-r--r--pkgs/development/ruby-modules/testing/assertions.nix28
-rw-r--r--pkgs/development/ruby-modules/testing/driver.nix20
-rw-r--r--pkgs/development/ruby-modules/testing/stubs.nix33
-rw-r--r--pkgs/development/ruby-modules/testing/tap-support.nix21
-rw-r--r--pkgs/development/ruby-modules/testing/testing.nix62
-rw-r--r--pkgs/development/tools/ammonite/default.nix4
-rw-r--r--pkgs/development/tools/corundum/Gemfile3
-rw-r--r--pkgs/development/tools/corundum/Gemfile.lock56
-rw-r--r--pkgs/development/tools/corundum/default.nix15
-rw-r--r--pkgs/development/tools/corundum/gemset.nix154
31 files changed, 1038 insertions, 138 deletions
diff --git a/pkgs/development/haskell-modules/lib.nix b/pkgs/development/haskell-modules/lib.nix
index 81cf298e0e61..30d82d3efc93 100644
--- a/pkgs/development/haskell-modules/lib.nix
+++ b/pkgs/development/haskell-modules/lib.nix
@@ -111,6 +111,4 @@ rec {
   overrideSrc = drv: { src, version ? drv.version }:
     overrideCabal drv (_: { inherit src version; editedCabalFile = null; });
 
-  hasNoDataOutput = drv: overrideCabal drv (drv: { hasDataDir = false; });
-  hasNoDocOutput = drv: overrideCabal drv (drv: { hasDocDir = false; });
 }
diff --git a/pkgs/development/libraries/frei0r/default.nix b/pkgs/development/libraries/frei0r/default.nix
index f3c9b95d6b47..9614762ef2a3 100644
--- a/pkgs/development/libraries/frei0r/default.nix
+++ b/pkgs/development/libraries/frei0r/default.nix
@@ -2,11 +2,11 @@
 
 stdenv.mkDerivation rec {
   name = "frei0r-plugins-${version}";
-  version = "1.4";
+  version = "1.6.1";
 
   src = fetchurl {
     url = "https://files.dyne.org/frei0r/releases/${name}.tar.gz";
-    sha256 = "0mxyhdp1p1a3ga8170ijygb870zwbww1dgp3kdr1nd4zvsmzqw44";
+    sha256 = "0pji26fpd0dqrx1akyhqi6729s394irl73dacnyxk58ijqq4dhp0";
   };
 
   buildInputs = [ autoconf cairo opencv pkgconfig ];
diff --git a/pkgs/development/node-packages/node-packages-v6.json b/pkgs/development/node-packages/node-packages-v6.json
index 627f6bf4b880..b50b47ac0a93 100644
--- a/pkgs/development/node-packages/node-packages-v6.json
+++ b/pkgs/development/node-packages/node-packages-v6.json
@@ -8,6 +8,7 @@
 , "coffee-script"
 , "cordova"
 , "csslint"
+, "dhcp"
 , "dnschain"
 , "docker-registry-server"
 , "elasticdump"
diff --git a/pkgs/development/node-packages/node-packages-v6.nix b/pkgs/development/node-packages/node-packages-v6.nix
index e241864f0820..31e5dddd6fdb 100644
--- a/pkgs/development/node-packages/node-packages-v6.nix
+++ b/pkgs/development/node-packages/node-packages-v6.nix
@@ -22688,6 +22688,25 @@ in
     };
     production = true;
   };
+  dhcp = nodeEnv.buildNodePackage {
+    name = "dhcp";
+    packageName = "dhcp";
+    version = "0.2.9";
+    src = fetchurl {
+      url = "https://registry.npmjs.org/dhcp/-/dhcp-0.2.9.tgz";
+      sha1 = "204208be1cef2788d528744fb263f60a528363a2";
+    };
+    dependencies = [
+      sources."minimist-1.2.0"
+    ];
+    buildInputs = globalBuildInputs;
+    meta = {
+      description = "A DHCP server written in JavaScript";
+      homepage = https://github.com/infusion/node-dhcp;
+      license = "MIT OR GPL-2.0";
+    };
+    production = true;
+  };
   dnschain = nodeEnv.buildNodePackage {
     name = "dnschain";
     packageName = "dnschain";
diff --git a/pkgs/development/python-modules/Cython/default.nix b/pkgs/development/python-modules/Cython/default.nix
new file mode 100644
index 000000000000..9d09b93ed20b
--- /dev/null
+++ b/pkgs/development/python-modules/Cython/default.nix
@@ -0,0 +1,57 @@
+{ lib
+, stdenv
+, buildPythonPackage
+, fetchPypi
+, isPy3k
+, python
+, glibcLocales
+, pkgconfig
+, gdb
+, numpy
+, ncurses
+}:
+
+buildPythonPackage rec {
+  pname = "Cython";
+  name = "${pname}-${version}";
+  version = "0.25.2";
+
+  src = fetchPypi {
+    inherit pname version;
+    sha256 = "01h3lrf6d98j07iakifi81qjszh6faa37ibx7ylva1vsqbwx2hgi";
+  };
+
+  # With Python 2.x on i686-linux or 32-bit ARM this test fails because the
+  # result is "3L" instead of "3", so let's fix it in-place.
+  #
+  # Upstream issue: https://github.com/cython/cython/issues/1548
+  postPatch = lib.optionalString ((stdenv.isi686 || stdenv.isArm) && !isPy3k) ''
+    sed -i -e 's/\(>>> *\)\(verify_resolution_GH1533()\)/\1int(\2)/' \
+      tests/run/cpdef_enums.pyx
+  '';
+
+  buildInputs = [ glibcLocales pkgconfig gdb ];
+  # For testing
+  nativeBuildInputs = [ numpy ncurses ];
+
+  LC_ALL = "en_US.UTF-8";
+
+  # cython's testsuite is not working very well with libc++
+  # We are however optimistic about things outside of testsuite still working
+  checkPhase = ''
+    export HOME="$NIX_BUILD_TOP"
+    ${python.interpreter} runtests.py \
+      ${if stdenv.cc.isClang or false then ''--exclude="(cpdef_extern_func|libcpp_algo)"'' else ""}
+  '';
+
+  # Disable tests temporarily
+  # https://github.com/cython/cython/issues/1676
+  doCheck = false;
+
+  meta = {
+    description = "An optimising static compiler for both the Python programming language and the extended Cython programming language";
+    homepage = http://cython.org;
+    license = lib.licenses.asl20;
+    maintainers = with lib.maintainers; [ fridh ];
+  };
+}
\ No newline at end of file
diff --git a/pkgs/development/python-modules/amqplib/default.nix b/pkgs/development/python-modules/amqplib/default.nix
index 7c4ef99b0a2c..1f539ef6d395 100644
--- a/pkgs/development/python-modules/amqplib/default.nix
+++ b/pkgs/development/python-modules/amqplib/default.nix
@@ -1,13 +1,13 @@
-{ stdenv, buildPythonPackage, fetchPypi }:
+{ stdenv, buildPythonPackage, fetchurl }:
 
 buildPythonPackage rec {
   pname = "amqplib";
   version = "0.6.1";
   name = "${pname}-${version}";
 
-  src = fetchPypi {
-    inherit pname version;
-    sha256 = "0f2618b74d95cd360a6d46a309a3fb1c37d881a237e269ac195a69a34e0e2f62";
+  src = fetchurl {
+    url = https://github.com/barryp/py-amqplib/archive/0.6.1.tar.gz;
+    sha256 = "04nsn68wz9m24rvbssirkyighazbn20j60wjmi0r7jcpcf00sb3s";
   };
 
   # error: invalid command 'test'
diff --git a/pkgs/development/python-modules/blaze/default.nix b/pkgs/development/python-modules/blaze/default.nix
new file mode 100644
index 000000000000..017b85cacc7c
--- /dev/null
+++ b/pkgs/development/python-modules/blaze/default.nix
@@ -0,0 +1,75 @@
+{ lib
+, buildPythonPackage
+, fetchurl
+, pytest
+, contextlib2
+, cytoolz
+, dask
+, datashape
+, flask
+, flask-cors
+, h5py
+, multipledispatch
+, numba
+, numpy
+, odo
+, pandas
+, psutil
+, pymongo
+, pyyaml
+, requests
+, sqlalchemy
+, tables
+, toolz
+}:
+
+buildPythonPackage rec {
+  pname = "blaze";
+  version = "0.11.0";
+  name = "${pname}-${version}";
+
+  src = fetchurl {
+    url = "https://github.com/blaze/blaze/archive/${version}.tar.gz";
+    sha256 = "07zrrxkmdqk84xvdmp29859zcfzlpx5pz6g62l28nqp6n6a7yq9a";
+  };
+
+  checkInputs = [ pytest ];
+  propagatedBuildInputs = [
+    contextlib2
+    cytoolz
+    dask
+    datashape
+    flask
+    flask-cors
+    h5py
+    multipledispatch
+    numba
+    numpy
+    odo
+    pandas
+    psutil
+    pymongo
+    pyyaml
+    requests
+    sqlalchemy
+    tables
+    toolz
+  ];
+
+  # Failing test
+  # ERROR collecting blaze/tests/test_interactive.py
+  # E   networkx.exception.NetworkXNoPath: node <class 'list'> not
+  # reachable from <class 'dask.array.core.Array'>
+  doCheck = false;
+
+  checkPhase = ''
+    py.test blaze/tests
+  '';
+
+  meta = {
+    homepage = https://github.com/ContinuumIO/blaze;
+    description = "Allows Python users a familiar interface to query data living in other data storage systems";
+    license = lib.licenses.bsdOriginal;
+    maintainers = with lib.maintainers; [ fridh ];
+  };
+}
\ No newline at end of file
diff --git a/pkgs/development/python-modules/cycler/default.nix b/pkgs/development/python-modules/cycler/default.nix
new file mode 100644
index 000000000000..e182f55cdc00
--- /dev/null
+++ b/pkgs/development/python-modules/cycler/default.nix
@@ -0,0 +1,37 @@
+{ lib
+, buildPythonPackage
+, fetchPypi
+, coverage
+, nose
+, six
+, python
+}:
+
+buildPythonPackage rec {
+  pname = "cycler";
+  name = "${pname}-${version}";
+  version = "0.10.0";
+
+  src = fetchPypi {
+    inherit pname version;
+    sha256 = "cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8";
+  };
+
+  checkInputs = [ coverage nose ];
+  propagatedBuildInputs = [ six ];
+
+  checkPhase = ''
+    ${python.interpreter} run_tests.py
+  '';
+
+  # Tests were not included in release.
+  # https://github.com/matplotlib/cycler/issues/31
+  doCheck = false;
+
+  meta = {
+    description = "Composable style cycles";
+    homepage = http://github.com/matplotlib/cycler;
+    license = lib.licenses.bsd3;
+    maintainers = with lib.maintainers; [ fridh ];
+  };
+}
\ No newline at end of file
diff --git a/pkgs/development/python-modules/sounddevice/default.nix b/pkgs/development/python-modules/sounddevice/default.nix
new file mode 100644
index 000000000000..0413366c5501
--- /dev/null
+++ b/pkgs/development/python-modules/sounddevice/default.nix
@@ -0,0 +1,34 @@
+{ lib
+, buildPythonPackage
+, fetchPypi
+, cffi
+, numpy
+, portaudio
+}:
+
+buildPythonPackage rec {
+  pname = "sounddevice";
+  name = "${pname}-${version}";
+  version = "0.3.8";
+
+  src = fetchPypi {
+    inherit pname version;
+    sha256 = "dc5ec8534c3831ab133c497721f3aaeed4f5084b0eda842f0c0ada09f2f066dc";
+  };
+
+  propagatedBuildInputs = [ cffi numpy portaudio ];
+
+  # No tests included nor upstream available.
+  doCheck = false;
+
+  prePatch = ''
+    substituteInPlace sounddevice.py --replace "'portaudio'" "'${portaudio}/lib/libportaudio.so.2'"
+  '';
+
+  meta = {
+    description = "Play and Record Sound with Python";
+    homepage = http://python-sounddevice.rtfd.org/;
+    license = with lib.licenses; [ mit ];
+    maintainers = with lib.maintainers; [ fridh ];
+  };
+}
\ No newline at end of file
diff --git a/pkgs/development/ruby-modules/bundled-common/default.nix b/pkgs/development/ruby-modules/bundled-common/default.nix
new file mode 100644
index 000000000000..1bf6257f6559
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundled-common/default.nix
@@ -0,0 +1,156 @@
+{ stdenv, runCommand, ruby, lib
+, defaultGemConfig, buildRubyGem, buildEnv
+, makeWrapper
+, bundler
+}@defs:
+
+{
+  name ? null
+, pname ? null
+, mainGemName ? null
+, gemdir ? null
+, gemfile ? null
+, lockfile ? null
+, gemset ? null
+, ruby ? defs.ruby
+, gemConfig ? defaultGemConfig
+, postBuild ? null
+, document ? []
+, meta ? {}
+, groups ? ["default"]
+, ignoreCollisions ? false
+, ...
+}@args:
+
+assert name == null -> pname != null;
+
+with  import ./functions.nix { inherit lib gemConfig; };
+
+let
+  gemFiles = bundlerFiles args;
+
+  importedGemset = import gemFiles.gemset;
+
+  filteredGemset = filterGemset { inherit ruby groups; } importedGemset;
+
+  configuredGemset = lib.flip lib.mapAttrs filteredGemset (name: attrs:
+    applyGemConfigs (attrs // { inherit ruby; gemName = name; })
+  );
+
+  hasBundler = builtins.hasAttr "bundler" filteredGemset;
+
+  bundler =
+    if hasBundler then gems.bundler
+    else defs.bundler.override (attrs: { inherit ruby; });
+
+  gems = lib.flip lib.mapAttrs configuredGemset (name: attrs: buildGem name attrs);
+
+  name' = if name != null then
+    name
+  else
+    let
+      gem = gems."${pname}";
+      version = gem.version;
+    in
+      "${pname}-${version}";
+
+  pname' = if pname != null then
+    pname
+  else
+    name;
+
+  copyIfBundledByPath = { bundledByPath ? false, ...}@main:
+  (if bundledByPath then
+      assert gemFiles.gemdir != null; "cp -a ${gemFiles.gemdir}/* $out/"
+    else ""
+  );
+
+  maybeCopyAll = pkgname: if pkgname == null then "" else
+  let
+    mainGem = gems."${pkgname}" or (throw "bundlerEnv: gem ${pkgname} not found");
+  in
+    copyIfBundledByPath mainGem;
+
+  # We have to normalize the Gemfile.lock, otherwise bundler tries to be
+  # helpful by doing so at run time, causing executables to immediately bail
+  # out. Yes, I'm serious.
+  confFiles = runCommand "gemfile-and-lockfile" {} ''
+    mkdir -p $out
+    ${maybeCopyAll mainGemName}
+    cp ${gemFiles.gemfile} $out/Gemfile || ls -l $out/Gemfile
+    cp ${gemFiles.lockfile} $out/Gemfile.lock || ls -l $out/Gemfile.lock
+  '';
+
+  buildGem = name: attrs: (
+    let
+      gemAttrs = composeGemAttrs ruby gems name attrs;
+    in
+    if gemAttrs.type == "path" then
+      pathDerivation gemAttrs
+    else
+      buildRubyGem gemAttrs
+  );
+
+  envPaths = lib.attrValues gems ++ lib.optional (!hasBundler) bundler;
+
+  basicEnv = buildEnv {
+    inherit  ignoreCollisions;
+
+    name = name';
+
+    paths = envPaths;
+    pathsToLink = [ "/lib" ];
+
+    postBuild = genStubsScript (defs // args // {
+      inherit confFiles bundler groups;
+      binPaths = envPaths;
+    }) + lib.optionalString (postBuild != null) postBuild;
+
+    meta = { platforms = ruby.meta.platforms; } // meta;
+
+    passthru = rec {
+      inherit ruby bundler gems mainGem confFiles envPaths;
+
+      wrappedRuby =
+      stdenv.mkDerivation {
+        name = "wrapped-ruby-${pname}";
+        nativeBuildInputs = [ makeWrapper ];
+        buildCommand = ''
+          mkdir -p $out/bin
+          for i in ${ruby}/bin/*; do
+            makeWrapper "$i" $out/bin/$(basename "$i") \
+              --set BUNDLE_GEMFILE ${confFiles}/Gemfile \
+              --set BUNDLE_PATH ${basicEnv}/${ruby.gemPath} \
+              --set BUNDLE_FROZEN 1 \
+              --set GEM_HOME ${basicEnv}/${ruby.gemPath} \
+              --set GEM_PATH ${basicEnv}/${ruby.gemPath}
+          done
+        '';
+      };
+
+      env = let
+        irbrc = builtins.toFile "irbrc" ''
+          if !(ENV["OLD_IRBRC"].nil? || ENV["OLD_IRBRC"].empty?)
+            require ENV["OLD_IRBRC"]
+          end
+          require 'rubygems'
+          require 'bundler/setup'
+        '';
+        in stdenv.mkDerivation {
+          name = "${pname}-interactive-environment";
+          nativeBuildInputs = [ wrappedRuby basicEnv ];
+          shellHook = ''
+            export OLD_IRBRC=$IRBRC
+            export IRBRC=${irbrc}
+          '';
+          buildCommand = ''
+            echo >&2 ""
+            echo >&2 "*** Ruby 'env' attributes are intended for interactive nix-shell sessions, not for building! ***"
+            echo >&2 ""
+            exit 1
+          '';
+        };
+    };
+  };
+in
+  basicEnv
diff --git a/pkgs/development/ruby-modules/bundled-common/functions.nix b/pkgs/development/ruby-modules/bundled-common/functions.nix
new file mode 100644
index 000000000000..b17a4639e779
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundled-common/functions.nix
@@ -0,0 +1,75 @@
+{ lib, gemConfig, ... }:
+rec {
+  bundlerFiles = {
+    gemfile ? null
+  , lockfile ? null
+  , gemset ? null
+  , gemdir ? null
+  , ...
+  }: {
+    inherit gemdir;
+
+    gemfile =
+    if gemfile == null then assert gemdir != null; gemdir + "/Gemfile"
+    else gemfile;
+
+    lockfile =
+    if lockfile == null then assert gemdir != null; gemdir + "/Gemfile.lock"
+    else lockfile;
+
+    gemset =
+    if gemset == null then assert gemdir != null; gemdir + "/gemset.nix"
+    else gemset;
+  };
+
+  filterGemset = {ruby, groups,...}@env: gemset: lib.filterAttrs (name: attrs: platformMatches ruby attrs && groupMatches groups attrs) gemset;
+
+  platformMatches = {rubyEngine, version, ...}@ruby: attrs: (
+  !(attrs ? "platforms") ||
+  builtins.length attrs.platforms == 0 ||
+    builtins.any (platform:
+      platform.engine == rubyEngine &&
+        (!(platform ? "version") || platform.version == version.majMin)
+    ) attrs.platforms
+  );
+
+  groupMatches = groups: attrs: (
+  !(attrs ? "groups") ||
+    builtins.any (gemGroup: builtins.any (group: group == gemGroup) groups) attrs.groups
+  );
+
+  applyGemConfigs = attrs:
+    (if gemConfig ? "${attrs.gemName}"
+    then attrs // gemConfig."${attrs.gemName}" attrs
+    else attrs);
+
+  genStubsScript = { lib, ruby, confFiles, bundler, groups, binPaths, ... }: ''
+      ${ruby}/bin/ruby ${./gen-bin-stubs.rb} \
+        "${ruby}/bin/ruby" \
+        "${confFiles}/Gemfile" \
+        "$out/${ruby.gemPath}" \
+        "${bundler}/${ruby.gemPath}" \
+        ${lib.escapeShellArg binPaths} \
+        ${lib.escapeShellArg groups}
+    '';
+
+  pathDerivation = { gemName, version, path, ...  }:
+    let
+      res = {
+          type = "derivation";
+          bundledByPath = true;
+          name = gemName;
+          version = version;
+          outPath = path;
+          outputs = [ "out" ];
+          out = res;
+          outputName = "out";
+        };
+    in res;
+
+  composeGemAttrs = ruby: gems: name: attrs: ((removeAttrs attrs ["source" "platforms"]) // attrs.source // {
+    inherit ruby;
+    gemName = name;
+    gemPath = map (gemName: gems."${gemName}") (attrs.dependencies or []);
+  });
+}
diff --git a/pkgs/development/ruby-modules/bundler-env/gen-bin-stubs.rb b/pkgs/development/ruby-modules/bundled-common/gen-bin-stubs.rb
index 92321d6427dc..92321d6427dc 100644
--- a/pkgs/development/ruby-modules/bundler-env/gen-bin-stubs.rb
+++ b/pkgs/development/ruby-modules/bundled-common/gen-bin-stubs.rb
diff --git a/pkgs/development/ruby-modules/bundled-common/test.nix b/pkgs/development/ruby-modules/bundled-common/test.nix
new file mode 100644
index 000000000000..ee3754595f39
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundled-common/test.nix
@@ -0,0 +1,50 @@
+{ stdenv, writeText, lib, ruby, defaultGemConfig, callPackage, test, stubs, should }@defs:
+let
+  testConfigs = {
+    inherit lib;
+    gemConfig =  defaultGemConfig;
+  };
+  functions = (import ./functions.nix testConfigs);
+in
+  builtins.concatLists [
+    ( test.run "All set, no gemdir" (functions.bundlerFiles {
+      gemfile  = test/Gemfile;
+      lockfile = test/Gemfile.lock;
+      gemset   = test/gemset.nix;
+    }) {
+      gemfile  = should.equal test/Gemfile;
+      lockfile = should.equal test/Gemfile.lock;
+      gemset   = should.equal test/gemset.nix;
+    })
+
+    ( test.run "Just gemdir" (functions.bundlerFiles {
+      gemdir = test/.;
+    }) {
+      gemfile  = should.equal test/Gemfile;
+      lockfile = should.equal test/Gemfile.lock;
+      gemset   = should.equal test/gemset.nix;
+    })
+
+    ( test.run "Gemset and dir" (functions.bundlerFiles {
+      gemdir = test/.;
+      gemset = test/extraGemset.nix;
+    }) {
+      gemfile  = should.equal test/Gemfile;
+      lockfile = should.equal test/Gemfile.lock;
+      gemset   = should.equal test/extraGemset.nix;
+    })
+
+    ( test.run "Filter empty gemset" {} (set: functions.filterGemset {inherit ruby; groups = ["default"]; } set == {}))
+    ( let gemSet = { test = { groups = ["x" "y"]; }; };
+      in
+      test.run "Filter matches a group" gemSet (set: functions.filterGemset {inherit ruby; groups = ["y" "z"];} set == gemSet))
+    ( let gemSet = { test = { platforms = []; }; };
+      in
+      test.run "Filter matches empty platforms list" gemSet (set: functions.filterGemset {inherit ruby; groups = [];} set == gemSet))
+    ( let gemSet = { test = { platforms = [{engine = ruby.rubyEngine; version = ruby.version.majMin;}]; }; };
+      in
+      test.run "Filter matches on platform" gemSet (set: functions.filterGemset {inherit ruby; groups = [];} set == gemSet))
+    ( let gemSet = { test = { groups = ["x" "y"]; }; };
+      in
+      test.run "Filter excludes based on groups" gemSet (set: functions.filterGemset {inherit ruby; groups = ["a" "b"];} set == {}))
+  ]
diff --git a/pkgs/development/ruby-modules/bundler-app/default.nix b/pkgs/development/ruby-modules/bundler-app/default.nix
new file mode 100644
index 000000000000..99d1dd64dc4f
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundler-app/default.nix
@@ -0,0 +1,48 @@
+{ lib, stdenv, callPackage, runCommand, ruby }@defs:
+
+# Use for simple installation of Ruby tools shipped in a Gem.
+# Start with a Gemfile that includes `gem <toolgem>`
+# > nix-shell -p bundler bundix
+# (shell)> bundle lock
+# (shell)> bundix
+# Then use rubyTool in the default.nix:
+
+# rubyTool { pname = "gemifiedTool"; gemdir = ./.; exes = ["gemified-tool"]; }
+# The 'exes' parameter ensures that a copy of e.g. rake doesn't polute the system.
+{
+  # use the name of the name in question; its version will be picked up from the gemset
+  pname
+  # gemdir is the location of the Gemfile{,.lock} and gemset.nix; usually ./.
+, gemdir
+  # Exes is the list of executables provided by the gems in the Gemfile
+, exes ? []
+  # Scripts are ruby programs depend on gems in the Gemfile (e.g. scripts/rails)
+, scripts ? []
+, ruby ? defs.ruby
+, gemfile ? null
+, lockfile ? null
+, gemset ? null
+, preferLocalBuild ? false
+, allowSubstitutes ? false
+, meta ? {}
+, postBuild ? ""
+}@args:
+
+let
+  basicEnv = (callPackage ../bundled-common {}) args;
+
+  cmdArgs = removeAttrs args [ "pname" "postBuild" ]
+  // { inherit preferLocalBuild allowSubstitutes; }; # pass the defaults
+in
+   runCommand basicEnv.name cmdArgs ''
+    mkdir -p $out/bin;
+      ${(lib.concatMapStrings (x: "ln -s '${basicEnv}/bin/${x}' $out/bin/${x};\n") exes)}
+      ${(lib.concatMapStrings (s: "makeWrapper $out/bin/$(basename ${s}) $srcdir/${s} " +
+              "--set BUNDLE_GEMFILE ${basicEnv.confFiles}/Gemfile "+
+              "--set BUNDLE_PATH ${basicEnv}/${ruby.gemPath} "+
+              "--set BUNDLE_FROZEN 1 "+
+              "--set GEM_HOME ${basicEnv}/${ruby.gemPath} "+
+              "--set GEM_PATH ${basicEnv}/${ruby.gemPath} "+
+              "--run \"cd $srcdir\";\n") scripts)}
+    ${postBuild}
+  ''
diff --git a/pkgs/development/ruby-modules/bundler-env/default.nix b/pkgs/development/ruby-modules/bundler-env/default.nix
index 57ca23d41436..2e2653621a76 100644
--- a/pkgs/development/ruby-modules/bundler-env/default.nix
+++ b/pkgs/development/ruby-modules/bundler-env/default.nix
@@ -1,9 +1,6 @@
 { stdenv, runCommand, writeText, writeScript, writeScriptBin, ruby, lib
 , callPackage, defaultGemConfig, fetchurl, fetchgit, buildRubyGem, buildEnv
-, git
-, makeWrapper
-, bundler
-, tree
+, linkFarm, git, makeWrapper, bundler, tree
 }@defs:
 
 { name ? null
@@ -12,143 +9,54 @@
 , gemfile ? null
 , lockfile ? null
 , gemset ? null
+, groups ? ["default"]
 , ruby ? defs.ruby
 , gemConfig ? defaultGemConfig
 , postBuild ? null
 , document ? []
 , meta ? {}
-, groups ? ["default"]
 , ignoreCollisions ? false
 , ...
 }@args:
 
 let
-  drvName =
-    if name != null then name
-    else if pname != null then "${toString pname}-${mainGem.version}"
-    else throw "bundlerEnv: either pname or name must be set";
-
-  mainGem =
-    if pname == null then null
-    else gems."${pname}" or (throw "bundlerEnv: gem ${pname} not found");
-
-  gemfile' =
-    if gemfile == null then gemdir + "/Gemfile"
-    else gemfile;
-
-  lockfile' =
-    if lockfile == null then gemdir + "/Gemfile.lock"
-    else lockfile;
-
-  gemset' =
-    if gemset == null then gemdir + "/gemset.nix"
-    else gemset;
-
-  importedGemset = import gemset';
-
-  filteredGemset = (lib.filterAttrs (name: attrs:
-    if (builtins.hasAttr "groups" attrs)
-    then (builtins.any (gemGroup: builtins.any (group: group == gemGroup) groups) attrs.groups)
-    else true
-  ) importedGemset);
-
-  applyGemConfigs = attrs:
-    (if gemConfig ? "${attrs.gemName}"
-    then attrs // gemConfig."${attrs.gemName}" attrs
-    else attrs);
-
-  configuredGemset = lib.flip lib.mapAttrs filteredGemset (name: attrs:
-    applyGemConfigs (attrs // { inherit ruby; gemName = name; })
-  );
-
-  hasBundler = builtins.hasAttr "bundler" filteredGemset;
+  inherit (import ../bundled-common/functions.nix {inherit lib ruby gemConfig groups; }) genStubsScript;
 
-  bundler =
-    if hasBundler then gems.bundler
-    else defs.bundler.override (attrs: { inherit ruby; });
+  basicEnv = (callPackage ../bundled-common {}) (args // { inherit pname name; mainGemName = pname; });
 
-  gems = lib.flip lib.mapAttrs configuredGemset (name: attrs:
-    buildRubyGem ((removeAttrs attrs ["source"]) // attrs.source // {
-      inherit ruby;
-      gemName = name;
-      gemPath = map (gemName: gems."${gemName}") (attrs.dependencies or []);
-    }));
+  inherit (basicEnv) envPaths;
+  # Idea here is a mkDerivation that gen-bin-stubs new stubs "as specified" -
+  # either specific executables or the bin/ for certain gem(s), but
+  # incorporates the basicEnv as a requirement so that its $out is in our path.
 
-  # We have to normalize the Gemfile.lock, otherwise bundler tries to be
-  # helpful by doing so at run time, causing executables to immediately bail
-  # out. Yes, I'm serious.
-  confFiles = runCommand "gemfile-and-lockfile" {} ''
-    mkdir -p $out
-    cp ${gemfile'} $out/Gemfile
-    cp ${lockfile'} $out/Gemfile.lock
-  '';
+  # When stubbing the bins for a gem, we should use the gem expression
+  # directly, which means that basicEnv should somehow make it available.
 
-  envPaths = lib.attrValues gems ++ lib.optional (!hasBundler) bundler;
+  # Different use cases should use different variations on this file, rather
+  # than the expression trying to deduce a use case.
 
-  binPaths = if mainGem != null then [ mainGem ] else envPaths;
-
-  bundlerEnv = buildEnv {
-    inherit ignoreCollisions;
-
-    name = drvName;
-
-    paths = envPaths;
-    pathsToLink = [ "/lib" ];
-
-    postBuild = ''
-      ${ruby}/bin/ruby ${./gen-bin-stubs.rb} \
-        "${ruby}/bin/ruby" \
-        "${confFiles}/Gemfile" \
-        "$out/${ruby.gemPath}" \
-        "${bundler}/${ruby.gemPath}" \
-        ${lib.escapeShellArg binPaths} \
-        ${lib.escapeShellArg groups}
-    '' + lib.optionalString (postBuild != null) postBuild;
-
-    meta = { platforms = ruby.meta.platforms; } // meta;
-
-    passthru = rec {
-      inherit ruby bundler gems;
-
-      wrappedRuby = stdenv.mkDerivation {
-        name = "wrapped-ruby-${drvName}";
-        nativeBuildInputs = [ makeWrapper ];
-        buildCommand = ''
-          mkdir -p $out/bin
-          for i in ${ruby}/bin/*; do
-            makeWrapper "$i" $out/bin/$(basename "$i") \
-              --set BUNDLE_GEMFILE ${confFiles}/Gemfile \
-              --set BUNDLE_PATH ${bundlerEnv}/${ruby.gemPath} \
-              --set BUNDLE_FROZEN 1 \
-              --set GEM_HOME ${bundlerEnv}/${ruby.gemPath} \
-              --set GEM_PATH ${bundlerEnv}/${ruby.gemPath}
-          done
-        '';
-      };
-
-      env = let
-        irbrc = builtins.toFile "irbrc" ''
-          if !(ENV["OLD_IRBRC"].nil? || ENV["OLD_IRBRC"].empty?)
-            require ENV["OLD_IRBRC"]
-          end
-          require 'rubygems'
-          require 'bundler/setup'
-        '';
-        in stdenv.mkDerivation {
-          name = "interactive-${drvName}-environment";
-          nativeBuildInputs = [ wrappedRuby bundlerEnv ];
-          shellHook = ''
-            export OLD_IRBRC="$IRBRC"
-            export IRBRC=${irbrc}
-          '';
-          buildCommand = ''
-            echo >&2 ""
-            echo >&2 "*** Ruby 'env' attributes are intended for interactive nix-shell sessions, not for building! ***"
-            echo >&2 ""
-            exit 1
-          '';
-        };
-    };
-  };
+  # The basicEnv should be put into passthru so that e.g. nix-shell can use it.
 in
-  bundlerEnv
+  if pname == null then
+    basicEnv // { inherit name basicEnv; }
+  else
+    (buildEnv {
+      inherit ignoreCollisions;
+
+      name = basicEnv.name;
+
+      paths = envPaths;
+      pathsToLink = [ "/lib" ];
+
+      postBuild = genStubsScript {
+        inherit lib ruby bundler groups;
+        confFiles = basicEnv.confFiles;
+        binPaths = [ basicEnv.gems."${pname}" ];
+      } + lib.optionalString (postBuild != null) postBuild;
+
+      meta = { platforms = ruby.meta.platforms; } // meta;
+      passthru = basicEnv.passthru // {
+        inherit basicEnv;
+        inherit (basicEnv) env;
+      };
+    })
diff --git a/pkgs/development/ruby-modules/bundler-env/test.nix b/pkgs/development/ruby-modules/bundler-env/test.nix
new file mode 100644
index 000000000000..63da7044c0cf
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundler-env/test.nix
@@ -0,0 +1,33 @@
+{ stdenv, writeText, lib, ruby, defaultGemConfig, callPackage, test, stubs, should}@defs:
+let
+  bundlerEnv = callPackage ./default.nix stubs // {
+    basicEnv = callPackage ../bundled-common stubs;
+  };
+
+  justName = bundlerEnv {
+    name = "test-0.1.2";
+    gemset = ./test/gemset.nix;
+  };
+
+  pnamed = bundlerEnv {
+    pname = "test";
+    gemdir = ./test;
+    gemset = ./test/gemset.nix;
+    gemfile = ./test/Gemfile;
+    lockfile = ./test/Gemfile.lock;
+  };
+in
+  builtins.concatLists [
+    (test.run "bundlerEnv { name }" justName {
+      name = should.equal "test-0.1.2";
+    })
+    (test.run "bundlerEnv { pname }" pnamed
+    [
+      (should.haveKeys [ "name" "env" "postBuild" ])
+      {
+        name = should.equal "test-0.1.2";
+        env = should.beASet;
+        postBuild = should.havePrefix "/nix/store";
+      }
+    ])
+  ]
diff --git a/pkgs/development/ruby-modules/bundler-env/test/Gemfile b/pkgs/development/ruby-modules/bundler-env/test/Gemfile
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundler-env/test/Gemfile
diff --git a/pkgs/development/ruby-modules/bundler-env/test/Gemfile.lock b/pkgs/development/ruby-modules/bundler-env/test/Gemfile.lock
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundler-env/test/Gemfile.lock
diff --git a/pkgs/development/ruby-modules/bundler-env/test/gemset.nix b/pkgs/development/ruby-modules/bundler-env/test/gemset.nix
new file mode 100644
index 000000000000..53f15f96bc6d
--- /dev/null
+++ b/pkgs/development/ruby-modules/bundler-env/test/gemset.nix
@@ -0,0 +1,10 @@
+{
+  test = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1j5r0anj8m4qlf2psnldip4b8ha2bsscv11lpdgnfh4nnchzjnxw";
+      type = "gem";
+    };
+    version = "0.1.2";
+  };
+}
diff --git a/pkgs/development/ruby-modules/gem/default.nix b/pkgs/development/ruby-modules/gem/default.nix
index ade6659c400b..62a9d60686f3 100644
--- a/pkgs/development/ruby-modules/gem/default.nix
+++ b/pkgs/development/ruby-modules/gem/default.nix
@@ -87,6 +87,7 @@ stdenv.mkDerivation (attrs // {
     ++ lib.optional stdenv.isDarwin darwin.libobjc
     ++ buildInputs;
 
+  #name = builtins.trace (attrs.name or "no attr.name" ) "${namePrefix}${gemName}-${version}";
   name = attrs.name or "${namePrefix}${gemName}-${version}";
 
   inherit src;
diff --git a/pkgs/development/ruby-modules/runtests.sh b/pkgs/development/ruby-modules/runtests.sh
new file mode 100755
index 000000000000..8bb8c8a5462c
--- /dev/null
+++ b/pkgs/development/ruby-modules/runtests.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+set -o xtrace
+cd $(dirname $0)
+find . -name text.nix
+testfiles=$(find . -name test.nix)
+nix-build -E "with import <nixpkgs> {}; callPackage testing/driver.nix { testFiles = [ $testfiles ]; }" --show-trace && cat result
diff --git a/pkgs/development/ruby-modules/testing/assertions.nix b/pkgs/development/ruby-modules/testing/assertions.nix
new file mode 100644
index 000000000000..f28cfcd508d4
--- /dev/null
+++ b/pkgs/development/ruby-modules/testing/assertions.nix
@@ -0,0 +1,28 @@
+{ test, lib, ...}:
+{
+  equal = expected: actual:
+    if actual == expected then
+      (test.passed "= ${toString expected}") else
+      (test.failed (
+      "expected '${toString expected}'(${builtins.typeOf expected})"
+      + " !=  "+
+      "actual '${toString actual}'(${builtins.typeOf actual})"
+      ));
+
+  beASet = actual:
+    if builtins.isAttrs actual then
+      (test.passed "is a set") else
+      (test.failed "is not a set, was ${builtins.typeOf actual}: ${toString actual}");
+
+  haveKeys = expected: actual:
+    if builtins.all
+    (ex: builtins.any (ac: ex == ac) (builtins.attrNames actual))
+    expected then
+      (test.passed "has expected keys") else
+      (test.failed "keys differ: expected: [${lib.concatStringsSep ";" expected}] actual: [${lib.concatStringsSep ";" (builtins.attrNames actual)}]");
+
+  havePrefix = expected: actual:
+    if lib.hasPrefix expected actual then
+      (test.passed "has prefix '${expected}'") else
+      (test.failed "prefix '${expected}' not found in '${actual}'");
+}
diff --git a/pkgs/development/ruby-modules/testing/driver.nix b/pkgs/development/ruby-modules/testing/driver.nix
new file mode 100644
index 000000000000..65e7c8d4416d
--- /dev/null
+++ b/pkgs/development/ruby-modules/testing/driver.nix
@@ -0,0 +1,20 @@
+/*
+Run with:
+nix-build -E 'with import <nixpkgs> { }; callPackage ./test.nix {}' --show-trace; and cat result
+
+Confusingly, the ideal result ends with something like:
+error: build of ‘/nix/store/3245f3dcl2wxjs4rci7n069zjlz8qg85-test-results.tap.drv’ failed
+*/
+{ writeText, lib, callPackage, testFiles, stdenv, ruby }@defs:
+let
+  testTools = rec {
+    test = import ./testing.nix;
+    stubs = import ./stubs.nix defs;
+    should = import ./assertions.nix { inherit test lib; };
+  };
+
+  tap = import ./tap-support.nix;
+
+  results = builtins.concatLists (map (file: callPackage file testTools) testFiles);
+in
+  writeText "test-results.tap" (tap.output results)
diff --git a/pkgs/development/ruby-modules/testing/stubs.nix b/pkgs/development/ruby-modules/testing/stubs.nix
new file mode 100644
index 000000000000..3585681478c8
--- /dev/null
+++ b/pkgs/development/ruby-modules/testing/stubs.nix
@@ -0,0 +1,33 @@
+{ stdenv, lib, ruby, callPackage, ... }:
+let
+  real = {
+    inherit (stdenv) mkDerivation;
+  };
+  mkDerivation = {name, ...}@argSet:
+  derivation {
+    inherit name;
+    text = (builtins.toJSON (lib.filterAttrs ( n: v: builtins.any (x: x == n) ["name" "system"]) argSet));
+    builder = stdenv.shell;
+    args = [ "-c" "echo  $(<$textPath) > $out"];
+    system = stdenv.system;
+    passAsFile = ["text"];
+  };
+  fetchurl = {url?"", urls ? [],...}: "fetchurl:${if urls == [] then url else builtins.head urls}";
+
+  stdenv' = stdenv // {
+    inherit mkDerivation;
+    stubbed = true;
+  };
+  ruby' = ruby // {
+    stdenv = stdenv';
+    stubbed = true;
+  };
+in
+  {
+    ruby = ruby';
+    buildRubyGem = callPackage ../gem {
+      inherit fetchurl;
+      ruby = ruby';
+    };
+    stdenv = stdenv';
+  }
diff --git a/pkgs/development/ruby-modules/testing/tap-support.nix b/pkgs/development/ruby-modules/testing/tap-support.nix
new file mode 100644
index 000000000000..74fcceebaa04
--- /dev/null
+++ b/pkgs/development/ruby-modules/testing/tap-support.nix
@@ -0,0 +1,21 @@
+with builtins;
+let
+  withIndexes = list: genList (idx: (elemAt list idx) // {index = idx;}) (length list);
+
+  testLine = report: "${okStr report} ${toString (report.index + 1)} ${report.description}" + testDirective report + testYaml report;
+
+  # These are part of the TAP spec, not yet implemented.
+  #c.f.  https://github.com/NixOS/nixpkgs/issues/27071
+  testDirective = report: "";
+  testYaml = report: "";
+
+  okStr = { result, ...}: if result == "pass" then "ok" else "not ok";
+in
+  {
+    output = reports: ''
+      TAP version 13
+      1..${toString (length reports)}'' + (foldl' (l: r: l + "\n" + r) "" (map testLine (withIndexes reports))) + ''
+
+      # Finished at ${toString currentTime}
+      '';
+  }
diff --git a/pkgs/development/ruby-modules/testing/testing.nix b/pkgs/development/ruby-modules/testing/testing.nix
new file mode 100644
index 000000000000..43d10fca0444
--- /dev/null
+++ b/pkgs/development/ruby-modules/testing/testing.nix
@@ -0,0 +1,62 @@
+with builtins;
+let
+  /*
+  underTest = {
+    x = {
+      a = 1;
+      b = "2";
+    };
+  };
+
+  tests = [
+    (root: false)
+    {
+      x = [
+        (set: true)
+        {
+          a = (a: a > 1);
+          b = (b: b == "3");
+        }
+      ];
+    }
+  ];
+
+  results = run "Examples" underTest tests;
+  */
+
+  passed = desc: {
+    result = "pass";
+    description = desc;
+  };
+
+  failed = desc: {
+    result = "failed";
+    description = desc;
+  };
+
+  prefixName = name: res: {
+    inherit (res) result;
+    description = "${name}: ${res.description}";
+  };
+
+  run = name: under: tests: if isList tests then
+    (concatLists (map (run name under) tests))
+  else if isAttrs tests then
+    (concatLists (map (
+    subName: run (name + "." + subName) (if hasAttr subName under then getAttr subName under else "<MISSING!>") (getAttr subName tests)
+    ) (attrNames tests)))
+  else if isFunction tests then
+    let
+      res = tests under;
+    in
+      if isBool res then
+        [
+          (prefixName name (if tests under then passed "passed" else failed "failed"))
+        ]
+      else
+        [ (prefixName name res) ]
+  else [
+    failed (name ": not a function, list or set")
+  ];
+in
+  { inherit run passed failed; }
diff --git a/pkgs/development/tools/ammonite/default.nix b/pkgs/development/tools/ammonite/default.nix
index feb6865566f0..bd1be88bb32d 100644
--- a/pkgs/development/tools/ammonite/default.nix
+++ b/pkgs/development/tools/ammonite/default.nix
@@ -5,12 +5,12 @@
 with stdenv.lib;
 stdenv.mkDerivation rec {
   name = "ammonite-${version}";
-  version = "1.0.0";
+  version = "1.0.1";
   scalaVersion = "2.12";
 
   src = fetchurl {
     url = "https://github.com/lihaoyi/Ammonite/releases/download/${version}/${scalaVersion}-${version}";
-    sha256 = "0d74b3aasgg4ap5ishzzm4jbf1k4dxv7gzd88d69miyapsaa4p0c";
+    sha256 = "1gfswia6wg1z8whzmca7zmrkbhkvianbyd15yimnbd08minm1z2d";
   };
 
   propagatedBuildInputs = [ jre ] ;
diff --git a/pkgs/development/tools/corundum/Gemfile b/pkgs/development/tools/corundum/Gemfile
new file mode 100644
index 000000000000..5f817ae498a7
--- /dev/null
+++ b/pkgs/development/tools/corundum/Gemfile
@@ -0,0 +1,3 @@
+source "https://rubygems.org"
+
+gem "corundum", "=0.6.2"
diff --git a/pkgs/development/tools/corundum/Gemfile.lock b/pkgs/development/tools/corundum/Gemfile.lock
new file mode 100644
index 000000000000..40ad1948394f
--- /dev/null
+++ b/pkgs/development/tools/corundum/Gemfile.lock
@@ -0,0 +1,56 @@
+GEM
+  remote: https://rubygems.org/
+  specs:
+    calibrate (0.0.1)
+    caliph (0.3.1)
+    corundum (0.6.2)
+      bundler (~> 1.10)
+      caliph (~> 0.3)
+      mattock (~> 0.9)
+      paint (~> 0.8)
+      rspec (>= 2.0, < 4)
+      simplecov (>= 0.5)
+      simplecov-json (~> 0.2)
+    diff-lcs (1.3)
+    docile (1.1.5)
+    json (2.1.0)
+    mattock (0.10.1)
+      calibrate (~> 0.0.1)
+      caliph (~> 0.3)
+      rake (~> 10.0)
+      tilt (> 0)
+      valise (~> 1.1)
+    paint (0.9.0)
+    rake (10.5.0)
+    rspec (3.6.0)
+      rspec-core (~> 3.6.0)
+      rspec-expectations (~> 3.6.0)
+      rspec-mocks (~> 3.6.0)
+    rspec-core (3.6.0)
+      rspec-support (~> 3.6.0)
+    rspec-expectations (3.6.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.6.0)
+    rspec-mocks (3.6.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.6.0)
+    rspec-support (3.6.0)
+    simplecov (0.14.1)
+      docile (~> 1.1.0)
+      json (>= 1.8, < 3)
+      simplecov-html (~> 0.10.0)
+    simplecov-html (0.10.1)
+    simplecov-json (0.2)
+      json
+      simplecov
+    tilt (2.0.7)
+    valise (1.2.1)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  corundum (= 0.6.2)
+
+BUNDLED WITH
+   1.14.4
diff --git a/pkgs/development/tools/corundum/default.nix b/pkgs/development/tools/corundum/default.nix
new file mode 100644
index 000000000000..22d7b236ffa4
--- /dev/null
+++ b/pkgs/development/tools/corundum/default.nix
@@ -0,0 +1,15 @@
+{ lib, bundlerApp }:
+
+bundlerApp {
+  pname = "corundum";
+  gemdir = ./.;
+  exes = [ "corundum-skel" ];
+
+  meta = with lib; {
+    description = "Tool and libraries for maintaining Ruby gems.";
+    homepage    = https://github.com/nyarly/corundum;
+    license     = licenses.mit;
+    maintainers = [ maintainers.nyarly ];
+    platforms   = platforms.unix;
+  };
+}
diff --git a/pkgs/development/tools/corundum/gemset.nix b/pkgs/development/tools/corundum/gemset.nix
new file mode 100644
index 000000000000..e395e098e6d1
--- /dev/null
+++ b/pkgs/development/tools/corundum/gemset.nix
@@ -0,0 +1,154 @@
+{
+  calibrate = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "17kmlss7db70pjwdbbhag7mnixh8wasdq6n1v8663x50z9c7n2ng";
+      type = "gem";
+    };
+    version = "0.0.1";
+  };
+  caliph = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "08d07n4m4yh1h9icq6n9dkw4jwgdmgd638f15mxr2pvqp4wycsnr";
+      type = "gem";
+    };
+    version = "0.3.1";
+  };
+  corundum = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1y6shjrqaqyh14a1r4ic660g6jnq4abdrx9imglyalzyrlrwbsxq";
+      type = "gem";
+    };
+    version = "0.6.2";
+  };
+  diff-lcs = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "18w22bjz424gzafv6nzv98h0aqkwz3d9xhm7cbr1wfbyas8zayza";
+      type = "gem";
+    };
+    version = "1.3";
+  };
+  docile = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0m8j31whq7bm5ljgmsrlfkiqvacrw6iz9wq10r3gwrv5785y8gjx";
+      type = "gem";
+    };
+    version = "1.1.5";
+  };
+  json = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "01v6jjpvh3gnq6sgllpfqahlgxzj50ailwhj9b3cd20hi2dx0vxp";
+      type = "gem";
+    };
+    version = "2.1.0";
+  };
+  mattock = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "02d6igwr4sfj4jnky8d5h0rm2cc665k1bqz7sj4khzvr18nk3ai6";
+      type = "gem";
+    };
+    version = "0.10.1";
+  };
+  paint = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1fcn7cfrhbl4nl95fmcd67q33h7bl3iafsafs6w9yj4nqzagz1yc";
+      type = "gem";
+    };
+    version = "0.9.0";
+  };
+  rake = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0jcabbgnjc788chx31sihc5pgbqnlc1c75wakmqlbjdm8jns2m9b";
+      type = "gem";
+    };
+    version = "10.5.0";
+  };
+  rspec = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1nd50hycab2a2vdah9lxi585g8f63jxjvmzmxqyln51grxwx9hzb";
+      type = "gem";
+    };
+    version = "3.6.0";
+  };
+  rspec-core = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "18np8wyw2g79waclpaacba6nd7x60ixg07ncya0j0qj1z9b37grd";
+      type = "gem";
+    };
+    version = "3.6.0";
+  };
+  rspec-expectations = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "028ifzf9mqp3kxx40q1nbwj40g72g9zk0wr78l146phblkv96w0a";
+      type = "gem";
+    };
+    version = "3.6.0";
+  };
+  rspec-mocks = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0nv6jkxy24sag1i9w9wi3850k6skk2fm6yhcrgnmlz6vmwxvizp8";
+      type = "gem";
+    };
+    version = "3.6.0";
+  };
+  rspec-support = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "050paqqpsml8w88nf4a15zbbj3vvm471zpv73sjfdnz7w21wnypb";
+      type = "gem";
+    };
+    version = "3.6.0";
+  };
+  simplecov = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1r9fnsnsqj432cmrpafryn8nif3x0qg9mdnvrcf0wr01prkdlnww";
+      type = "gem";
+    };
+    version = "0.14.1";
+  };
+  simplecov-html = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0f3psphismgp6jp1fxxz09zbswh7m2xxxr6gqlzdh7sgv415clvm";
+      type = "gem";
+    };
+    version = "0.10.1";
+  };
+  simplecov-json = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "0x9hr08pkj5d14nfzsn5h8b7ayl6q0xir45dcx5rv2a7g10kzlpp";
+      type = "gem";
+    };
+    version = "0.2";
+  };
+  tilt = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1is1ayw5049z8pd7slsk870bddyy5g2imp4z78lnvl8qsl8l0s7b";
+      type = "gem";
+    };
+    version = "2.0.7";
+  };
+  valise = {
+    source = {
+      remotes = ["https://rubygems.org"];
+      sha256 = "1arsbmk2gifrhv244qrld7s3202xrnxy6vlc5gqklg70dpsinbn5";
+      type = "gem";
+    };
+    version = "1.2.1";
+  };
+}
\ No newline at end of file