gnu: go: Update to 1.14.4.
[jackhill/guix/guix.git] / gnu / packages / ruby.scm
index b1adf80..d636005 100644 (file)
@@ -5,7 +5,7 @@
 ;;; Copyright © 2014, 2015 David Thompson <davet@gnu.org>
 ;;; Copyright © 2015, 2019 Ricardo Wurmus <rekado@elephly.net>
 ;;; Copyright © 2015, 2016, 2017 Ben Woodcroft <donttrustben@gmail.com>
-;;; Copyright © 2017 ng0 <ng0@n0.is>
+;;; Copyright © 2017 Nikita <nikita@n0.is>
 ;;; Copyright © 2017, 2019, 2020 Marius Bakke <mbakke@fastmail.com>
 ;;; Copyright © 2017, 2018, 2019 Efraim Flashner <efraim@flashner.co.il>
 ;;; Copyright © 2017, 2018, 2020 Tobias Geerinckx-Rice <me@tobias.gr>
@@ -20,6 +20,7 @@
 ;;; Copyright © 2019 Collin J. Doering <collin@rekahsoft.ca>
 ;;; Copyright © 2019 Diego N. Barbato <dnbarbato@posteo.de>
 ;;; Copyright © 2019 Brett Gilio <brettg@posteo.de>
+;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -41,6 +42,7 @@
   #:use-module (gnu packages)
   #:use-module (gnu packages base)
   #:use-module (gnu packages bison)
+  #:use-module (gnu packages c)
   #:use-module (gnu packages check)
   #:use-module (gnu packages compression)
   #:use-module (gnu packages crypto)
@@ -131,29 +133,53 @@ a focus on simplicity and productivity.")
     (home-page "https://www.ruby-lang.org")
     (license license:ruby)))
 
