<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ruby &#8211; CS@Worcester</title>
	<atom:link href="https://cs.worcester.edu/category/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>https://cs.worcester.edu</link>
	<description>Worcester State University Computer Science Department</description>
	<lastBuildDate>Sun, 30 Aug 2015 19:00:00 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>
<site xmlns="com-wordpress:feed-additions:1">236835116</site>	<item>
		<title>Ruby on Guix</title>
		<link>http://dthompson.us/ruby-on-guix.html</link>
		
		<dc:creator><![CDATA[David Thompson]]></dc:creator>
		<pubDate>Sun, 30 Aug 2015 19:00:00 +0000</pubDate>
				<category><![CDATA[gnu]]></category>
		<category><![CDATA[guile]]></category>
		<category><![CDATA[guix]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[scheme]]></category>
		<category><![CDATA[WSU]]></category>
		<guid isPermaLink="false">http://cs.worcester.edu/blog/?guid=cd8a17791ee842681e7b97c007621b14</guid>

					<description><![CDATA[<p>I've been working with Ruby professionally for over 3 years now and
I've grown frustrated with two of its most popular development tools:
RVM and Bundler.  For those that may not know, RVM is the Ruby version
manager and it allows unprivileged users to download, compile,
install, and manage many versions of Ruby instead of being stuck with
the one that is installed globally by your distro's package manager.
Bundler is the tool that allows developers to keep a version
controlled "Gemfile" that specifies all of the project's dependencies
and provides utilities to install and update those gems.  These tools
are crucial because Ruby developers often work with many applications
that use different versions of Ruby and/or different versions of gems
such as Rails.  Traditional GNU/Linux distributions install packages
to the global <tt>/usr</tt> directory, limiting users to a single version
of Ruby and associated gems, if they are packaged at all.  Traditional
package management fails to meet the needs of a lot of users, so many
niche package managers have been developed to supplement them.</p>
<p>Taking a step back, it becomes apparent that dependency isolation is a
general problem that isn't confined to software written in Ruby: Node
has npm and nvm, Python has pip and virtualenv, and so on.  A big
limitation of all these language-specific package managers is that
they cannot control what is outside of their language domain.  In
order to use RVM to successfully compile a version of Ruby, you need
to make sure you have the GCC toolchain, OpenSSL, readline, libffi,
etc. installed using the system package manager (note: I've seen RVM
try to build prerequisites like OpenSSL before, which I then disabled
to avoid duplication and security issues and I recommend you do the
same.)  In order to use Bundler to install Nokogiri, you need to make
sure libxml2 has been installed using the system package manager.  If
you work with more than a single language, the number of different
package management tools needed to get work done is staggering.  For
web applications, it's not uncommon to use RVM, Bundler, NPM, Bower,
and the system package manager simultaneously to get all of the
necessary programs and libraries.  Large web applications are
notoriously difficult to deploy, and companies hire a bunch of
operations folk like me to try to wrangle it all.</p>
<p>Anyway, let's forget about Node, Python, etc. and just focus on Ruby.
Have you or someone you work with encountered hard to debug issues and
Git merge conflicts due to a problem with <tt>Gemfile.lock</tt>?  Bundler's
fast and loose versioning in the <tt>Gemfile</tt> (e.g. <tt>rails &#62;= 4.0</tt>)
causes headaches when different users update different gems at
different times and check the resulting auto-generated
<tt>Gemfile.lock</tt> into the repository.  Have you ever been frustrated
that it's difficult to deduplicate gems that are shared between
multiple bundled gem sets?  Have you looked at the <a href="https://rvm.io/">RVM home page</a>
and been frustrated that they recommend you to <tt>curl &#124; bash</tt> to
install their software?  Have you been annoyed by RVM's strange system
of overriding shell built-ins in order to work its magic?  I'm not
sure how you feel, dear reader, but my Ruby environments feel like one
giant, brittle hack, and I'm often enough involved in fixing issues
with them on my own workstation, that of my colleagues, and on
production servers.</p>
<p>So, if you're still with me, what do we do about this?  How can we
work to improve upon the status quo?  Just use Docker?  Docker is
helpful, and certainly much better than no isolation at all, but it
hides the flaws of package management inside an opaque disk image and
restricts the environments in which your application is built to
function.  The general problem of dependency isolation is orthogonal
to the runtime environment, be it container, virtual machine, or "bare
metal."  Enter functional package management.  What does it mean for a
package manager to be functional?  GNU Guix, the functional package
manager that I contribute to and recommend, has this to say:</p>
<blockquote>
<p>GNU Guix is a functional package management tool for the GNU
system.  Package management consists of all activities that relate
to building packages from sources, honoring their build-time and
run-time dependencies, installing packages in user environments,
upgrading installed packages to new versions or rolling back to a
previous set, removing unused software packages, etc.</p>
<p>The term functional refers to a specific package management
discipline.  In Guix, the package build and installation process
is seen as a function, in the mathematical sense.  That function
takes inputs, such as build scripts, a compiler, and libraries,
and returns an installed package.</p>
</blockquote>
<p>Guix has a rich set of features, some of which you may find in other
package managers, but not all of them (unless you use another
functional package manager such as Nix.)  Gem/Bundler can do
unprivileged gem installation, but it cannot do transactional upgrades
and rollbacks or install non-Ruby dependencies.  Dpkg/yum/pacman can
install all build-time and rumtime dependencies, but it cannot do
unprivileged package installation to isolated user environments.  And
none of them can precisely describe the <em>full</em> dependency graph (all
the way down to the C compiler's compiler) but <em>Guix can</em>.</p>
<p>Guix is written in Guile, an implementation of the Scheme programming
language.  The upcoming release of Guix will feature a Ruby build
system that captures the process of installing gems from <tt>.gem</tt>
archives and a RubyGems import utility to make it easier to write Guix
packages by using the metadata available on <a href="https://rubygems.org/">https://rubygems.org</a>.
Ruby developers interested in functional package management are
encouraged to try packaging their gems (and dependencies) for Guix.</p>
<p>Now, how exactly can Guix replace RVM and Bundler?  Guix uses an
abstraction called a "profile" that represents a user-defined set of
packages that should work together.  Think of it as having many
<tt>/usr</tt> file system trees that can be used in isolation from the
others (without invoking virtualization technologies such as virtual
machines or containers.)  To install multiple versions of Ruby and
various gems, the user need only create a separate profile for them:</p>
<div><pre>guix package --profile=project-1 --install ruby-2.2 ruby-rspec-3
# Hypothetical packages:
guix package --profile=project-2 --install ruby-1.9 ruby-rspec-2
</pre></div>
<p>A profile is a "symlink forest" that is the union of all the packages
it includes, and files are deduplicated among all of them.  To
actually use the profile, the relevant environment variables must be
configured.  Guix is aware of such variables, and can tell you what to
set by running the following:</p>
<div><pre>guix package --search-paths --profile=project-1
</pre></div>
<p>Additionally, you can also create ad-hoc development environments with
the <tt>guix environment</tt> tool.  This tool will spawn a sub-shell (or
another program of your choice) in an environment in which a set of
specified packages are available.  This is my preferred method as it
automagically sets all of the environment variables for me and Guix is
free to garbage collect the packages when I close the sub-shell:</p>
<div><pre># Launch a Ruby REPL with ActiveSupport available.
guix environment --ad-hoc ruby ruby-activesupport -E irb
</pre></div>
<p>In order to make this environment reproducible for others, I recommend
keeping a <tt>package.scm</tt> file in version control that describes the
complete dependency graph for your project, as well as metadata such
as the license, version, and description:</p>
<div><pre><span>(</span><span>use-modules</span> <span>(</span><span>guix</span> <span>packages</span><span>)</span>
             <span>(</span><span>guix</span> <span>licenses</span><span>)</span>
             <span>(</span><span>guix</span> <span>build-system</span> <span>ruby</span><span>)</span>
             <span>(</span><span>gnu</span> <span>packages</span><span>)</span>
             <span>(</span><span>gnu</span> <span>packages</span> <span>version-control</span><span>)</span>
             <span>(</span><span>gnu</span> <span>packages</span> <span>ssh</span><span>)</span>
             <span>(</span><span>gnu</span> <span>packages</span> <span>ruby</span><span>))</span>

<span>(</span><span>package</span>
  <span>(</span><span>name</span> <span>"cool-ruby-project"</span><span>)</span>
  <span>(</span><span>version</span> <span>"1.0"</span><span>)</span>
  <span>(</span><span>source</span> <span>#f</span><span>)</span> <span>; not needed just to create dev environment</span>
  <span>(</span><span>build-system</span> <span>ruby-build-system</span><span>)</span>
  <span>;; These correspond roughly to "development" dependencies.</span>
  <span>(</span><span>native-inputs</span>
   <span>`</span><span>((</span><span>"git"</span> <span>,</span><span>git</span><span>)</span>
     <span>(</span><span>"openssh"</span> <span>,</span><span>openssh</span><span>)</span>
     <span>(</span><span>"ruby-rspec"</span> <span>,</span><span>ruby-rspec</span><span>)))</span>
  <span>(</span><span>propagated-inputs</span>
   <span>`</span><span>((</span><span>"ruby-pg"</span> <span>,</span><span>ruby-pg</span><span>)</span>
     <span>(</span><span>"ruby-nokogiri"</span> <span>,</span><span>ruby-nokogiri</span><span>)</span>
     <span>(</span><span>"ruby-i18n"</span> <span>,</span><span>ruby-i18n</span><span>)</span>
     <span>(</span><span>"ruby-rails"</span> <span>,</span><span>ruby-rails</span><span>)))</span>
  <span>(</span><span>synopsis</span> <span>"A cool Ruby project"</span><span>)</span>
  <span>(</span><span>description</span> <span>"This software does some cool stuff, trust me."</span><span>)</span>
  <span>(</span><span>home-page</span> <span>"https://example.com"</span><span>)</span>
  <span>(</span><span>license</span> <span>expat</span><span>))</span>
</pre></div>
<p>With this package file, it is simple to an instantiate a development
environment:</p>
<div><pre>guix environment -l package.scm
</pre></div>
<p>I'm not covering it in this post, but properly filling out the blank
<tt>source</tt> field above would allow for building development snapshots,
including running the test suite, in an isolated build container using
the <tt>guix build</tt> utility.  This is a very useful when composed with
a continuous integration system.  Guix itself uses <a href="https://nixos.org/hydra/">Hydra</a> as its CI
system to perform all package builds.</p>
<p>As mentioned earlier, one of the big advantages of writing Guix
package recipes is that the full dependency graph can be captured,
including non-Ruby components.  The pg gem provides a good example:</p>
<div><pre><span>(</span><span>define-public</span> <span>ruby-pg</span>
  <span>(</span><span>package</span>
    <span>(</span><span>name</span> <span>"ruby-pg"</span><span>)</span>
    <span>(</span><span>version</span> <span>"0.18.2"</span><span>)</span>
    <span>(</span><span>source</span>
     <span>(</span><span>origin</span>
       <span>(</span><span>method</span> <span>url-fetch</span><span>)</span>
       <span>(</span><span>uri</span> <span>(</span><span>rubygems-uri</span> <span>"pg"</span> <span>version</span><span>))</span>
       <span>(</span><span>sha256</span>
        <span>(</span><span>base32</span>
         <span>"1axxbf6ij1iqi3i1r3asvjc80b0py5bz0m2wy5kdi5xkrpr82kpf"</span><span>))))</span>
    <span>(</span><span>build-system</span> <span>ruby-build-system</span><span>)</span>
    <span>(</span><span>arguments</span>
     <span>'</span><span>(</span><span>#</span><span>:test-target</span> <span>"spec"</span><span>))</span>
    <span>;; Native inputs are used only at build and test time.</span>
    <span>(</span><span>native-inputs</span>
     <span>`</span><span>((</span><span>"ruby-rake-compiler"</span> <span>,</span><span>ruby-rake-compiler</span><span>)</span>
       <span>(</span><span>"ruby-hoe"</span> <span>,</span><span>ruby-hoe</span><span>)</span>
       <span>(</span><span>"ruby-rspec"</span> <span>,</span><span>ruby-rspec</span><span>)))</span>
    <span>;; Native extension links against PostgreSQL shared library.</span>
    <span>(</span><span>inputs</span>
     <span>`</span><span>((</span><span>"postgresql"</span> <span>,</span><span>postgresql</span><span>)))</span>
    <span>(</span><span>synopsis</span> <span>"Ruby interface to PostgreSQL"</span><span>)</span>
    <span>(</span><span>description</span> <span>"Pg is the Ruby interface to the PostgreSQL RDBMS.  It works</span>
<span>with PostgreSQL 8.4 and later."</span><span>)</span>
    <span>(</span><span>home-page</span> <span>"https://bitbucket.org/ged/ruby-pg"</span><span>)</span>
    <span>(</span><span>license</span> <span>license:ruby</span><span>)))</span>
</pre></div>
<p>Note how the recipe specifies the PostgreSQL dependency.  Below is the
dependency graph for ruby-pg as produced by <tt>guix graph</tt>, excluding
the GCC compiler toolchain and other low-level tools for brevity.
Pretty neat, eh?</p>
<img alt="" src="http://dthompson.us/images/guix/ruby-pg-graph.png"><p>Given that Guix doesn't yet have many gems packaged (help wanted), it
can still be advantageous to use it for getting more up-to-date
packages than many distros provide, but in conjuction with Bundler for
fetching Ruby gems.  This gets RVM out of your hair whilst creating a
migration path away from Bundler at a later time once the required
gems have been packaged:</p>
<div><pre>cd my-project/
guix environment --ad-hoc ruby bundler libxml2 libxslt # etc.
# A small bash script can be used to make these gem sets.
mkdir .gems
export GEM_HOME=$PWD/.gems
export GEM_PATH=$GEM_HOME:$GEM_PATH
export PATH=$GEM_HOME/bin:$PATH
bundle install
</pre></div>
<p>As you've seen in the above package snippets, Guix package definitions
are typically very short and rather easy to write yourself.  The
<tt>guix import gem</tt> tool was made to lower the barrier even more by
generating most of the boilerplate code.  For example:</p>
<div><pre>guix import gem pry
</pre></div>
<p>Produces this Scheme code:</p>
<div><pre><span>(</span><span>package</span>
  <span>(</span><span>name</span> <span>"ruby-pry"</span><span>)</span>
  <span>(</span><span>version</span> <span>"0.10.1"</span><span>)</span>
  <span>(</span><span>source</span>
    <span>(</span><span>origin</span>
      <span>(</span><span>method</span> <span>url-fetch</span><span>)</span>
      <span>(</span><span>uri</span> <span>(</span><span>rubygems-uri</span> <span>"pry"</span> <span>version</span><span>))</span>
      <span>(</span><span>sha256</span>
        <span>(</span><span>base32</span>
          <span>"1j0r5fm0wvdwzbh6d6apnp7c0n150hpm9zxpm5xvcgfqr36jaj8z"</span><span>))))</span>
  <span>(</span><span>build-system</span> <span>ruby-build-system</span><span>)</span>
  <span>(</span><span>propagated-inputs</span>
    <span>`</span><span>((</span><span>"ruby-coderay"</span> <span>,</span><span>ruby-coderay</span><span>)</span>
      <span>(</span><span>"ruby-method-source"</span> <span>,</span><span>ruby-method-source</span><span>)</span>
      <span>(</span><span>"ruby-slop"</span> <span>,</span><span>ruby-slop</span><span>)))</span>
  <span>(</span><span>synopsis</span>
    <span>"An IRB alternative and runtime developer console"</span><span>)</span>
  <span>(</span><span>description</span>
    <span>"An IRB alternative and runtime developer console"</span><span>)</span>
  <span>(</span><span>home-page</span> <span>"http://pryrepl.org"</span><span>)</span>
  <span>(</span><span>license</span> <span>expat</span><span>))</span>
</pre></div>
<p>One still has to package the propagated inputs if they aren't yet
available, add the necessary inputs for building native extensions if
needed, and fiddle with the native inputs needed to run the test
suite, but for most pure Ruby gems this gets you close to a working
package quickly.</p>
<p>In conclusion, while support for Ruby in Guix is still in its early
days, I hope that you have seen the benefits that using a
general-purpose, functional package manager can bring to your Ruby
environments (and all other environments, too.)  For more information
about Guix concepts, installation instructions, programming interface,
and tools, please refer to the <a href="https://gnu.org/software/guix/manual/">official manual</a>.  Check out the
<a href="https://gnu.org/software/guix/help/">help</a> page for ways to contact the development team for help or to
report bugs.  If you are interested in getting your hands dirty,
please <a href="https://gnu.org/software/guix/contribute/">contribute</a>.  Besides contributions of code, art, and docs,
we also need <a href="https://gnu.org/software/guix/donate/">hardware donations</a> to grow our build farm to meet the
needs of all our users.  Happy hacking!</p>]]></description>
										<content:encoded><![CDATA[<p>I&#8217;ve been working with Ruby professionally for over 3 years now and<br />
I&#8217;ve grown frustrated with two of its most popular development tools:<br />
RVM and Bundler.  For those that may not know, RVM is the Ruby version<br />
manager and it allows unprivileged users to download, compile,<br />
install, and manage many versions of Ruby instead of being stuck with<br />
the one that is installed globally by your distro&#8217;s package manager.<br />
Bundler is the tool that allows developers to keep a version<br />
controlled &quot;Gemfile&quot; that specifies all of the project&#8217;s dependencies<br />
and provides utilities to install and update those gems.  These tools<br />
are crucial because Ruby developers often work with many applications<br />
that use different versions of Ruby and/or different versions of gems<br />
such as Rails.  Traditional GNU/Linux distributions install packages<br />
to the global <tt class="docutils literal">/usr</tt> directory, limiting users to a single version<br />
of Ruby and associated gems, if they are packaged at all.  Traditional<br />
package management fails to meet the needs of a lot of users, so many<br />
niche package managers have been developed to supplement them.</p>
<p>Taking a step back, it becomes apparent that dependency isolation is a<br />
general problem that isn&#8217;t confined to software written in Ruby: Node<br />
has npm and nvm, Python has pip and virtualenv, and so on.  A big<br />
limitation of all these language-specific package managers is that<br />
they cannot control what is outside of their language domain.  In<br />
order to use RVM to successfully compile a version of Ruby, you need<br />
to make sure you have the GCC toolchain, OpenSSL, readline, libffi,<br />
etc. installed using the system package manager (note: I&#8217;ve seen RVM<br />
try to build prerequisites like OpenSSL before, which I then disabled<br />
to avoid duplication and security issues and I recommend you do the<br />
same.)  In order to use Bundler to install Nokogiri, you need to make<br />
sure libxml2 has been installed using the system package manager.  If<br />
you work with more than a single language, the number of different<br />
package management tools needed to get work done is staggering.  For<br />
web applications, it&#8217;s not uncommon to use RVM, Bundler, NPM, Bower,<br />
and the system package manager simultaneously to get all of the<br />
necessary programs and libraries.  Large web applications are<br />
notoriously difficult to deploy, and companies hire a bunch of<br />
operations folk like me to try to wrangle it all.</p>
<p>Anyway, let&#8217;s forget about Node, Python, etc. and just focus on Ruby.<br />
Have you or someone you work with encountered hard to debug issues and<br />
Git merge conflicts due to a problem with <tt class="docutils literal">Gemfile.lock</tt>?  Bundler&#8217;s<br />
fast and loose versioning in the <tt class="docutils literal">Gemfile</tt> (e.g. <tt class="docutils literal">rails &gt;= 4.0</tt>)<br />
causes headaches when different users update different gems at<br />
different times and check the resulting auto-generated<br />
<tt class="docutils literal">Gemfile.lock</tt> into the repository.  Have you ever been frustrated<br />
that it&#8217;s difficult to deduplicate gems that are shared between<br />
multiple bundled gem sets?  Have you looked at the <a class="reference external" href="https://rvm.io/">RVM home page</a><br />
and been frustrated that they recommend you to <tt class="docutils literal">curl | bash</tt> to<br />
install their software?  Have you been annoyed by RVM&#8217;s strange system<br />
of overriding shell built-ins in order to work its magic?  I&#8217;m not<br />
sure how you feel, dear reader, but my Ruby environments feel like one<br />
giant, brittle hack, and I&#8217;m often enough involved in fixing issues<br />
with them on my own workstation, that of my colleagues, and on<br />
production servers.</p>
<p>So, if you&#8217;re still with me, what do we do about this?  How can we<br />
work to improve upon the status quo?  Just use Docker?  Docker is<br />
helpful, and certainly much better than no isolation at all, but it<br />
hides the flaws of package management inside an opaque disk image and<br />
restricts the environments in which your application is built to<br />
function.  The general problem of dependency isolation is orthogonal<br />
to the runtime environment, be it container, virtual machine, or &quot;bare<br />
metal.&quot;  Enter functional package management.  What does it mean for a<br />
package manager to be functional?  GNU Guix, the functional package<br />
manager that I contribute to and recommend, has this to say:</p>
<blockquote>
<p>GNU Guix is a functional package management tool for the GNU<br />
system.  Package management consists of all activities that relate<br />
to building packages from sources, honoring their build-time and<br />
run-time dependencies, installing packages in user environments,<br />
upgrading installed packages to new versions or rolling back to a<br />
previous set, removing unused software packages, etc.</p>
<p>The term functional refers to a specific package management<br />
discipline.  In Guix, the package build and installation process<br />
is seen as a function, in the mathematical sense.  That function<br />
takes inputs, such as build scripts, a compiler, and libraries,<br />
and returns an installed package.</p>
</blockquote>
<p>Guix has a rich set of features, some of which you may find in other<br />
package managers, but not all of them (unless you use another<br />
functional package manager such as Nix.)  Gem/Bundler can do<br />
unprivileged gem installation, but it cannot do transactional upgrades<br />
and rollbacks or install non-Ruby dependencies.  Dpkg/yum/pacman can<br />
install all build-time and rumtime dependencies, but it cannot do<br />
unprivileged package installation to isolated user environments.  And<br />
none of them can precisely describe the <em>full</em> dependency graph (all<br />
the way down to the C compiler&#8217;s compiler) but <em>Guix can</em>.</p>
<p>Guix is written in Guile, an implementation of the Scheme programming<br />
language.  The upcoming release of Guix will feature a Ruby build<br />
system that captures the process of installing gems from <tt class="docutils literal">.gem</tt><br />
archives and a RubyGems import utility to make it easier to write Guix<br />
packages by using the metadata available on <a class="reference external" href="https://rubygems.org/">https://rubygems.org</a>.<br />
Ruby developers interested in functional package management are<br />
encouraged to try packaging their gems (and dependencies) for Guix.</p>
<p>Now, how exactly can Guix replace RVM and Bundler?  Guix uses an<br />
abstraction called a &quot;profile&quot; that represents a user-defined set of<br />
packages that should work together.  Think of it as having many<br />
<tt class="docutils literal">/usr</tt> file system trees that can be used in isolation from the<br />
others (without invoking virtualization technologies such as virtual<br />
machines or containers.)  To install multiple versions of Ruby and<br />
various gems, the user need only create a separate profile for them:</p>
<div class="highlight">
<pre>guix package --profile=project-1 --install ruby-2.2 ruby-rspec-3
# Hypothetical packages:
guix package --profile=project-2 --install ruby-1.9 ruby-rspec-2
</pre>
</div>
<p>A profile is a &quot;symlink forest&quot; that is the union of all the packages<br />
it includes, and files are deduplicated among all of them.  To<br />
actually use the profile, the relevant environment variables must be<br />
configured.  Guix is aware of such variables, and can tell you what to<br />
set by running the following:</p>
<div class="highlight">
<pre>guix package --search-paths --profile=project-1
</pre>
</div>
<p>Additionally, you can also create ad-hoc development environments with<br />
the <tt class="docutils literal">guix environment</tt> tool.  This tool will spawn a sub-shell (or<br />
another program of your choice) in an environment in which a set of<br />
specified packages are available.  This is my preferred method as it<br />
automagically sets all of the environment variables for me and Guix is<br />
free to garbage collect the packages when I close the sub-shell:</p>
<div class="highlight">
<pre># Launch a Ruby REPL with ActiveSupport available.
guix environment --ad-hoc ruby ruby-activesupport -E irb
</pre>
</div>
<p>In order to make this environment reproducible for others, I recommend<br />
keeping a <tt class="docutils literal">package.scm</tt> file in version control that describes the<br />
complete dependency graph for your project, as well as metadata such<br />
as the license, version, and description:</p>
<div class="highlight">
<pre><span class="p">(</span><span class="nf">use-modules</span> <span class="p">(</span><span class="nf">guix</span> <span class="nv">packages</span><span class="p">)</span>
             <span class="p">(</span><span class="nf">guix</span> <span class="nv">licenses</span><span class="p">)</span>
             <span class="p">(</span><span class="nf">guix</span> <span class="nv">build-system</span> <span class="nv">ruby</span><span class="p">)</span>
             <span class="p">(</span><span class="nf">gnu</span> <span class="nv">packages</span><span class="p">)</span>
             <span class="p">(</span><span class="nf">gnu</span> <span class="nv">packages</span> <span class="nv">version-control</span><span class="p">)</span>
             <span class="p">(</span><span class="nf">gnu</span> <span class="nv">packages</span> <span class="nv">ssh</span><span class="p">)</span>
             <span class="p">(</span><span class="nf">gnu</span> <span class="nv">packages</span> <span class="nv">ruby</span><span class="p">))</span>

<span class="p">(</span><span class="nf">package</span>
  <span class="p">(</span><span class="nf">name</span> <span class="s">&quot;cool-ruby-project&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">version</span> <span class="s">&quot;1.0&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">source</span> <span class="no">#f</span><span class="p">)</span> <span class="c1">; not needed just to create dev environment</span>
  <span class="p">(</span><span class="nf">build-system</span> <span class="nv">ruby-build-system</span><span class="p">)</span>
  <span class="c1">;; These correspond roughly to &quot;development&quot; dependencies.</span>
  <span class="p">(</span><span class="nf">native-inputs</span>
   <span class="o">`</span><span class="p">((</span><span class="s">&quot;git&quot;</span> <span class="o">,</span><span class="nv">git</span><span class="p">)</span>
     <span class="p">(</span><span class="s">&quot;openssh&quot;</span> <span class="o">,</span><span class="nv">openssh</span><span class="p">)</span>
     <span class="p">(</span><span class="s">&quot;ruby-rspec&quot;</span> <span class="o">,</span><span class="nv">ruby-rspec</span><span class="p">)))</span>
  <span class="p">(</span><span class="nf">propagated-inputs</span>
   <span class="o">`</span><span class="p">((</span><span class="s">&quot;ruby-pg&quot;</span> <span class="o">,</span><span class="nv">ruby-pg</span><span class="p">)</span>
     <span class="p">(</span><span class="s">&quot;ruby-nokogiri&quot;</span> <span class="o">,</span><span class="nv">ruby-nokogiri</span><span class="p">)</span>
     <span class="p">(</span><span class="s">&quot;ruby-i18n&quot;</span> <span class="o">,</span><span class="nv">ruby-i18n</span><span class="p">)</span>
     <span class="p">(</span><span class="s">&quot;ruby-rails&quot;</span> <span class="o">,</span><span class="nv">ruby-rails</span><span class="p">)))</span>
  <span class="p">(</span><span class="nf">synopsis</span> <span class="s">&quot;A cool Ruby project&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">description</span> <span class="s">&quot;This software does some cool stuff, trust me.&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">home-page</span> <span class="s">&quot;https://example.com&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">license</span> <span class="nv">expat</span><span class="p">))</span>
</pre>
</div>
<p>With this package file, it is simple to an instantiate a development<br />
environment:</p>
<div class="highlight">
<pre>guix environment -l package.scm
</pre>
</div>
<p>I&#8217;m not covering it in this post, but properly filling out the blank<br />
<tt class="docutils literal">source</tt> field above would allow for building development snapshots,<br />
including running the test suite, in an isolated build container using<br />
the <tt class="docutils literal">guix build</tt> utility.  This is a very useful when composed with<br />
a continuous integration system.  Guix itself uses <a class="reference external" href="https://nixos.org/hydra/">Hydra</a> as its CI<br />
system to perform all package builds.</p>
<p>As mentioned earlier, one of the big advantages of writing Guix<br />
package recipes is that the full dependency graph can be captured,<br />
including non-Ruby components.  The pg gem provides a good example:</p>
<div class="highlight">
<pre><span class="p">(</span><span class="nf">define-public</span> <span class="nv">ruby-pg</span>
  <span class="p">(</span><span class="nf">package</span>
    <span class="p">(</span><span class="nf">name</span> <span class="s">&quot;ruby-pg&quot;</span><span class="p">)</span>
    <span class="p">(</span><span class="nf">version</span> <span class="s">&quot;0.18.2&quot;</span><span class="p">)</span>
    <span class="p">(</span><span class="nf">source</span>
     <span class="p">(</span><span class="nf">origin</span>
       <span class="p">(</span><span class="nf">method</span> <span class="nv">url-fetch</span><span class="p">)</span>
       <span class="p">(</span><span class="nf">uri</span> <span class="p">(</span><span class="nf">rubygems-uri</span> <span class="s">&quot;pg&quot;</span> <span class="nv">version</span><span class="p">))</span>
       <span class="p">(</span><span class="nf">sha256</span>
        <span class="p">(</span><span class="nf">base32</span>
         <span class="s">&quot;1axxbf6ij1iqi3i1r3asvjc80b0py5bz0m2wy5kdi5xkrpr82kpf&quot;</span><span class="p">))))</span>
    <span class="p">(</span><span class="nf">build-system</span> <span class="nv">ruby-build-system</span><span class="p">)</span>
    <span class="p">(</span><span class="nf">arguments</span>
     <span class="o">&#39;</span><span class="p">(</span><span class="o">#</span><span class="nv">:test-target</span> <span class="s">&quot;spec&quot;</span><span class="p">))</span>
    <span class="c1">;; Native inputs are used only at build and test time.</span>
    <span class="p">(</span><span class="nf">native-inputs</span>
     <span class="o">`</span><span class="p">((</span><span class="s">&quot;ruby-rake-compiler&quot;</span> <span class="o">,</span><span class="nv">ruby-rake-compiler</span><span class="p">)</span>
       <span class="p">(</span><span class="s">&quot;ruby-hoe&quot;</span> <span class="o">,</span><span class="nv">ruby-hoe</span><span class="p">)</span>
       <span class="p">(</span><span class="s">&quot;ruby-rspec&quot;</span> <span class="o">,</span><span class="nv">ruby-rspec</span><span class="p">)))</span>
    <span class="c1">;; Native extension links against PostgreSQL shared library.</span>
    <span class="p">(</span><span class="nf">inputs</span>
     <span class="o">`</span><span class="p">((</span><span class="s">&quot;postgresql&quot;</span> <span class="o">,</span><span class="nv">postgresql</span><span class="p">)))</span>
    <span class="p">(</span><span class="nf">synopsis</span> <span class="s">&quot;Ruby interface to PostgreSQL&quot;</span><span class="p">)</span>
    <span class="p">(</span><span class="nf">description</span> <span class="s">&quot;Pg is the Ruby interface to the PostgreSQL RDBMS.  It works</span>
<span class="s">with PostgreSQL 8.4 and later.&quot;</span><span class="p">)</span>
    <span class="p">(</span><span class="nf">home-page</span> <span class="s">&quot;https://bitbucket.org/ged/ruby-pg&quot;</span><span class="p">)</span>
    <span class="p">(</span><span class="nf">license</span> <span class="nv">license:ruby</span><span class="p">)))</span>
</pre>
</div>
<p>Note how the recipe specifies the PostgreSQL dependency.  Below is the<br />
dependency graph for ruby-pg as produced by <tt class="docutils literal">guix graph</tt>, excluding<br />
the GCC compiler toolchain and other low-level tools for brevity.<br />
Pretty neat, eh?</p>
<p><img data-recalc-dims="1" decoding="async" alt="" src="https://i0.wp.com/dthompson.us/images/guix/ruby-pg-graph.png?w=625" /></p>
<p>Given that Guix doesn&#8217;t yet have many gems packaged (help wanted), it<br />
can still be advantageous to use it for getting more up-to-date<br />
packages than many distros provide, but in conjuction with Bundler for<br />
fetching Ruby gems.  This gets RVM out of your hair whilst creating a<br />
migration path away from Bundler at a later time once the required<br />
gems have been packaged:</p>
<div class="highlight">
<pre>cd my-project/
guix environment --ad-hoc ruby bundler libxml2 libxslt # etc.
# A small bash script can be used to make these gem sets.
mkdir .gems
export GEM_HOME=$PWD/.gems
export GEM_PATH=$GEM_HOME:$GEM_PATH
export PATH=$GEM_HOME/bin:$PATH
bundle install
</pre>
</div>
<p>As you&#8217;ve seen in the above package snippets, Guix package definitions<br />
are typically very short and rather easy to write yourself.  The<br />
<tt class="docutils literal">guix import gem</tt> tool was made to lower the barrier even more by<br />
generating most of the boilerplate code.  For example:</p>
<div class="highlight">
<pre>guix import gem pry
</pre>
</div>
<p>Produces this Scheme code:</p>
<div class="highlight">
<pre><span class="p">(</span><span class="nf">package</span>
  <span class="p">(</span><span class="nf">name</span> <span class="s">&quot;ruby-pry&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">version</span> <span class="s">&quot;0.10.1&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">source</span>
    <span class="p">(</span><span class="nf">origin</span>
      <span class="p">(</span><span class="nf">method</span> <span class="nv">url-fetch</span><span class="p">)</span>
      <span class="p">(</span><span class="nf">uri</span> <span class="p">(</span><span class="nf">rubygems-uri</span> <span class="s">&quot;pry&quot;</span> <span class="nv">version</span><span class="p">))</span>
      <span class="p">(</span><span class="nf">sha256</span>
        <span class="p">(</span><span class="nf">base32</span>
          <span class="s">&quot;1j0r5fm0wvdwzbh6d6apnp7c0n150hpm9zxpm5xvcgfqr36jaj8z&quot;</span><span class="p">))))</span>
  <span class="p">(</span><span class="nf">build-system</span> <span class="nv">ruby-build-system</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">propagated-inputs</span>
    <span class="o">`</span><span class="p">((</span><span class="s">&quot;ruby-coderay&quot;</span> <span class="o">,</span><span class="nv">ruby-coderay</span><span class="p">)</span>
      <span class="p">(</span><span class="s">&quot;ruby-method-source&quot;</span> <span class="o">,</span><span class="nv">ruby-method-source</span><span class="p">)</span>
      <span class="p">(</span><span class="s">&quot;ruby-slop&quot;</span> <span class="o">,</span><span class="nv">ruby-slop</span><span class="p">)))</span>
  <span class="p">(</span><span class="nf">synopsis</span>
    <span class="s">&quot;An IRB alternative and runtime developer console&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">description</span>
    <span class="s">&quot;An IRB alternative and runtime developer console&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">home-page</span> <span class="s">&quot;http://pryrepl.org&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">license</span> <span class="nv">expat</span><span class="p">))</span>
</pre>
</div>
<p>One still has to package the propagated inputs if they aren&#8217;t yet<br />
available, add the necessary inputs for building native extensions if<br />
needed, and fiddle with the native inputs needed to run the test<br />
suite, but for most pure Ruby gems this gets you close to a working<br />
package quickly.</p>
<p>In conclusion, while support for Ruby in Guix is still in its early<br />
days, I hope that you have seen the benefits that using a<br />
general-purpose, functional package manager can bring to your Ruby<br />
environments (and all other environments, too.)  For more information<br />
about Guix concepts, installation instructions, programming interface,<br />
and tools, please refer to the <a class="reference external" href="https://gnu.org/software/guix/manual/">official manual</a>.  Check out the<br />
<a class="reference external" href="https://gnu.org/software/guix/help/">help</a> page for ways to contact the development team for help or to<br />
report bugs.  If you are interested in getting your hands dirty,<br />
please <a class="reference external" href="https://gnu.org/software/guix/contribute/">contribute</a>.  Besides contributions of code, art, and docs,<br />
we also need <a class="reference external" href="https://gnu.org/software/guix/donate/">hardware donations</a> to grow our build farm to meet the<br />
needs of all our users.  Happy hacking!</p>

<p class="syndicated-attribution"><em>From the blog <a href="http://dthompson.us/">dthompson</a> by <a href="https://cs.worcester.edu/author/0/" title="Read other posts by David Thompson">David Thompson</a></em> and used with permission of the author. All other rights reserved by the author.</p>]]></content:encoded>
					
		
		<enclosure url="" length="0" type="" />

		<post-id xmlns="com-wordpress:feed-additions:1">3972</post-id>	</item>
	</channel>
</rss>
