about summary refs log tree commit diff
path: root/nixpkgs/pkgs/development/interpreters/ruby
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/pkgs/development/interpreters/ruby')
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/bitperfect-rdoc.patch13
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/config.nix8
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/default.nix309
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/dev.nix23
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/patchsets.nix83
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/rand-egd.patch42
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/rbconfig.rb25
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/ruby-version.nix63
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/ruby19-parallel-install.patch15
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/rubygems/0001-add-post-extract-hook.patch34
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/rubygems/0002-binaries-with-env-shebang.patch28
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/rubygems/0003-gem-install-default-to-user.patch26
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/rubygems/default.nix35
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/rvm-patchsets.nix8
-rw-r--r--nixpkgs/pkgs/development/interpreters/ruby/ssl_v3.patch16
15 files changed, 728 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/bitperfect-rdoc.patch b/nixpkgs/pkgs/development/interpreters/ruby/bitperfect-rdoc.patch
new file mode 100644
index 000000000000..d5fb9e4554fa
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/bitperfect-rdoc.patch
@@ -0,0 +1,13 @@
+diff -r -u orig/lib/rdoc/generator/template/darkfish/filepage.rhtml new/lib/rdoc/generator/template/darkfish/filepage.rhtml
+--- orig/lib/rdoc/generator/template/darkfish/filepage.rhtml
++++ new/lib/rdoc/generator/template/darkfish/filepage.rhtml
+@@ -88,9 +88,6 @@
+ <body class="file file-popup">
+   <div id="metadata">
+     <dl>
+-      <dt class="modified-date">Last Modified</dt>
+-      <dd class="modified-date"><%= file.last_modified %></dd>
+-
+       <% if file.requires %>
+       <dt class="requires">Requires</dt>
+       <dd class="requires">
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/config.nix b/nixpkgs/pkgs/development/interpreters/ruby/config.nix
new file mode 100644
index 000000000000..c4f3160d1602
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/config.nix
@@ -0,0 +1,8 @@
+# Ruby >= 2.1.0 tries to download config.{guess,sub}
+{ fetchFromSavannah }:
+
+fetchFromSavannah {
+  repo = "config";
+  rev = "576c839acca0e082e536fd27568b90a446ce5b96";
+  sha256 = "11bjngchjhj0qq0ppp8c37rfw0yhp230nvhs2jvlx15i9qbf56a0";
+}
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/default.nix b/nixpkgs/pkgs/development/interpreters/ruby/default.nix
new file mode 100644
index 000000000000..d90a2f4f971b
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/default.nix
@@ -0,0 +1,309 @@
+{ stdenv, buildPackages, lib, defaultGemConfig, buildRubyGem
+, fetchurl, fetchpatch, fetchFromSavannah, fetchFromGitHub
+, zlib, openssl, gdbm, ncurses, readline, groff, libyaml, libffi, autoreconfHook, bison
+, autoconf, libiconv, libobjc, libunwind, Foundation
+, buildEnv, bundler, bundix, makeWrapper, removeReferencesTo
+} @ args:
+
+let
+  op = lib.optional;
+  ops = lib.optionals;
+  opString = lib.optionalString;
+  patchSet = import ./rvm-patchsets.nix { inherit fetchFromGitHub; };
+  config = import ./config.nix { inherit fetchFromSavannah; };
+  rubygems = import ./rubygems { inherit stdenv lib fetchurl fetchpatch; };
+
+  # Contains the ruby version heuristics
+  rubyVersion = import ./ruby-version.nix { inherit lib; };
+
+  # Needed during postInstall
+  buildRuby =
+    if stdenv.hostPlatform == stdenv.buildPlatform
+    then "$out/bin/ruby"
+    else "${buildPackages.ruby}/bin/ruby";
+
+  generic = { version, sha256 }: let
+    ver = version;
+    tag = ver.gitTag;
+    isRuby20 = ver.majMin == "2.0";
+    isRuby21 = ver.majMin == "2.1";
+    atLeast25 = lib.versionAtLeast ver.majMin "2.5";
+    atLeast27 = lib.versionAtLeast ver.majMin "2.7";
+    baseruby = self.override {
+      useRailsExpress = false;
+      docSupport = false;
+      rubygemsSupport = false;
+    };
+    with-packages = import ../../ruby-modules/with-packages {
+      inherit lib stdenv makeWrapper buildRubyGem buildEnv;
+      gemConfig = defaultGemConfig;
+      ruby = self;
+    };
+    self = lib.makeOverridable (
+      { stdenv, buildPackages, lib
+      , fetchurl, fetchpatch, fetchFromSavannah, fetchFromGitHub
+      , useRailsExpress ? true
+      , rubygemsSupport ? true
+      , zlib, zlibSupport ? true
+      , openssl, opensslSupport ? true
+      , gdbm, gdbmSupport ? true
+      , ncurses, readline, cursesSupport ? true
+      , groff, docSupport ? true
+      , libyaml, yamlSupport ? true
+      , libffi, fiddleSupport ? true
+      # ruby -e "puts RbConfig::CONFIG['configure_args']"
+      # puts a reference to the C compiler in the binary.
+      # This might be required by some gems at runtime,
+      # but we allow to strip it out for smaller closure size.
+      , removeReferencesTo, removeReferenceToCC ? true
+      , autoreconfHook, bison, autoconf
+      , buildEnv, bundler, bundix
+      , libiconv, libobjc, libunwind, Foundation
+      , makeWrapper, buildRubyGem, defaultGemConfig
+      }:
+      stdenv.mkDerivation rec {
+        pname = "ruby";
+        inherit version;
+
+        src = if useRailsExpress then fetchFromGitHub {
+          owner  = "ruby";
+          repo   = "ruby";
+          rev    = tag;
+          sha256 = sha256.git;
+        } else fetchurl {
+          url = "https://cache.ruby-lang.org/pub/ruby/${ver.majMin}/ruby-${ver}.tar.gz";
+          sha256 = sha256.src;
+        };
+
+        # Have `configure' avoid `/usr/bin/nroff' in non-chroot builds.
+        NROFF = if docSupport then "${groff}/bin/nroff" else null;
+
+        outputs = [ "out" ] ++ lib.optional docSupport "devdoc";
+
+        nativeBuildInputs = [ autoreconfHook bison ]
+          ++ (op docSupport groff)
+          ++ op (stdenv.buildPlatform != stdenv.hostPlatform) buildPackages.ruby;
+        buildInputs = [ autoconf ]
+          ++ (op fiddleSupport libffi)
+          ++ (ops cursesSupport [ ncurses readline ])
+          ++ (op zlibSupport zlib)
+          ++ (op opensslSupport openssl)
+          ++ (op gdbmSupport gdbm)
+          ++ (op yamlSupport libyaml)
+          # Looks like ruby fails to build on darwin without readline even if curses
+          # support is not enabled, so add readline to the build inputs if curses
+          # support is disabled (if it's enabled, we already have it) and we're
+          # running on darwin
+          ++ op (!cursesSupport && stdenv.isDarwin) readline
+          ++ ops stdenv.isDarwin [ libiconv libobjc libunwind Foundation ];
+
+        enableParallelBuilding = true;
+
+        hardeningDisable = lib.optional isRuby20 "format";
+
+        patches =
+          (import ./patchsets.nix {
+            inherit patchSet useRailsExpress ops fetchpatch;
+            patchLevel = ver.patchLevel;
+          }).${ver.majMinTiny};
+
+        postUnpack = opString rubygemsSupport ''
+          rm -rf $sourceRoot/{lib,test}/rubygems*
+          cp -r ${rubygems}/lib/rubygems* $sourceRoot/lib
+          cp -r ${rubygems}/test/rubygems $sourceRoot/test
+        '' + opString isRuby21 ''
+          rm "$sourceRoot/enc/unicode/name2ctype.h"
+        '';
+
+        postPatch = if isRuby21 then ''
+          rm tool/config_files.rb
+          cp ${config}/config.guess tool/
+          cp ${config}/config.sub tool/
+        ''
+        else opString atLeast25 ''
+          sed -i configure.ac -e '/config.guess/d'
+          cp --remove-destination ${config}/config.guess tool/
+          cp --remove-destination ${config}/config.sub tool/
+        '';
+
+        # Force the revision.h generation. Somehow `revision.tmp` is an empty
+        # file and because we don't add `git` to buildInputs, hence the check is
+        # always true.
+        # https://github.com/ruby/ruby/commit/97a5af62a318fcd93a4e5e4428d576c0280ddbae
+        buildFlags = lib.optionals atLeast27 [ "REVISION_LATEST=0" ];
+
+        configureFlags = ["--enable-shared" "--enable-pthread" "--with-soname=ruby-${version}"]
+          ++ op useRailsExpress "--with-baseruby=${baseruby}/bin/ruby"
+          ++ op (!docSupport) "--disable-install-doc"
+          ++ ops stdenv.isDarwin [
+            # on darwin, we have /usr/include/tk.h -- so the configure script detects
+            # that tk is installed
+            "--with-out-ext=tk"
+            # on yosemite, "generating encdb.h" will hang for a very long time without this flag
+            "--with-setjmp-type=setjmp"
+          ]
+          ++ op (stdenv.hostPlatform != stdenv.buildPlatform)
+             "--with-baseruby=${buildRuby}";
+
+        preConfigure = opString docSupport ''
+          configureFlagsArray+=("--with-ridir=$devdoc/share/ri")
+        '';
+
+        # fails with "16993 tests, 2229489 assertions, 105 failures, 14 errors, 89 skips"
+        # mostly TZ- and patch-related tests
+        # TZ- failures are caused by nix sandboxing, I didn't investigate others
+        doCheck = false;
+
+        preInstall = ''
+          # Ruby installs gems here itself now.
+          mkdir -pv "$out/${passthru.gemPath}"
+          export GEM_HOME="$out/${passthru.gemPath}"
+        '';
+
+        installFlags = stdenv.lib.optional docSupport "install-doc";
+        # Bundler tries to create this directory
+        postInstall = ''
+          # Remove unnecessary groff reference from runtime closure, since it's big
+          sed -i '/NROFF/d' $out/lib/ruby/*/*/rbconfig.rb
+          ${
+            lib.optionalString removeReferenceToCC ''
+              # Get rid of the CC runtime dependency
+              ${removeReferencesTo}/bin/remove-references-to \
+                -t ${stdenv.cc} \
+                $out/lib/libruby*
+            ''
+          }
+          # Bundler tries to create this directory
+          mkdir -p $out/nix-support
+          cat > $out/nix-support/setup-hook <<EOF
+          addGemPath() {
+            addToSearchPath GEM_PATH \$1/${passthru.gemPath}
+          }
+          addRubyLibPath() {
+            addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby
+            addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby/${ver.libDir}
+            addToSearchPath RUBYLIB \$1/lib/ruby/site_ruby/${ver.libDir}/${stdenv.targetPlatform.system}
+          }
+
+          addEnvHooks "$hostOffset" addGemPath
+          addEnvHooks "$hostOffset" addRubyLibPath
+          EOF
+
+          rbConfig=$(find $out/lib/ruby -name rbconfig.rb)
+        '' + opString docSupport ''
+          # Prevent the docs from being included in the closure
+          sed -i "s|\$(DESTDIR)$devdoc|\$(datarootdir)/\$(RI_BASE_NAME)|" $rbConfig
+          sed -i "s|'--with-ridir=$devdoc/share/ri'||" $rbConfig
+
+          # Add rbconfig shim so ri can find docs
+          mkdir -p $devdoc/lib/ruby/site_ruby
+          cp ${./rbconfig.rb} $devdoc/lib/ruby/site_ruby/rbconfig.rb
+        '' + opString useRailsExpress ''
+          # Prevent the baseruby from being included in the closure.
+          sed -i '/^  CONFIG\["BASERUBY"\]/d' $rbConfig
+          sed -i "s|'--with-baseruby=${baseruby}/bin/ruby'||" $rbConfig
+        '';
+
+        meta = with stdenv.lib; {
+          description = "The Ruby language";
+          homepage    = "http://www.ruby-lang.org/en/";
+          license     = licenses.ruby;
+          maintainers = with maintainers; [ vrthra manveru ];
+          platforms   = platforms.all;
+        };
+
+        passthru = rec {
+          version = ver;
+          rubyEngine = "ruby";
+          baseRuby = baseruby;
+          libPath = "lib/${rubyEngine}/${ver.libDir}";
+          gemPath = "lib/${rubyEngine}/gems/${ver.libDir}";
+          devEnv = import ./dev.nix {
+            inherit buildEnv bundler bundix;
+            ruby = self;
+          };
+
+          inherit (with-packages) withPackages gems;
+
+          # deprecated 2016-09-21
+          majorVersion = ver.major;
+          minorVersion = ver.minor;
+          teenyVersion = ver.tiny;
+          patchLevel = ver.patchLevel;
+        };
+      }
+    ) args; in self;
+
+in {
+  ruby_1_9 = generic {
+    version = rubyVersion "1" "9" "3" "p551";
+    sha256 = {
+      src = "1s2ibg3s2iflzdv7rfxi1qqkvdbn2dq8gxdn0nxrb77ls5ffanxv";
+      git = "1r9xzzxmci2ajb34qb4y1w424mz878zdgzxkfp9w60agldxnb36s";
+    };
+  };
+
+  ruby_2_0 = generic {
+    version = rubyVersion "2" "0" "0" "p648";
+    sha256 = {
+      src = "1y3n4c6xw2wki7pyjpq5zpbgxnw5i3jc8mcpj6rk7hs995mvv446";
+      git = "0ncjfq4hfqj9kcr8pbll6kypwnmcgs8w7l4466qqfyv7jj3yjd76";
+    };
+  };
+
+  ruby_2_1 = generic {
+    version = rubyVersion "2" "1" "10" "";
+    sha256 = {
+      src = "086x66w51lg41abjn79xb7f6xsryymkcc3nvakmkjnjyg96labpv";
+      git = "133phd5r5y0np5lc9nqif93l7yb13yd52aspyl6c46z5jhvhyvfi";
+    };
+  };
+
+  ruby_2_2 = generic {
+    version = rubyVersion "2" "2" "9" "";
+    sha256 = {
+      src = "19m1ximl7vcrsvq595dgrjh4yb6kar944095wbywqh7waiqcfirg";
+      git = "03qrjh55098wcqh2khxryzkzfqkznjrcdgwf27r2bgcycbg5ca5q";
+    };
+  };
+
+  ruby_2_3 = generic {
+    version = rubyVersion "2" "3" "8" "";
+    sha256 = {
+      src = "1gwsqmrhpx1wanrfvrsj3j76rv888zh7jag2si2r14qf8ihns0dm";
+      git = "0158fg1sx6l6applbq0831kl8kzx5jacfl9lfg0shfzicmjlys3f";
+    };
+  };
+
+  ruby_2_4 = generic {
+    version = rubyVersion "2" "4" "9" "";
+    sha256 = {
+      src = "1bn6n5b920qy3lsx99jr8495jkc3sg89swgb96d5fgd579g6p6zr";
+      git = "066kb1iki7mx7qkm10xhj5b6v8s47wg68v43l3nc36y2hyim1w2c";
+    };
+  };
+
+  ruby_2_5 = generic {
+    version = rubyVersion "2" "5" "8" "";
+    sha256 = {
+      src = "16md4jspjwixjlbhx3pnd5iwpca07p23ghkxkqd82sbchw3xy2vc";
+      git = "19gkk3q9l33cwkfsp5k8f8fipq7gkyqkqirm9farbvy425519rv2";
+    };
+  };
+
+  ruby_2_6 = generic {
+    version = rubyVersion "2" "6" "6" "";
+    sha256 = {
+      src = "1492x795qzgp3zhpl580kd1sdp50n5hfsmpbfhdsq2rnxwyi8jrn";
+      git = "1jr9v99a7awssqmw7531afbx4a8i9x5yfqyffha545g7r4s7kj50";
+    };
+  };
+
+  ruby_2_7 = generic {
+    version = rubyVersion "2" "7" "1" "";
+    sha256 = {
+      src = "0674x98f542y02r7n2yv2qhmh97blqhi2mvh2dn5f000vlxlh66l";
+      git = "0qk729kr5wm67xmwpljpdprwhp5wvn5y4ikqy00p1zcgwlwdcs33";
+    };
+  };
+}
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/dev.nix b/nixpkgs/pkgs/development/interpreters/ruby/dev.nix
new file mode 100644
index 000000000000..62d561fbc142
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/dev.nix
@@ -0,0 +1,23 @@
+/* An environment for development that bundles ruby, bundler and bundix
+   together. This avoids version conflicts where each is using a diferent
+   version of each-other.
+*/
+{ buildEnv, ruby, bundler, bundix }:
+let
+  bundler_ = bundler.override {
+    ruby = ruby;
+  };
+  bundix_ = bundix.override {
+    bundler = bundler_;
+  };
+in
+buildEnv {
+  name = "${ruby.rubyEngine}-dev-${ruby.version}";
+  paths = [
+    bundix_
+    bundler_
+    ruby
+  ];
+  pathsToLink = [ "/bin" ];
+  ignoreCollisions = true;
+}
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/patchsets.nix b/nixpkgs/pkgs/development/interpreters/ruby/patchsets.nix
new file mode 100644
index 000000000000..4407cb6e5da4
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/patchsets.nix
@@ -0,0 +1,83 @@
+{ patchSet, useRailsExpress, ops, patchLevel, fetchpatch }:
+
+{
+  "1.9.3" = [
+    ./ssl_v3.patch
+    ./rand-egd.patch
+    ./ruby19-parallel-install.patch
+    ./bitperfect-rdoc.patch
+  ] ++ ops useRailsExpress [
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/01-fix-make-clean.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/02-zero-broken-tests.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/03-railsbench-gc.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/04-display-more-detailed-stack-trace.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/05-fork-support-for-gc-logging.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/06-track-live-dataset-size.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/07-webrick_204_304_keep_alive_fix.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/08-export-a-few-more-symbols-for-ruby-prof.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/09-thread-variables.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/10-faster-loading.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/11-falcon-st-opt.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/12-falcon-sparse-array.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/13-falcon-array-queue.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/14-railsbench-gc-fixes.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/15-show-full-backtrace-on-stack-overflow.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/16-configurable-fiber-stack-sizes.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/17-backport-psych-20.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/18-fix-missing-c-return-event.patch"
+    "${patchSet}/patches/ruby/1.9.3/p${patchLevel}/railsexpress/19-fix-process-daemon-call.patch"
+  ];
+  "2.0.0" = [
+    ./ssl_v3.patch
+    ./rand-egd.patch
+  ] ++ ops useRailsExpress [
+    "${patchSet}/patches/ruby/2.0.0/p${patchLevel}/railsexpress/01-zero-broken-tests.patch"
+    "${patchSet}/patches/ruby/2.0.0/p${patchLevel}/railsexpress/02-railsexpress-gc.patch"
+    "${patchSet}/patches/ruby/2.0.0/p${patchLevel}/railsexpress/03-display-more-detailed-stack-trace.patch"
+    "${patchSet}/patches/ruby/2.0.0/p${patchLevel}/railsexpress/04-show-full-backtrace-on-stack-overflow.patch"
+  ];
+  "2.1.10" = [
+    ./rand-egd.patch
+  ] ++ ops useRailsExpress [
+    # 2.1.10 patchsets are not available, but 2.1.8 patchsets apply
+    "${patchSet}/patches/ruby/2.1.8/railsexpress/01-zero-broken-tests.patch"
+    "${patchSet}/patches/ruby/2.1.8/railsexpress/02-improve-gc-stats.patch"
+    "${patchSet}/patches/ruby/2.1.8/railsexpress/03-display-more-detailed-stack-trace.patch"
+    "${patchSet}/patches/ruby/2.1.8/railsexpress/04-show-full-backtrace-on-stack-overflow.patch"
+    "${patchSet}/patches/ruby/2.1.8/railsexpress/05-funny-falcon-stc-density.patch"
+    "${patchSet}/patches/ruby/2.1.8/railsexpress/06-funny-falcon-stc-pool-allocation.patch"
+    "${patchSet}/patches/ruby/2.1.8/railsexpress/07-aman-opt-aset-aref-str.patch"
+    "${patchSet}/patches/ruby/2.1.8/railsexpress/08-funny-falcon-method-cache.patch"
+    "${patchSet}/patches/ruby/2.1.8/railsexpress/09-heap-dump-support.patch"
+  ];
+  "2.2.9" = ops useRailsExpress [
+    "${patchSet}/patches/ruby/2.2/head/railsexpress/01-zero-broken-tests.patch"
+    "${patchSet}/patches/ruby/2.2/head/railsexpress/02-improve-gc-stats.patch"
+    "${patchSet}/patches/ruby/2.2/head/railsexpress/03-display-more-detailed-stack-trace.patch"
+  ];
+  "2.3.8" = ops useRailsExpress [
+    "${patchSet}/patches/ruby/2.3/head/railsexpress/01-skip-broken-tests.patch"
+    "${patchSet}/patches/ruby/2.3/head/railsexpress/02-improve-gc-stats.patch"
+    "${patchSet}/patches/ruby/2.3/head/railsexpress/03-display-more-detailed-stack-trace.patch"
+  ];
+  "2.4.9" = ops useRailsExpress [
+    "${patchSet}/patches/ruby/2.4/head/railsexpress/01-skip-broken-tests.patch"
+    "${patchSet}/patches/ruby/2.4/head/railsexpress/02-improve-gc-stats.patch"
+    "${patchSet}/patches/ruby/2.4/head/railsexpress/03-display-more-detailed-stack-trace.patch"
+  ];
+  "2.5.8" = ops useRailsExpress [
+    "${patchSet}/patches/ruby/2.5/head/railsexpress/01-fix-broken-tests-caused-by-ad.patch"
+    "${patchSet}/patches/ruby/2.5/head/railsexpress/02-improve-gc-stats.patch"
+    "${patchSet}/patches/ruby/2.5/head/railsexpress/03-more-detailed-stacktrace.patch"
+  ];
+  "2.6.6" = ops useRailsExpress [
+    "${patchSet}/patches/ruby/2.6/head/railsexpress/01-fix-broken-tests-caused-by-ad.patch"
+    "${patchSet}/patches/ruby/2.6/head/railsexpress/02-improve-gc-stats.patch"
+    "${patchSet}/patches/ruby/2.6/head/railsexpress/03-more-detailed-stacktrace.patch"
+  ];
+  "2.7.1" = ops useRailsExpress [
+    "${patchSet}/patches/ruby/2.7/head/railsexpress/01-fix-broken-tests-caused-by-ad.patch"
+    "${patchSet}/patches/ruby/2.7/head/railsexpress/02-improve-gc-stats.patch"
+    "${patchSet}/patches/ruby/2.7/head/railsexpress/03-more-detailed-stacktrace.patch"
+  ];
+}
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/rand-egd.patch b/nixpkgs/pkgs/development/interpreters/ruby/rand-egd.patch
new file mode 100644
index 000000000000..e4f6452000c2
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/rand-egd.patch
@@ -0,0 +1,42 @@
+diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
+index e272cba..3a1fa71 100644
+--- a/ext/openssl/extconf.rb
++++ b/ext/openssl/extconf.rb
+@@ -87,6 +87,7 @@
+ have_func("PEM_def_callback")
+ have_func("PKCS5_PBKDF2_HMAC")
+ have_func("PKCS5_PBKDF2_HMAC_SHA1")
++have_func("RAND_egd")
+ have_func("X509V3_set_nconf")
+ have_func("X509V3_EXT_nconf_nid")
+ have_func("X509_CRL_add0_revoked")
+diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c
+index 29cbf8c..27466fe 100644
+--- a/ext/openssl/ossl_rand.c
++++ b/ext/openssl/ossl_rand.c
+@@ -148,6 +148,7 @@ ossl_rand_pseudo_bytes(VALUE self, VALUE len)
+     return str;
+ }
+ 
++#ifdef HAVE_RAND_EGD
+ /*
+  *  call-seq:
+  *     egd(filename) -> true
+@@ -186,6 +187,7 @@ ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
+     }
+     return Qtrue;
+ }
++#endif /* HAVE_RAND_EGD */
+ 
+ /*
+  *  call-seq:
+@@ -219,7 +221,9 @@ Init_ossl_rand(void)
+     DEFMETH(mRandom, "write_random_file", ossl_rand_write_file, 1);
+     DEFMETH(mRandom, "random_bytes", ossl_rand_bytes, 1);
+     DEFMETH(mRandom, "pseudo_bytes", ossl_rand_pseudo_bytes, 1);
++#ifdef HAVE_RAND_EGD
+     DEFMETH(mRandom, "egd", ossl_rand_egd, 1);
+     DEFMETH(mRandom, "egd_bytes", ossl_rand_egd_bytes, 2);
++#endif /* HAVE_RAND_EGD */
+     DEFMETH(mRandom, "status?", ossl_rand_status, 0)
+ }
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/rbconfig.rb b/nixpkgs/pkgs/development/interpreters/ruby/rbconfig.rb
new file mode 100644
index 000000000000..eeba930b54b7
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/rbconfig.rb
@@ -0,0 +1,25 @@
+# This is a shim around whatever real rbconfig.rb is in the LOAD_PATH,
+# so that RbConfig::CONFIG["ridir"] can be overridden to point to the
+# custom location of the ri docs, without the main derivation having
+# those docs in its closure.
+
+MY_PATH = File.realpath(__FILE__)
+
+candidates = $LOAD_PATH.map { |dir| File.join(dir, "rbconfig.rb") }
+
+# First, drop everything _before_ this file in the LOAD_PATH, just on
+# the off-chance somebody is composing shims like this for some reason.
+candidates.drop_while { |c| !File.exist?(c) || File.realpath(c) != MY_PATH }
+
+# Now, the wrapped rbconfig.rb is the next rbconfig.rb in the LOAD_PATH
+# that isn't this same file. (Yes, duplicate LOAD_PATH entries are a
+# thing we have to deal with.)
+next_rbconfig = candidates.find { |c|
+  File.exist?(c) && File.realpath(c) != MY_PATH
+}
+
+# Load the wrapped rbconfig.rb
+require next_rbconfig
+
+# Now we have RbConfig, and can modify it for our own ends.
+RbConfig::CONFIG["ridir"] = File.expand_path("../../../share/ri", __dir__)
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/ruby-version.nix b/nixpkgs/pkgs/development/interpreters/ruby/ruby-version.nix
new file mode 100644
index 000000000000..b1cbbfc216dc
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/ruby-version.nix
@@ -0,0 +1,63 @@
+# Contains the ruby version heuristics
+{ lib }:
+with lib;
+let
+  # The returned set should be immutable
+  rubyVersion = major: minor: tiny: tail:
+    rec {
+      inherit major minor tiny tail;
+
+      # Contains the patch number "223" if tail is "p223" or null
+      patchLevel =
+        let
+          p = removePrefix "p" tail;
+          isPosInt = num:
+            0 == stringLength
+              (replaceStrings
+              ["0" "1" "2" "3" "4" "5" "6" "7" "8" "9"]
+              [""  ""  ""  ""  ""  ""  ""  ""  ""  "" ]
+              num);
+        in
+          if hasPrefix "p" tail && isPosInt p then p
+          else null;
+
+      # Shortcuts
+      majMin = "${major}.${minor}";
+      majMinTiny = "${major}.${minor}.${tiny}";
+
+      # Ruby separates lib and gem folders by ABI version which isn't very
+      # consistent.
+      libDir =
+        if versionAtLeast majMinTiny "2.1.0" then
+          "${majMin}.0"
+        else if versionAtLeast majMinTiny "2.0.0" then
+          "2.0.0"
+        else if versionAtLeast majMinTiny "1.9.1" then
+          "1.9.1"
+        else
+          throw "version ${majMinTiny} is not supported";
+
+      # How ruby releases are tagged on github.com/ruby/ruby
+      gitTag =
+        let
+          base = "v${major}_${minor}_${tiny}";
+        in
+          if patchLevel != null then
+            "${base}_${patchLevel}"
+          else
+            if tail != "" then
+              "${base}_${tail}"
+            else
+              base;
+
+      # Implements the builtins.toString interface.
+      __toString = self:
+        self.majMinTiny + (
+          if self.patchLevel != null then
+            "-p${self.patchLevel}"
+          else if self.tail != "" then
+            "-${self.tail}"
+          else "");
+    };
+in
+  rubyVersion
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/ruby19-parallel-install.patch b/nixpkgs/pkgs/development/interpreters/ruby/ruby19-parallel-install.patch
new file mode 100644
index 000000000000..bb8063508732
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/ruby19-parallel-install.patch
@@ -0,0 +1,15 @@
+Index: ruby-1.9.3-p392/lib/mkmf.rb
+===================================================================
+--- ruby-1.9.3-p392.orig/lib/mkmf.rb
++++ ruby-1.9.3-p392/lib/mkmf.rb
+@@ -2039,8 +2039,8 @@ static: $(STATIC_LIB)#{$extout ? " insta
+       end
+       for f in files
+         dest = "#{dir}/#{File.basename(f)}"
+-        mfile.print("install-rb#{sfx}: #{dest} #{dir}\n")
+-        mfile.print("#{dest}: #{f}\n")
++        mfile.print("install-rb#{sfx}: #{dest}\n")
++        mfile.print("#{dest}: #{f} #{timestamp_file(dir)}\n")
+         mfile.print("\t$(Q) $(#{$extout ? 'COPY' : 'INSTALL_DATA'}) #{f} $(@D#{sep})\n")
+         if defined?($installed_list) and !$extout
+           mfile.print("\t@echo #{dest}>>$(INSTALLED_LIST)\n")
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/rubygems/0001-add-post-extract-hook.patch b/nixpkgs/pkgs/development/interpreters/ruby/rubygems/0001-add-post-extract-hook.patch
new file mode 100644
index 000000000000..84d1d52409e5
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/rubygems/0001-add-post-extract-hook.patch
@@ -0,0 +1,34 @@
+From a6485cfcdf51ff8be452980f93cebfea97f34dec Mon Sep 17 00:00:00 2001
+From: zimbatm <zimbatm@zimbatm.com>
+Date: Wed, 21 Sep 2016 09:32:34 +0100
+Subject: [PATCH 1/3] add post-extract hook
+
+Allows nix to execute scripts just after the gem extraction
+---
+ lib/rubygems/installer.rb | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
+index d26b1e88..bf18fb7f 100644
+--- a/lib/rubygems/installer.rb
++++ b/lib/rubygems/installer.rb
+@@ -848,7 +848,15 @@ TEXT
+   # Ensures that files can't be installed outside the gem directory.
+ 
+   def extract_files
+-    @package.extract_files gem_dir
++    ret = @package.extract_files gem_dir
++    if ENV['NIX_POST_EXTRACT_FILES_HOOK']
++      puts
++      puts "running NIX_POST_EXTRACT_FILES_HOOK #{ENV['NIX_POST_EXTRACT_FILES_HOOK']} #{gem_dir}"
++      system(ENV['NIX_POST_EXTRACT_FILES_HOOK'], gem_dir.to_s)
++      puts "running NIX_POST_EXTRACT_FILES_HOOK done"
++      puts
++    end
++    ret
+   end
+ 
+   ##
+-- 
+2.21.0
+
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/rubygems/0002-binaries-with-env-shebang.patch b/nixpkgs/pkgs/development/interpreters/ruby/rubygems/0002-binaries-with-env-shebang.patch
new file mode 100644
index 000000000000..d6eba67e1065
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/rubygems/0002-binaries-with-env-shebang.patch
@@ -0,0 +1,28 @@
+From 2e1328bcdddd35e557eabdff83ac07f3591dc693 Mon Sep 17 00:00:00 2001
+From: zimbatm <zimbatm@zimbatm.com>
+Date: Wed, 21 Sep 2016 19:37:05 +0100
+Subject: [PATCH 2/3] binaries with env shebang
+
+By default, don't point to the absolute ruby derivation path. As a user
+installing a gem in the home, it would freeze the selected ruby version
+to the currently-installed ruby derivation.
+---
+ lib/rubygems/dependency_installer.rb | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb
+index 34620860..00ab31d9 100644
+--- a/lib/rubygems/dependency_installer.rb
++++ b/lib/rubygems/dependency_installer.rb
+@@ -18,7 +18,7 @@ class Gem::DependencyInstaller
+   extend Gem::Deprecate
+ 
+   DEFAULT_OPTIONS = { # :nodoc:
+-    :env_shebang         => false,
++    :env_shebang         => true,
+     :document            => %w[ri],
+     :domain              => :both, # HACK dup
+     :force               => false,
+-- 
+2.21.0
+
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/rubygems/0003-gem-install-default-to-user.patch b/nixpkgs/pkgs/development/interpreters/ruby/rubygems/0003-gem-install-default-to-user.patch
new file mode 100644
index 000000000000..138d432c8203
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/rubygems/0003-gem-install-default-to-user.patch
@@ -0,0 +1,26 @@
+From d69249d0ff210316121b44d971ddd2439b1bc393 Mon Sep 17 00:00:00 2001
+From: zimbatm <zimbatm@zimbatm.com>
+Date: Wed, 21 Sep 2016 09:40:39 +0100
+Subject: [PATCH 3/3] gem install default to user
+
+Default to not installing gems to the read-only system derivation.
+---
+ lib/rubygems/path_support.rb | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lib/rubygems/path_support.rb b/lib/rubygems/path_support.rb
+index ed680d65..749b9ea6 100644
+--- a/lib/rubygems/path_support.rb
++++ b/lib/rubygems/path_support.rb
+@@ -23,7 +23,7 @@ class Gem::PathSupport
+   # hashtable, or defaults to ENV, the system environment.
+   #
+   def initialize(env)
+-    @home = env["GEM_HOME"] || Gem.default_dir
++    @home = env["GEM_HOME"] || Gem.user_dir
+ 
+     if File::ALT_SEPARATOR
+       @home = @home.gsub(File::ALT_SEPARATOR, File::SEPARATOR)
+-- 
+2.21.0
+
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/rubygems/default.nix b/nixpkgs/pkgs/development/interpreters/ruby/rubygems/default.nix
new file mode 100644
index 000000000000..0bbcadba3f51
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/rubygems/default.nix
@@ -0,0 +1,35 @@
+{ stdenv, lib, fetchurl, fetchpatch }:
+
+stdenv.mkDerivation rec {
+  name = "rubygems";
+  version = "3.1.2";
+
+  src = fetchurl {
+    url = "https://rubygems.org/rubygems/rubygems-${version}.tgz";
+    sha256 = "0h7ij4jpj8rgnpkl63cwh2lnav73pw5wpfqra3va7077lsyadlgd";
+  };
+
+  patches = [
+    ./0001-add-post-extract-hook.patch
+    ./0002-binaries-with-env-shebang.patch
+    ./0003-gem-install-default-to-user.patch
+
+    (fetchpatch {
+      url = "https://github.com/rubygems/rubygems/commit/0af4d2d369ff580ef54839ec15a8c7ec419978cb.patch";
+      sha256 = "13gyfxn4rmxq1dbxq5rzphnhagn8n8kpp8lb9h6h4s9d4zaklax9";
+    })
+  ];
+
+  installPhase = ''
+    runHook preInstall
+    cp -r . $out
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Package management framework for Ruby";
+    homepage = "https://rubygems.org/";
+    license = with licenses; [ mit /* or */ ruby ];
+    maintainers = with maintainers; [ qyliss zimbatm ];
+  };
+}
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/rvm-patchsets.nix b/nixpkgs/pkgs/development/interpreters/ruby/rvm-patchsets.nix
new file mode 100644
index 000000000000..331dda5d0503
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/rvm-patchsets.nix
@@ -0,0 +1,8 @@
+{ fetchFromGitHub }:
+
+fetchFromGitHub {
+  owner  = "skaes";
+  repo   = "rvm-patchsets";
+  rev    = "6d8888d34a321198f7fd9253343b78c209efb046";
+  sha256 = "0xczl0nng1649km3bcbjn6zrr591l6m2kkwgnknh1fnwmmrdaya7";
+}
diff --git a/nixpkgs/pkgs/development/interpreters/ruby/ssl_v3.patch b/nixpkgs/pkgs/development/interpreters/ruby/ssl_v3.patch
new file mode 100644
index 000000000000..faa402165751
--- /dev/null
+++ b/nixpkgs/pkgs/development/interpreters/ruby/ssl_v3.patch
@@ -0,0 +1,16 @@
+--- a/ext/openssl/ossl_ssl.c  2015-11-26 16:41:03.775058140 +0000
++++ b/ext/openssl/ossl_ssl.c  2015-11-26 16:40:56.191907346 +0000
+@@ -138,9 +138,12 @@
+     OSSL_SSL_METHOD_ENTRY(SSLv2_server),
+     OSSL_SSL_METHOD_ENTRY(SSLv2_client),
+ #endif
++#if defined(HAVE_SSLV3_METHOD) && defined(HAVE_SSLV3_SERVER_METHOD) && \
++        defined(HAVE_SSLV3_CLIENT_METHOD)
+     OSSL_SSL_METHOD_ENTRY(SSLv3),
+     OSSL_SSL_METHOD_ENTRY(SSLv3_server),
+     OSSL_SSL_METHOD_ENTRY(SSLv3_client),
++#endif
+     OSSL_SSL_METHOD_ENTRY(SSLv23),
+     OSSL_SSL_METHOD_ENTRY(SSLv23_server),
+     OSSL_SSL_METHOD_ENTRY(SSLv23_client),
+