-(define-public ruby-2.5
+(define-public ruby-2.7
   (package
     (inherit ruby)
-    (version "2.5.7")
+    (version "2.7.1")
     (source
      (origin
        (method url-fetch)
        (uri (string-append "http://cache.ruby-lang.org/pub/ruby/"
                            (version-major+minor version)
-                           "/ruby-" version ".tar.xz"))
+                           "/ruby-" version ".tar.gz"))
        (sha256
         (base32
-         "159zka4sbx1p4ayxqi7a5ybbzxvn3n5mivrz4d1damw9ypl70610"))
+         "0674x98f542y02r7n2yv2qhmh97blqhi2mvh2dn5f000vlxlh66l"))
        (modules '((guix build utils)))
        (snippet `(begin
                    ;; Remove bundled libffi
                    (delete-file-recursively "ext/fiddle/libffi-3.2.1")
-                   #t))))))
+                   #t))))
+    (arguments
+     `(#:test-target "test"
+       #:configure-flags '("--enable-shared") ; dynamic linking
+       #:phases
+       (modify-phases %standard-phases
+         (add-before 'configure 'replace-bin-sh-and-remove-libffi
+           (lambda _
+             (substitute* '("configure.ac"
+                            "template/Makefile.in"
+                            "lib/rubygems/installer.rb"
+                            "ext/pty/pty.c"
+                            "io.c"
+                            "lib/mkmf.rb"
+                            "process.c"
+                            "test/rubygems/test_gem_ext_configure_builder.rb"
+                            "test/rdoc/test_rdoc_parser.rb"
+                            "test/ruby/test_rubyoptions.rb"
+                            "test/ruby/test_process.rb"
+                            "test/ruby/test_system.rb"
+                            "tool/rbinstall.rb")
+               (("/bin/sh") (which "sh")))
+             #t)))))
+    (native-inputs
+     `(("autoconf" ,autoconf)))))
 
-(define-public ruby-2.4
+(define-public ruby-2.5
   (package
     (inherit ruby)
-    (version "2.4.9")
+    (version "2.5.8")
     (source
      (origin
        (method url-fetch)
@@ -162,17 +188,17 @@ a focus on simplicity and productivity.")
                            "/ruby-" version ".tar.xz"))
        (sha256
         (base32
-         "0546ymj2h3iai679fvx17bb2hksrqyhh22llxgz8fwggac100khc"))
+         "0vad5ah1lrdhxsyqr5iqc8c7r7qczpmm76cz8rsf4crimpzv5483"))
        (modules '((guix build utils)))
        (snippet `(begin
                    ;; Remove bundled libffi
                    (delete-file-recursively "ext/fiddle/libffi-3.2.1")
                    #t))))))
 
-(define-public ruby-2.3
+(define-public ruby-2.4
   (package
     (inherit ruby)
-    (version "2.3.8")
+    (version "2.4.10")
     (source
      (origin
        (method url-fetch)
@@ -181,7 +207,7 @@ a focus on simplicity and productivity.")
                            "/ruby-" version ".tar.xz"))
        (sha256
         (base32
-         "1zhxbjff08pvbnxvn58krns6q0p6g4977q6ykfn823gxhifn63wi"))
+         "1prhqlgik1zmw9lakl6hkriqslspw48pvhxff17h7ns42p8qwrnm"))
        (modules '((guix build utils)))
        (snippet `(begin
                    ;; Remove bundled libffi
@@ -357,13 +383,13 @@ announcement.")
 (define-public ruby-rake-compiler
   (package
     (name "ruby-rake-compiler")
-    (version "1.0.4")
+    (version "1.1.0")
     (source (origin
               (method url-fetch)
               (uri (rubygems-uri "rake-compiler" version))
               (sha256
                (base32
-                "1xpdi4w8zaklk1i9ps8g3k0icw3v5fcks092l84w28rgrpx82qip"))))
+                "0l4hg21v0phfrfsc2hilgmwvn2imxr0byqh8dv16bya1s5d3km0q"))))
     (build-system ruby-build-system)
     (arguments
      '(#:tests? #f)) ; needs cucumber
@@ -621,10 +647,12 @@ outcomes of a code example.")
                (("rspec rspec-core rspec-expectations rspec-mocks rspec-support")
                 ""))
              #t))
-         (add-before 'build 'update-ffi-in-gemfile
+         (add-before 'build 'loosen-ffi-requirement
            (lambda _
+             ;; Accept any version of ruby-ffi.
              (substitute* "Gemfile"
-               (("  gem 'ffi', '~> 1.9.25'") "  gem 'ffi', '~> 1.10.0'"))
+               (("  gem 'ffi', '~> 1\\.9\\.25'")
+                "  gem 'ffi'"))
              #t))
          (add-before 'build 'remove-unnecessary-dependency-versions-from-gemfile
            (lambda _
@@ -1518,6 +1546,49 @@ a Ruby object.")
     (home-page "https://github.com/rails/execjs")
     (license license:expat)))
 
+(define-public ruby-fakefs
+  (package
+    (name "ruby-fakefs")
+    (version "1.2.2")
+    (home-page "https://github.com/fakefs/fakefs")
+    (source (origin
+              ;; The Rubygems release does not contain tests.
+              (method git-fetch)
+              (uri (git-reference
+                    (url home-page)
+                    (commit (string-append "v" version))))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "008dq9knyip2bfbl0mrk8b8r7bv0k3bf128wcfqsgy1rqal4mgwk"))))
+    (build-system ruby-build-system)
+    (arguments
+     '(#:phases (modify-phases %standard-phases
+                  (replace 'replace-git-ls-files
+                    (lambda _
+                      (substitute* "fakefs.gemspec"
+                        (("`git ls-files lib README.md LICENSE`")
+                         "`find lib README.md LICENSE -type f | sort`"))
+                      #t))
+                  (add-before 'check 'remove-version-constraints
+                    (lambda _
+                      ;; Drop hard version requirements for test dependencies.
+                      (substitute* "fakefs.gemspec"
+                        (("(.*add_development_dependency .*), .*" _ dep)
+                         (string-append dep "\n")))
+                      #t)))))
+    (native-inputs
+     `(("ruby-bump" ,ruby-bump)
+       ("ruby-maxitest" ,ruby-maxitest)
+       ("ruby-rubocop" ,ruby-rubocop)
+       ("ruby-rspec" ,ruby-rspec)))
+    (synopsis "Fake file system for Ruby")
+    (description
+     "This package provides a fake file system for use in test suites.  It
+avoids the need for manually creating temporary directories, or dealing
+with platform intricacies in @code{File} and @code{FileUtils}.")
+    (license license:expat)))
+
 (define-public ruby-orderedhash
   (package
     (name "ruby-orderedhash")
@@ -1613,18 +1684,70 @@ Ruby.")
 (define-public ruby-thor
   (package
     (name "ruby-thor")
-    (version "0.19.4")
+    (version "1.0.1")
     (source (origin
-              (method url-fetch)
-              (uri (rubygems-uri "thor" version))
+              ;; Pull from git because the gem has no tests.
+              (method git-fetch)
+              (uri (git-reference
+                    (url "https://github.com/erikhuda/thor")
+                    (commit (string-append "v" version))))
+              (file-name (git-file-name name version))
               (sha256
                (base32
-                "01n5dv9kql60m6a00zc0r66jvaxx98qhdny3klyj0p3w34pad2ns"))))
-    (build-system ruby-build-system)
-    (arguments
-     '(#:tests? #f)) ; no test suite
+                "1anrx5vynk57hn5c8ig5pgkmcsbj9q5mvckd5rviw1jid7n89k57"))))
+    (build-system ruby-build-system)
+    (arguments
+     '(#:phases (modify-phases %standard-phases
+                  (add-after 'unpack 'fix-readline-tests
+                    (lambda _
+                      ;; Ensure Readline is initialized before running the
+                      ;; test to avoid a type clash with the mock ::Readline.
+                      ;; See <https://github.com/erikhuda/thor/pull/717>.
+                      (substitute* "spec/line_editor/readline_spec.rb"
+                        (("unless defined\\? ::Readline" all)
+                         (string-append "Thor::LineEditor::Readline.available?\n"
+                                        all)))
+                      #t))
+                  (add-after 'unpack 'remove-coveralls-dependency
+                    (lambda _
+                      ;; Do not hook the test suite into the online
+                      ;; coveralls service.
+                      (substitute* "Gemfile"
+                        ((".*coveralls.*") ""))
+                      (substitute* "spec/helper.rb"
+                        (("require \"coveralls\"") "")
+                        (("Coveralls::SimpleCov::Formatter") "")
+                        ;; Also drop the WebMock dependency which is only
+                        ;; present to allow a coveralls.io connection, and
+                        ;; would otherwise introduce a circular dependency.
+                        (("require \"webmock/rspec\"") "")
+                        (("WebMock\\.disable_net_connect.*") ""))
+                      #t))
+                  (add-after 'unpack 'disable-network-tests
+                    (lambda _
+                      ;; These tests attempt to look up example.com.
+                      (substitute* "spec/actions/file_manipulation_spec.rb"
+                        (("it \"accepts (https?) remote sources" _ proto)
+                         (string-append "xit \"accepts " proto " remote sources")))
+                      #t))
+                  (add-after 'unpack 'disable-quality-tests
+                    (lambda _
+                      ;; These tests attempt to check the git repository for
+                      ;; tabs vs spaces, double vs single quotes, etc, and
+                      ;; depend on the git checkout.
+                      (delete-file "spec/quality_spec.rb")
+                      #t))
+                  (add-before 'check 'make-files-writable
+                    (lambda _
+                      ;; The tests needs rw access to the test suite.
+                      (for-each make-file-writable (find-files "spec"))
+                      #t))
+                  (replace 'check
+                    (lambda _
+                      (invoke "rspec" "spec"))))))
     (native-inputs
-     `(("bundler" ,bundler)))
+     `(("ruby-rspec" ,ruby-rspec)
+       ("ruby-simplecov" ,ruby-simplecov)))
     (synopsis "Ruby toolkit for building command-line interfaces")
     (description "Thor is a toolkit for building powerful command-line
 interfaces.")
@@ -1732,6 +1855,41 @@ and inspect the environment.")
     (home-page "https://github.com/e2/nenv")
     (license license:expat)))
 
+(define-public ruby-ptools
+  (package
+    (name "ruby-ptools")
+    (version "1.3.5")
+    (source (origin
+              (method url-fetch)
+              (uri (rubygems-uri "ptools" version))
+              (sha256
+               (base32
+                "1jb1h1nsk9zwykpniw8filbsk26kjsdlpk5wz6w0zyamcd41h87j"))))
+    (build-system ruby-build-system)
+    (arguments
+     '(#:phases (modify-phases %standard-phases
+                  (add-after 'unpack 'patch-/bin/ls
+                    (lambda _
+                      (substitute* "test/test_binary.rb"
+                        (("/bin/ls")
+                         (which "ls")))
+                      #t))
+                   (add-before 'install 'create-gem
+                     (lambda _
+                       ;; Do not attempt to sign the gem.
+                       (substitute* "Rakefile"
+                         (("spec\\.signing_key = .*")
+                          ""))
+                       (invoke "rake" "gem:create"))))))
+    (synopsis "Extra methods for Ruby's @code{File} class")
+    (description
+     "The @dfn{ptools} (power tools) library extends Ruby's core @code{File}
+class with many additional methods modelled after common POSIX tools, such as
+@code{File.which} for finding executables, @code{File.tail} to print the last
+lines of a file, @code{File.wc} to count words, and so on.")
+    (home-page "https://github.com/djberg96/ptools")
+    (license license:artistic2.0)))
+
 (define-public ruby-permutation
   (package
     (name "ruby-permutation")
@@ -1816,6 +1974,57 @@ libraries such as Libnotify.")
     (home-page "https://github.com/guard/notiffany")
     (license license:expat)))
 
+(define-public ruby-forking-test-runner
+  (package
+    (name "ruby-forking-test-runner")
+    (version "1.6.0")
+    (home-page "https://github.com/grosser/forking_test_runner")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference (url home-page)
+                                  (commit (string-append "v" version))))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1mrglzkj2nrgisccf2f30zbfmcs0awv1g3lw994b2az90fl39x8m"))))
+    (build-system ruby-build-system)
+    (arguments
+     '(#:test-target "spec"
+       ;; FIXME: ActiveRecord depends on sqlite3 1.3.6, but Guix has
+       ;; 1.4.1, which in turn breaks the tests that use ActiveRecord.
+       #:tests? #f
+       #:phases (modify-phases %standard-phases
+                  (replace 'replace-git-ls-files
+                    (lambda _
+                      (substitute* "forking_test_runner.gemspec"
+                        (("`git ls-files lib/ bin/ MIT-LICENSE`")
+                         "`find lib/ bin/ MIT-LICENSE -type f | sort`"))
+                      #t))
+                  (add-before 'check 'remove-version-constraints
+                    (lambda _
+                      ;; Ignore hard coded version constraints for the tests.
+                      (delete-file "Gemfile.lock")
+                      #t))
+                  (add-before 'check 'set-HOME
+                    (lambda _
+                      ;; Many tests invoke Bundler, and fails when Bundler
+                      ;; warns that /homeless-shelter does not exist.
+                      (setenv "HOME" "/tmp")
+                      #t)))))
+    (native-inputs
+     `(("ruby-activerecord" ,ruby-activerecord)
+       ("ruby-bump" ,ruby-bump)
+       ("ruby-rspec" ,ruby-rspec)
+       ("ruby-sqlite3" ,ruby-sqlite3)
+       ("ruby-wwtd" ,ruby-wwtd)))
+    (propagated-inputs
+     `(("ruby-parallel-tests" ,ruby-parallel-tests)))
+    (synopsis "Run every test in a fork")
+    (description
+     "This package is a wrapper around @code{parallel_tests} that runs every
+test in a fork to avoid pollution and get clean output per test.")
+    (license license:expat)))
+
 (define-public ruby-formatador
   (package
     (name "ruby-formatador")
@@ -2058,13 +2267,13 @@ two hashes.")
 (define-public ruby-rubygems-tasks
   (package
     (name "ruby-rubygems-tasks")
-    (version "0.2.4")
+    (version "0.2.5")
     (source (origin
               (method url-fetch)
               (uri (rubygems-uri "rubygems-tasks" version))
               (sha256
                (base32
-                "16cp45qlbcglnqdm4f1vj3diywdz4v024saqpgrz6palf0wmgz2j"))))
+                "1x3sz3n2dlknd3v7w1mrq6f0ag6pwzhjvg7z29p75w3p42ma1gbx"))))
     (build-system ruby-build-system)
     ;; Tests need Internet access.
     (arguments `(#:tests? #f))
@@ -2287,6 +2496,65 @@ interface for Ruby programs.")
     (home-page "https://github.com/mperham/connection_pool")
     (license license:expat)))
 
+(define-public ruby-fast-gettext
+  (package
+    (name "ruby-fast-gettext")
+    (version "2.0.3")
+    (home-page "https://github.com/grosser/fast_gettext")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference (url home-page)
+                                  (commit (string-append "v" version))))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1dg14apq5sfjshhcq0idphhs7aq9ikzswhqmn689p1h76mxqr1v6"))))
+    (build-system ruby-build-system)
+    (arguments
+     '(#:test-target "spec"
+       #:phases (modify-phases %standard-phases
+                  (add-before 'check 'remove-version-constraints
+                    (lambda _
+                      (delete-file "Gemfile.lock")
+                      #t))
+                  (add-before 'check 'remove-activerecord-test
+                    (lambda _
+                      ;; FIXME: This test fails because ActiveRecord depends on
+                      ;; a different version of ruby-sqlite than the currently
+                      ;; available one.
+                      (delete-file
+                       "spec/fast_gettext/translation_repository/db_spec.rb")
+                      #t))
+                  (add-before 'check 'disable-i18n-test
+                    (lambda _
+                      ;; XXX: This test checks i18n intricasies with Rails 3 and
+                      ;; automatically disables itself for Rails 4.0, but does
+                      ;; not know about newer versions as it has not been updated
+                      ;; since 2014.  Disable for later versions of Rails too.
+                      (substitute* "spec/fast_gettext/vendor/string_spec.rb"
+                        (((string-append "ActiveRecord::VERSION::MAJOR == 4 and "
+                                         "ActiveRecord::VERSION::MINOR == 0"))
+                         "ActiveRecord::VERSION::MAJOR >= 4"))
+                      #t)))))
+    (native-inputs
+     `(;; For tests.
+       ("ruby-activerecord" ,ruby-activerecord)
+       ("ruby-activesupport" ,ruby-activesupport)
+       ("ruby-bump" ,ruby-bump)
+       ("ruby-forking-test-runner" ,ruby-forking-test-runner)
+       ("ruby-i18n" ,ruby-i18n)
+       ("ruby-rubocop" ,ruby-rubocop)
+       ("ruby-rspec" ,ruby-rspec)
+       ("ruby-single-cov" ,ruby-single-cov)
+       ("ruby-sqlite3" ,ruby-sqlite3)
+       ("ruby-wwtd" ,ruby-wwtd)))
+    (synopsis "Fast implementation of @code{GetText}")
+    (description
+     "This package provides an alternative implementation of the Ruby
+@code{GetText} library that is approximately 12x faster yet thread safe.")
+    ;; Some parts are covered by the Ruby license, see file headers.
+    (license (list license:expat license:ruby))))
+
 (define-public ruby-net-http-persistent
   (package
     (name "ruby-net-http-persistent")
@@ -2627,6 +2895,28 @@ objects.")
     (home-page "https://github.com/floehopper/metaclass")
     (license license:expat)))
 
+(define-public ruby-mkmf-lite
+  (package
+    (name "ruby-mkmf-lite")
+    (version "0.3.2")
+    (source (origin
+              (method url-fetch)
+              (uri (rubygems-uri "mkmf-lite" version))
+              (sha256
+               (base32
+                "0br9k6zijj1zc25n8p7f2j1mwl58nfgdknf3q13h9k156jvrir06"))))
+    (build-system ruby-build-system)
+    (propagated-inputs
+     `(("ruby-ptools" ,ruby-ptools)))
+    (synopsis "Lightweight alternative to @code{mkmf}")
+    (description
+     "@code{mkmf-lite} is a light version of Ruby's @code{mkmf.rb} designed
+for use as a library.  It does not create packages, builds, or log files of
+any kind.  Instead, it provides mixin methods that you can use in FFI or tests
+to check for the presence of header files, constants, and so on.")
+    (home-page "https://github.com/djberg96/mkmf-lite")
+    (license license:asl2.0)))
+
 (define-public ruby-mspec
   (package
     (name "ruby-mspec")
@@ -2963,62 +3253,90 @@ Ruby, but can be used for all programs.")
   (home-page "https://github.com/alexch/rerun/")
   (license license:expat)))
 
+(define-public ruby-maxitest
+  (package
+    (name "ruby-maxitest")
+    (version "3.6.0")
+    (home-page "https://github.com/grosser/maxitest")
+    (source (origin
+              ;; Pull from git because the gem does not contain tests.
+              (method git-fetch)
+              (uri (git-reference
+                    (url home-page)
+                    (commit (string-append "v" version))))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "07b3j0bv3dx5j42jlvpvl07aaxplyi6wq688y3jl8y528ww2hjz8"))))
+    (build-system ruby-build-system)
+    (arguments
+     '(#:test-target "default"
+       #:phases (modify-phases %standard-phases
+                  (replace 'replace-git-ls-files
+                    (lambda _
+                      (substitute* "maxitest.gemspec"
+                        (("`git ls-files lib/ bin/ MIT-LICENSE Readme.md`")
+                         "`find lib/ bin/ MIT-LICENSE Readme.md -type f | sort`"))
+                      #t))
+                  (add-before 'check 'remove-version-constraints
+                    (lambda _
+                      ;; Don't use specific versions of dependencies, instead
+                      ;; take whatever is available in Guix.
+                      (delete-file "Gemfile.lock")
+                      #t))
+                  (add-before 'check 'add-mtest-on-PATH
+                    (lambda _
+                      ;; Tests use 'mtest' which is not automatically added on
+                      ;; PATH.
+                      (setenv "PATH" (string-append (getcwd) "/bin:"
+                                                    (getenv "PATH")))
+                      #t)))))
+    (native-inputs
+     `(("ps" ,procps)
+       ("ruby-bump" ,ruby-bump)
+       ("ruby-byebug" ,ruby-byebug)
+       ("ruby-rspec" ,ruby-rspec)
+       ("ruby-wwtd" ,ruby-wwtd)))
+    (propagated-inputs
+     `(("ruby-minitest" ,ruby-minitest)))
+    (synopsis "Minitest with extra features")
+    (description
+     "Maxitest is a wrapper around Minitest with extra functionality such
+as timeouts, an @command{mtest} executable that can run tests by line
+number, support for interrupted tests, better backtraces, and more.")
+    (license license:expat)))
+
 (define-public ruby-mocha
   (package
     (name "ruby-mocha")
-    (version "1.1.0")
+    (version "1.11.2")
     (source (origin
               (method url-fetch)
               (uri (rubygems-uri "mocha" version))
               (sha256
                (base32
-                "107nmnngbv8lq2g7hbjpn5kplb4v2c8gs9lxrg6vs8gdbddkilzi"))))
+                "0hxmkm8qxd04vwj8mqnpyrf2dwy7g1k9zipdfhl4y71cw7ijm9n4"))))
     (build-system ruby-build-system)
     (arguments
      `(#:phases
        (modify-phases %standard-phases
-         (add-after 'unpack 'add-test-unit-to-search-path
-          (lambda* (#:key inputs #:allow-other-keys)
-            (let* ((test-unit (assoc-ref inputs "ruby-test-unit")))
-              (substitute* "Rakefile"
-                (("t\\.libs << 'test'" line)
-                 (string-append line "; t.libs << \""
-                                test-unit "/lib/ruby/vendor_ruby"
-                                "/gems/test-unit-"
-                                ,(package-version ruby-test-unit)
-                                "/lib\""))))
-            #t))
-         (add-before 'check 'use-latest-redcarpet
-          (lambda _
-            (substitute* "mocha.gemspec"
-              (("<redcarpet>.freeze, \\[\"~> 1\"\\]")
-               "<redcarpet>.freeze, [\">= 3\"]"))
-            #t))
-         (add-before 'check 'hardcode-version
-          (lambda _
-            ;; Mocha is undefined at build time
-            (substitute* "Rakefile"
-              (("#\\{Mocha::VERSION\\}") ,version))
-            #t))
-         (add-before 'check 'remove-failing-test
-          ;; FIXME: This test fails for reasons unrelated to Guix packaging.
-          (lambda _
-            (delete-file "test/acceptance/stubbing_nil_test.rb")
-            #t)))))
-    (propagated-inputs
-     `(("ruby-metaclass" ,ruby-metaclass)))
+         (add-before 'check 'remove-rubocop-dependency
+           (lambda _
+             ;; Disable dependency on Rubocop, which is just a linter,
+             ;; and would introduce a circular dependency.
+             (substitute* "mocha.gemspec"
+               ((".*rubocop.*")
+                "true\n"))
+             #t)))))
     (native-inputs
-     `(("bundler" ,bundler)
-       ("ruby-yard" ,ruby-yard)
-       ("ruby-introspection" ,ruby-introspection)
-       ("ruby-test-unit" ,ruby-test-unit)
-       ("ruby-redcarpet" ,ruby-redcarpet)))
+     `(("ruby-introspection" ,ruby-introspection)))
     (synopsis "Mocking and stubbing library for Ruby")
     (description
      "Mocha is a mocking and stubbing library with JMock/SchMock syntax, which
 allows mocking and stubbing of methods on real (non-mock) classes.")
     (home-page "http://gofreerange.com/mocha/docs")
-    (license license:expat)))
+    ;; Mocha can be used with either license at the users choice.
+    (license (list license:expat license:ruby))))
 
 (define-public ruby-mocha-on-bacon
   (package
@@ -3478,6 +3796,28 @@ URIs using the normal URI.parse method.")
     (home-page "https://github.com/dball/data_uri")
     (license license:expat)))
 
+(define-public ruby-deep-merge
+  (package
+    (name "ruby-deep-merge")
+    (version "1.2.1")
+    (home-page "https://github.com/danielsdeleo/deep_merge")
+    ;; The Rubygem source does not contain the gemspec required for tests.
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference (url home-page) (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0c9rk23ilhc0n4489y6lda2wzphpzh6ish6fahlbpjhxn82wb931"))))
+    (build-system ruby-build-system)
+    (native-inputs
+     `(("ruby-minitest" ,ruby-minitest)))
+    (synopsis "Recursively merge hashes")
+    (description
+     "Deep Merge is a set of utility functions for @code{Hash}.  It permits
+you to merge elements inside a hash together recursively.")
+    (license license:expat)))
+
 (define-public ruby-git
   (package
     (name "ruby-git")
@@ -3514,6 +3854,38 @@ and manipulate Git repositories by wrapping system calls to the git binary.")
     (home-page "https://github.com/schacon/ruby-git")
     (license license:expat)))
 
+(define-public ruby-hocon
+  (package
+    (name "ruby-hocon")
+    (version "1.3.1")
+    (home-page "https://github.com/puppetlabs/ruby-hocon")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference (url home-page) (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "172hh2zr0n9nnszv0qvlgwszgkrq84yahrg053m68asy79zpmbqr"))))
+    (build-system ruby-build-system)
+    (arguments
+     '(#:phases (modify-phases %standard-phases
+                  (replace 'check
+                    (lambda* (#:key tests? #:allow-other-keys)
+                      (if tests?
+                          (invoke "rspec")
+                          (format #t "test suite not run~%"))
+                      #t)))))
+    (native-inputs
+     `(("bundler" ,bundler)
+       ("ruby-rspec" ,ruby-rspec)))
+    (synopsis "HOCON config library")
+    (description
+     "This package provides Ruby support for the @acronym{HOCON,
+Human-Optimized Config Object Notation} configuration file format.  It
+supports parsing and modifying HOCON and JSON files, and rendering parsed
+objects back to a @code{String}.")
+    (license license:asl2.0)))
+
 (define-public ruby-slop
   (package
     (name "ruby-slop")
@@ -3753,13 +4125,13 @@ to reproduce user environments.")
 (define-public ruby-nokogiri
   (package
     (name "ruby-nokogiri")
-    (version "1.10.5")
+    (version "1.10.9")
     (source (origin
               (method url-fetch)
               (uri (rubygems-uri "nokogiri" version))
               (sha256
                (base32
-                "185g3dwba73jqxjr94bd2zk6fil6n9hmcfnfyzh3p1w47vm296r7"))))
+                "12j76d0bp608932xkzmfi638c7aqah57l437q8494znzbj610qnm"))))
     (build-system ruby-build-system)
     (arguments
      ;; Tests fail because Nokogiri can only test with an installed extension,
@@ -3843,6 +4215,70 @@ for select languages.")
     (home-page "http://coderay.rubychan.de")
     (license license:expat)))
 
+(define-public ruby-parallel-tests
+  (package
+    (name "ruby-parallel-tests")
+    (version "2.32.0")
+    (home-page "https://github.com/grosser/parallel_tests")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                    (url home-page)
+                    (commit (string-append "v" version))))
+              (file-name (string-append name version))
+              (sha256
+               (base32
+                "0l2rjz9fnxv7hvz679v7a75mghsh9x9qpvbyapiavqsx21v42l7m"))))
+    (build-system ruby-build-system)
+    (arguments
+     '(#:test-target "default"
+       #:phases (modify-phases %standard-phases
+                  (add-after 'patch-source-shebangs 'patch-shell-invokations
+                    (lambda _
+                      (substitute* '("lib/parallel_tests/tasks.rb"
+                                     "spec/parallel_tests/tasks_spec.rb")
+                        (("/bin/sh") (which "sh"))
+                        (("/bin/bash") (which "bash")))
+                      #t))
+                  (add-before 'check 'remove-version-constraints
+                    (lambda _
+                      ;; Remove hard coded version constraints, instead just
+                      ;; use whatever versions are available in Guix.
+                      (delete-file "Gemfile.lock")
+                      (substitute* "Gemfile"
+                        (("'minitest',.*")
+                         "'minitest'\n")
+                        (("'cucumber',.*")
+                         "'cucumber'\n"))
+                      #t))
+                  (add-before 'check 'disable-rails-test
+                    (lambda _
+                      ;; XXX: This test attempts to download and run the test
+                      ;; suites of multiple Rails versions(!) directly.
+                      (delete-file "spec/rails_spec.rb")
+                      #t))
+                  (add-before 'check 'set-HOME
+                    (lambda _
+                      ;; Some tests check the output of Bundler, and fail when
+                      ;; Bundler warns that /homeless-shelter does not exist.
+                      (setenv "HOME" "/tmp")
+                      #t)))))
+    (native-inputs
+     `(("ruby-bump" ,ruby-bump)
+       ("ruby-cucumber" ,ruby-cucumber)
+       ("ruby-minitest" ,ruby-minitest)
+       ("ruby-rake" ,ruby-rake)
+       ("ruby-rspec" ,ruby-rspec)
+       ("ruby-spinach" ,ruby-spinach)))
+    (propagated-inputs
+     `(("ruby-parallel" ,ruby-parallel)))
+    (synopsis "Run tests in parallel")
+    (description
+     "This package can speed up @code{Test::Unit}, @code{RSpec},
+@code{Cucumber}, and @code{Spinach} tests by running them concurrently
+across multiple CPU cores.")
+    (license license:expat)))
+
 (define-public ruby-parser
   (package
     (name "ruby-parser")
@@ -3870,6 +4306,54 @@ for select languages.")
     (home-page "https://github.com/whitequark/parser")
     (license license:expat)))
 
+(define-public ruby-sexp-processor
+  (package
+    (name "ruby-sexp-processor")
+    (version "4.15.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (rubygems-uri "sexp_processor" version))
+       (sha256
+        (base32
+         "0d1vks77xnd0m3s94a58f9bkdwlaml5qdkmprx279m2s0pc2gv55"))))
+    (build-system ruby-build-system)
+    (native-inputs
+     ;; TODO: Add ruby-minitest-proveit once available.
+     `(("hoe" ,ruby-hoe)))
+    (synopsis "ParseTree fork which includes generic S-exp processing tools")
+    (description "The sexp_processor package is derived from ParseTree, but
+contrary to ParseTree, it includes all the generic S-exp processing tools.
+Amongst the included tools are @code{Sexp}, @code{SexpProcessor} and
+@code{Environment}")
+    (home-page "https://github.com/seattlerb/sexp_processor")
+    (license license:expat)))
+
+(define-public ruby-ruby-parser
+  (package
+    (name "ruby-ruby-parser")
+    (version "3.14.2")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (rubygems-uri "ruby_parser" version))
+       (sha256
+        (base32
+         "09qcdyjjw3p7g6cjm5m9swkms1xnv35ndiy7yw24cas16qrhha6c"))))
+    (build-system ruby-build-system)
+    (native-inputs
+     `(("hoe" ,ruby-hoe)
+       ("racc" ,ruby-racc)
+       ("unifdef" ,unifdef)))
+    (propagated-inputs
+     `(("ruby-sexp-processor" ,ruby-sexp-processor)))
+    (home-page "https://github.com/seattlerb/ruby_parser/")
+    (synopsis "Ruby parser written in pure Ruby")
+    (description "The ruby_parser (RP) package provides a Ruby parser written
+in pure Ruby.  It outputs S-expressions which can be manipulated and converted
+back to Ruby via the @code{ruby2ruby} library.")
+    (license license:expat)))
+
 (define-public ruby-prawn-manual-builder
   (package
     (name "ruby-prawn-manual-builder")
@@ -3999,6 +4483,61 @@ invocation, and source and documentation browsing.")
     (home-page "https://pryrepl.org")
     (license license:expat)))
 
+(define-public ruby-single-cov
+  (package
+    (name "ruby-single-cov")
+    (version "1.3.2")
+    (home-page "https://github.com/grosser/single_cov")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference (url home-page)
+                                  (commit (string-append "v" version))))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "05qdzpcai1p23a120gb9bxkfl4y73k9hicx34ch2lsk31lgi9bl7"))))
+    (build-system ruby-build-system)
+    (arguments
+     '(#:test-target "default"
+       #:phases (modify-phases %standard-phases
+                  (replace 'replace-git-ls-files
+                    (lambda _
+                      (substitute* "single_cov.gemspec"
+                        (("`git ls-files lib/ bin/ MIT-LICENSE`")
+                         "`find lib/ bin/ MIT-LICENSE -type f | sort`"))
+                      #t))
+                  (add-before 'check 'remove-version-constraints
+                    (lambda _
+                      (delete-file "Gemfile.lock")
+                      #t))
+                  (add-before 'check 'make-files-writable
+                    (lambda _
+                      ;; Tests need to create local directories and open files
+                      ;; with write permissions.
+                      (for-each make-file-writable
+                                (find-files "specs" #:directories? #t))
+                      #t))
+                  (add-before 'check 'disable-failing-test
+                    (lambda _
+                      ;; XXX: This test copies assets from minitest, but can
+                      ;; not cope with the files being read-only.  Just skip
+                      ;; it for now.
+                      (substitute* "specs/single_cov_spec.rb"
+                        (("it \"complains when coverage is bad\"")
+                         "xit \"complains when coverage is bad\""))
+                      #t)))))
+    (native-inputs
+     `(("ruby-bump" ,ruby-bump)
+       ("ruby-minitest" ,ruby-minitest)
+       ("ruby-rspec" ,ruby-rspec)
+       ("ruby-simplecov" ,ruby-simplecov)))
+    (synopsis "Code coverage reporting tool")
+    (description
+     "This package provides actionable code coverage reports for Ruby
+projects.  It has very little overhead and can be easily integrated with
+development tools to catch coverage problems early.")
+    (license license:expat)))
+
 (define-public ruby-guard
   (package
     (name "ruby-guard")
@@ -4048,6 +4587,34 @@ file or directories are modified.")
     (home-page "https://guardgem.org/")
     (license license:expat)))
 
+(define-public ruby-spinach
+  (package
+    (name "ruby-spinach")
+    (version "0.11.0")
+    (home-page "http://github.com/codegram/spinach")
+    (source (origin
+              (method url-fetch)
+              (uri (rubygems-uri "spinach" version))
+              (sha256
+               (base32
+                "1mv053mqz9c8ngqa6wp1ymk2fax6j0yqzax6918akrdr7c3fx3c6"))))
+    (build-system ruby-build-system)
+    (arguments
+       ;; FIXME: Disable tests altogether because they depend on 'capybara'
+       ;; which in turn depends on many other unpackaged gems.  Enable once
+       ;; capybara is available.
+       '(#:tests? #f))
+    (propagated-inputs
+     `(("ruby-colorize" ,ruby-colorize)
+       ("ruby-gherkin-ruby" ,ruby-gherkin-ruby)
+       ("ruby-json" ,ruby-json)))
+    (synopsis "Gherkin-based BDD framework")
+    (description
+     "Spinach is a high-level @acronym{BDD, Behavior-driven development}
+framework that leverages the expressive @code{Gherkin} language to help you
+define executable specifications of your code.")
+    (license license:expat)))
+
 (define-public ruby-tilt
   (package
     (name "ruby-tilt")
@@ -4752,117 +5319,82 @@ multibyte strings, internationalization, time zones, and testing.")
 (define-public ruby-crass
   (package
     (name "ruby-crass")
-    (version "1.0.4")
+    (version "1.0.6")
+    (home-page "https://github.com/rgrove/crass")
     (source (origin
-              (method url-fetch)
-              (uri (rubygems-uri "crass" version))
+              ;; The gem does not contain tests, so pull from git.
+              (method git-fetch)
+              (uri (git-reference
+                    (url home-page)
+                    (commit (string-append "v" version))))
+              (file-name (git-file-name name version))
               (sha256
                (base32
-                "0bpxzy6gjw9ggjynlxschbfsgmx8lv3zw1azkjvnb8b9i895dqfi"))))
+                "1gbsb81psgb6xhnwpx4s409jc0mk0gijh039sy5xyi8jpaaadp40"))))
     (build-system ruby-build-system)
-    (native-inputs
-     `(("bundler" ,bundler)
-       ("ruby-minitest" ,ruby-minitest)))
     (synopsis "Pure Ruby CSS parser")
     (description
      "Crass is a pure Ruby CSS parser based on the CSS Syntax Level 3 spec.")
-    (home-page "https://github.com/rgrove/crass/")
     (license license:expat)))
 
 (define-public ruby-nokogumbo
-  (let ((commit "fb51ff299a1c34346837580b6d1d9a60fadf5dbd"))
-    (package
-      (name "ruby-nokogumbo")
-      (version (string-append "1.4.7-1." (string-take commit 8)))
-      (source (origin
-                ;; We use the git reference, because there's no Rakefile in the
-                ;; published gem and the tarball on Github is outdated.
-                (method git-fetch)
-                (uri (git-reference
-                      (url "https://github.com/rubys/nokogumbo.git")
-                      (commit "d56f954d20a")))
-                (file-name (string-append name "-" version "-checkout"))
-                (sha256
-                 (base32
-                  "0bnppjy96xiadrsrc9dp8y6wvdwnkfa930n7acrp0mqm4qywl2wl"))))
-      (build-system ruby-build-system)
-      (arguments
-       `(#:modules ((guix build ruby-build-system)
-                    (guix build utils)
-                    (ice-9 rdelim))
-         #:phases
-         (modify-phases %standard-phases
-           (add-after 'unpack 'build-gemspec
-            (lambda _
-              (substitute* "Rakefile"
-                ;; Build Makefile even without a copy of gumbo-parser sources
-                (("'gumbo-parser/src',") "")
-                ;; We don't bundle gumbo-parser sources
-                (("'gumbo-parser/src/\\*',") "")
-                (("'gumbo-parser/visualc/include/\\*',") "")
-                ;; The definition of SOURCES will be cut in gemspec, and
-                ;; "FileList" will be undefined.
-                (("SOURCES \\+ FileList\\[")
-                 "['ext/nokogumboc/extconf.rb', 'ext/nokogumboc/nokogumbo.c', "))
-
-              ;; Copy the Rakefile and cut out the gemspec.
-              (copy-file "Rakefile" ".gemspec")
-              (with-atomic-file-replacement ".gemspec"
-                (lambda (in out)
-                  (let loop ((line (read-line in 'concat))
-                             (skipping? #t))
-                    (if (eof-object? line)
-                        #t
-                        (let ((skip-next? (if skipping?
-                                              (not (string-prefix? "SPEC =" line))
-                                              (string-prefix? "end" line))))
-                          (when (or (not skipping?)
-                                    (and skipping? (not skip-next?)))
-                                (format #t "~a" line)
-                                (display line out))
-                          (loop (read-line in 'concat) skip-next?))))))
-              #t)))))
-      (inputs
-       `(("gumbo-parser" ,gumbo-parser)))
-      (propagated-inputs
-       `(("ruby-nokogiri" ,ruby-nokogiri)))
-      (synopsis "Ruby bindings to the Gumbo HTML5 parser")
-      (description
-       "Nokogumbo allows a Ruby program to invoke the Gumbo HTML5 parser and
+  (package
+    (name "ruby-nokogumbo")
+    (version "2.0.2")
+    (source (origin
+              ;; We use the git reference, because there's no Rakefile in the
+              ;; published gem and the tarball on Github is outdated.
+              (method git-fetch)
+              (uri (git-reference
+                    (url "https://github.com/rubys/nokogumbo.git")
+                    (commit (string-append "v" version))))
+              (file-name (string-append name "-" version "-checkout"))
+              (sha256
+               (base32
+                "1qg0iyw450lw6d0j1ghzg79a6l60nm1m4qmrzwzybi585861jxcx"))))
+    (build-system ruby-build-system)
+    (native-inputs
+     `(("ruby-rake-compiler" ,ruby-rake-compiler)))
+    (inputs
+     `(("gumbo-parser" ,gumbo-parser)))
+    (propagated-inputs
+     `(("ruby-nokogiri" ,ruby-nokogiri)))
+    (synopsis "Ruby bindings to the Gumbo HTML5 parser")
+    (description
+     "Nokogumbo allows a Ruby program to invoke the Gumbo HTML5 parser and
 access the result as a Nokogiri parsed document.")
-      (home-page "https://github.com/rubys/nokogumbo/")
-      (license license:asl2.0))))
+    (home-page "https://github.com/rubys/nokogumbo/")
+    (license license:asl2.0)))
 
 (define-public ruby-sanitize
   (package
     (name "ruby-sanitize")
-    (version "4.6.3")
+    (version "5.1.0")
+    (home-page "https://github.com/rgrove/sanitize")
     (source (origin
-              (method url-fetch)
+              (method git-fetch)
               ;; The gem does not include the Rakefile, so we download the
-              ;; release tarball from Github.
-              (uri (string-append "https://github.com/rgrove/"
-                                  "sanitize/archive/v" version ".tar.gz"))
-              (file-name (string-append name "-" version ".tar.gz"))
+              ;; source from Github.
+              (uri (git-reference
+                    (url home-page)
+                    (commit (string-append "v" version))))
+              (file-name (git-file-name name version))
+              (patches (search-patches "ruby-sanitize-system-libxml.patch"))
               (sha256
                (base32
-                "1fmqppwif3cm8h79006jfzkdnlxxzlry9kzk03psk0d5xpg55ycc"))))
+                "0lj0q9yhjp0q0in5majkshnki07mw8m2vxgndx4m5na6232aszl0"))))
     (build-system ruby-build-system)
     (propagated-inputs
      `(("ruby-crass" ,ruby-crass)
        ("ruby-nokogiri" ,ruby-nokogiri)
        ("ruby-nokogumbo" ,ruby-nokogumbo)))
     (native-inputs
-     `(("bundler" ,bundler)
-       ("ruby-minitest" ,ruby-minitest)
-       ("ruby-redcarpet" ,ruby-redcarpet)
-       ("ruby-yard" ,ruby-yard)))
+     `(("ruby-minitest" ,ruby-minitest)))
     (synopsis "Whitelist-based HTML and CSS sanitizer")
     (description
      "Sanitize is a whitelist-based HTML and CSS sanitizer.  Given a list of
 acceptable elements, attributes, and CSS properties, Sanitize will remove all
 unacceptable HTML and/or CSS from a string.")
-    (home-page "https://github.com/rgrove/sanitize/")
     (license license:expat)))
 
 (define-public ruby-oj
@@ -5470,6 +6002,25 @@ Ruby classes.")
     (home-page "https://ms-ati.github.io/docile/")
     (license license:expat)))
 
+(define-public ruby-middleware
+  (package
+    (name "ruby-middleware")
+    (version "0.1.0")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (rubygems-uri "middleware" version))
+       (sha256
+        (base32
+         "0703nkf2v371wqr41c04x5qid7ww45cxqv3hnlg07if3b3xrm9xl"))))
+    (build-system ruby-build-system)
+    (arguments '(#:tests? #f))          ;no test suite
+    (synopsis "Implementation of a middleware abstraction for Ruby")
+    (description "Middleware is a generalized implementation of a middleware
+abstraction for Ruby.")
+    (home-page "https://github.com/mitchellh/middleware")
+    (license license:expat)))
+
 (define-public ruby-gherkin
   (package
     (name "ruby-gherkin")
@@ -5493,6 +6044,25 @@ It is intended be used by all Cucumber implementations to parse
     (home-page "https://github.com/cucumber-attic/gherkin")
     (license license:expat)))
 
+(define-public ruby-gherkin-ruby
+  (package
+    (name "ruby-gherkin-ruby")
+    (version "0.3.2")
+    (home-page "http://github.com/codegram/gherkin-ruby")
+    (source (origin
+              (method url-fetch)
+              (uri (rubygems-uri "gherkin-ruby" version))
+              (sha256
+               (base32
+                "18ay7yiibf4sl9n94k7mbi4k5zj2igl4j71qcmkswv69znyx0sn1"))))
+    (build-system ruby-build-system)
+    (synopsis "Pure Ruby Gherkin parser")
+    (description
+     "Gherkin-ruby is a Gherkin parser written in pure Ruby and less than
+200 lines of code.")
+    ;; XXX: No license information anywhere but Readme.md.
+    (license license:expat)))
+
 (define-public ruby-aruba
   (package
     (name "ruby-aruba")
@@ -7618,6 +8188,36 @@ is part of Ruby's standard library.  It more closely conforms to RFC 3986,
 RFC 3987, and RFC 6570 (level 4), providing support for IRIs and URI templates.")
     (license license:asl2.0)))
 
+(define-public ruby-colorize
+  (package
+    (name "ruby-colorize")
+    (version "0.8.1")
+    (source (origin
+              (method url-fetch)
+              (uri (rubygems-uri "colorize" version))
+              (sha256
+               (base32
+                "133rqj85n400qk6g3dhf2bmfws34mak1wqihvh3bgy9jhajw580b"))))
+    (build-system ruby-build-system)
+    (arguments
+     '(#:phases (modify-phases %standard-phases
+                  (add-before 'check 'remove-codeclimate-dependency
+                    (lambda _
+                      (substitute* "test/test_colorize.rb"
+                        ;; Do not hook the tests into the online CodeClimate
+                        ;; service which is unnecessary for these tests.
+                        (("require 'codeclimate-test-reporter'")
+                         "")
+                        (("CodeClimate.*") ""))
+                      #t)))))
+    (synopsis "Add color effects to the @code{String} class")
+    (description
+     "This package extends the @code{String} class and adds a
+@code{ColorizedString} with methods to set text color, background color,
+and text effects.")
+    (home-page "http://github.com/fazibear/colorize")
+    (license license:gpl2+)))
+
 (define-public ruby-colorator
   (package
     (name "ruby-colorator")
@@ -8808,6 +9408,35 @@ the Thin library.")
     (home-page "https://github.com/sj26/skinny")
     (license license:expat)))
 
+(define-public ruby-sys-filesystem
+  (package
+    (name "ruby-sys-filesystem")
+    (version "1.3.4")
+    (source (origin
+              (method url-fetch)
+              (uri (rubygems-uri "sys-filesystem" version))
+              (sha256
+               (base32
+                "0mizqnsiagagmracadr16s5na2ks2j3ih1w0f3gp4ssrda6szl01"))))
+    (build-system ruby-build-system)
+    (arguments
+     '(#:phases (modify-phases %standard-phases
+                  (add-before 'check 'set-HOME
+                    (lambda _
+                      ;; Some tests attempt to stat $HOME.  Let them.
+                      (setenv "HOME" "/tmp")
+                      #t)))))
+    (propagated-inputs
+     `(("ruby-ffi" ,ruby-ffi)))
+    (native-inputs
+     `(("ruby-mkmf-lite" ,ruby-mkmf-lite)))
+    (synopsis "Gather file system information")
+    (description
+     "The @code{sys-filesystem} library provides a cross-platform interface
+for gathering file system information, such as disk space and mount points.")
+    (home-page "https://github.com/djberg96/sys-filesystem")
+    (license license:asl2.0)))
+
 (define-public mailcatcher
   (package
     (name "mailcatcher")
@@ -9072,3 +9701,55 @@ which snapshots to consider and what files to include.")
     (home-page
      "https://github.com/hartator/wayback-machine-downloader")
     (license license:expat)))
+
+(define-public ruby-wwtd
+  (package
+    (name "ruby-wwtd")
+    (version "1.4.1")
+    (home-page "http://github.com/grosser/wwtd")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                    (url home-page)
+                    (commit (string-append "v" version))))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0gw7vfnbb41cy67yw82zji3jkhfsgmzcgzaszm99ax77y18wclf2"))
+              (modules '((guix build utils)))
+              (snippet
+               '(begin
+                  ;; Remove bundled library.
+                  (delete-file "spec/rake-12.3.0.gem")
+                  #t))))
+    (build-system ruby-build-system)
+    (arguments
+     '(;; XXX: Tests need multiple versions of ruby, wants to run
+       ;; `bundle install`, etc.
+       #:tests? #f
+       #:phases (modify-phases %standard-phases
+                  (replace 'replace-git-ls-files
+                    (lambda _
+                      (substitute* "wwtd.gemspec"
+                        (("git ls-files lib/ bin/`")
+                         "find lib/ bin/ -type f |sort`"))
+                      #t))
+                  (add-before 'check 'remove-version-constraints
+                    (lambda _
+                      (delete-file "Gemfile.lock")
+                      #t))
+                  (replace 'check
+                    (lambda* (#:key tests? #:allow-other-keys)
+                      (if tests?
+                          (invoke "rspec" "spec/")
+                          (format #t "test suite not run~%"))
+                      #t)))))
+    (native-inputs
+     `(("ruby-bump" ,ruby-bump)
+       ("ruby-rspec" ,ruby-rspec)))
+    (synopsis "Run @file{.travis.yml} files locally")
+    (description
+     "WWTD is a @dfn{Travis Simulator} that lets you run test matrices
+defined in @file{.travis.yml} on your local machine, using @code{rvm},
+@code{rbenv}, or @code{chruby} to test different versions of Ruby.")
+    (license license:expat)))