Running a Private Gem Server

There are a few different ways to share code between Ruby applications, but perhaps the best known is by creating a Ruby gem. However, RubyGems.org (where gems are published by default) is a public system, and all gems published there are publicly available. This is a problem if you’re dealing with proprietary code that you need to keep private.

Thankfully, it is very easy to get up and running with your own private gem server.

Why not use Bundler to pull code from a private Git repository?

Another popular way of sharing code between applications is to use Bundler to pull code directly from a git repository. Pulling in code from a private git repository allows you to share code between applications while keeping that code private. However, this approach has some drawbacks.

Transitive dependencies don’t work well

Gems are able to specify their dependencies in the .gemspec file.

Gem::Specification.new do |spec|
  ...
  spec.add_dependency "activesupport"
end

But, what happens when you need to specify a dependency on a private gem? The gem specification does not allow you to point to a GitHub repository. Since we cannot specify the location of the dependency in the .gemspec, the only option is to do that in the application’s Gemfile.

In the gem’s .gemspec

# Some gem has a dependency on a private library
Gem::Specification.new do |spec|
  spec.name = "some-private-library"
  ...
  spec.add_dependency "another-private-library"
end

In the application’s Gemfile

# The application's Gemfile must tell bundler where to find that library
source 'https://rubygems.org'

gem 'some-private-library', git: 'git@github.com:jwood/some-private-library.git'

# Required by some-private-library
gem 'another-private-library', git: 'git@github.com:jwood/another-private-library.git'

The application should only need to care about the libraries that it directly depends on. It should not need to specify the location of transitive dependencies. This tightly couples the application to the implementation of the some-private-library gem, for no good reason.

It is less clear which version of the library you are using.

Looking at an example from a project’s Gemfile.lock, compare this:

GIT
  remote: git@github.com:redis/redis-rb.git
  revision: 9bb4156dcd43105b68e24e5efc579dddb12cf260
  specs:
    redis (3.0.6)

with this:

    redis (3.0.6)

Which version of the library are you working with in the first example? How about the second? If you said 3.0.6 for the first example, then you may be incorrect. You’re actually using the version identified by 9bb4156dcd43105b68e24e5efc579dddb12cf260. That may in fact be the same version of the code with the 3.0.6 label. Or, possibly, it is pointing at a version of the code that is several commits past the 3.0.6 label.

In the second example, it is abundantly clear that you are using version 3.0.6 of the gem.

Harder to stick to released versions of the library.

Like any other codebase, libraries are often under continuous development. Commits are constantly being made. Branches are constantly being merged. While the contents of master should always work, it may not always represent what the library author/maintainer would consider releasable code. At some point, the maintainer of the library will deem the version of code in master releasable, tag the code, and cut a new version of the library. If you use Bundler to point to a private git repository, you could end up using code that is not considered releasable.

One way around this issue is to tag releases in git, and then use bundler pull in that version of the code.

gem 'rails', git: 'git://github.com/rails/rails.git', tag: 'v2.3.5'

While this will in fact lock you to the tagged version of the code, it makes updating the gem more difficult. You can no longer use bundle update rails to update to the newest released version of the gem. You will remain locked on the v2.3.5 tag until you remove the tag directive from the gem in your Gemfile.

How do I setup a private gem server?

Thankfully, setting up your own gem server is very easy. The fantastic Gem in a Box project is a self contained, full featured gem server. It is even recommended as the “way to go” by Rubygems.org if you want to run your own gem server.

After your gem server has been setup, you can continue to pull public gems from Rubygems.org, while pulling private gems from your new private gem server.

How can I publish gems to my private gem server?

It doesn’t take much work to get a set of rake tasks that you can use to publish gems to your private gem server.

First, in your .gemspec file, make sure you specify rake, bundler and geminabox as development dependencies. Make sure you use version 1.3.0 or greater of bundler, as 1.3.0 added a feature which we will take advantage of later.

  spec.add_development_dependency "rake"
  spec.add_development_dependency "bundler", ">= 1.3.0"
  spec.add_development_dependency "geminabox"

Next, require bundler’s gem tasks in your project’s Rakefile.

require "bundler/gem_tasks"

bundler/gem_tasks gives you three rake tasks that come in handy for publishing gems.

rake build    # Build some-private-library-0.0.1.gem into the pkg directory.
rake install  # Build and install some-private-library-0.0.1.gem into system gems.
rake release  # Create tag v0.0.1 and build and push some-private-library-0.0.1.gem to Rubygems

By default, the release task will publish your gem to Rubygems.org. But, that’s not what we want. With a few lines of code in our Rakefile, we can tell bundler to push the gem to our internal gem server instead.

# Don't push the gem to rubygems
ENV["gem_push"] = "false" # Utilizes feature in bundler 1.3.0

# Let bundler's release task do its job, minus the push to Rubygems,
# and after it completes, use "gem inabox" to publish the gem to our
# internal gem server.
Rake::Task["release"].enhance do
  spec = Gem::Specification::load(Dir.glob("*.gemspec").first)
  sh "gem inabox pkg/#{spec.name}-#{spec.version}.gem"
end

Now, to release your gem, you simply type rake release

% rake release
some-private-library 0.0.1 built to pkg/some-private-library-0.0.1.gem.
Tagged v0.0.1.
Pushed git commits and tags.
gem inabox pkg/some-private-library-0.0.1.gem
Pushing some-private-library-0.0.1.gem to http://gems.mydomain.com/...
Gem some-private-library-0.0.1.gem received and indexed.

The first time you do this, geminabox will prompt you for the location of your gem server. After that, it will remember.

How do I use the gems on my private gem server?

To use the gems on your private gem server, you simply need to tell bundler where to find them in your application’s Gemfile. This is done using the source command:

# The application's Gemfile

source 'https://rubygems.org'
source 'https://gems.mydomain.com'

gem 'some-private-library'  # Will be found on the private gem server

Introducing AuroraAlarm

I just finished up work on my latest side project, AuroraAlarm.

AuroraAlarm is a FREE service that will notify you via SMS when conditions are optimal for viewing the Aurora Borealis in your area.

I have always enjoyed watching the weather and the stars. However, I’m not much of a night owl, and every attempt I’ve made to stay up late enough to see an Aurora after a solar event has failed, miserably. Time and time again I would fall asleep, and wake up to find that the conditions were great for viewing an Aurora the night before.

I wanted something that would wake me up if there was a possibility of seeing an Aurora. So, I created AuroraAlarm to do just that.

How it works

Every evening, AuroraAlarm checks to see if any solar events have occurred that could trigger a geomagnetic storm, which can produce an Aurora. If a solar event has occurred, it will send a text message notifying all users of the event, asking if they would like to receive a text message during the next few nights if conditions are optimal for viewing the Aurora.

If they indicate that they would like to be notified, AuroraAlarm will send them a text message at night if conditions are optimal for viewing the Aurora in their area.

What are optimal conditions?

  • Dark. Likely in the hours past midnight.
  • A Kp index strong enough to push the Aurora down to their geomagnetic latitude.
  • Clear skies.
  • A dark moon.

The goal

I have no idea if the aurora will be visible from where I live. Honestly, I think there may be a bit too much ambient light for me to see it. But, with the help of AuroraAlarm, at least I’ll be able to find out. And, I’m really not too far (about a 15 minute drive) from some REALLY dark areas. I certainly wouldn’t rule out making this short trip if it allowed me to see one of nature’s most fantastic displays.

Professionals Act Professional

I’m sick of it.

Every week (at least it feels that way) some new drama rears its ugly head in the ruby community. Petty arguments via twitter, one ranting blog post after another, people mocking ideas they consider less than ideal, and even some personal attacks thrown in the mix. There’s so much drama in fact that there is now a site out there that lists it all for the rest of the world to see.

Seriously? Are we all still in junior high?

Just think for a minute about all of the time and energy we are wasting here. Instead of igniting these flame wars, from which nothing productive is ever achieved, we could be growing as a community. We could be bringing up the next generation of software developers. We could be positively encouraging others to build better software. We could be sharing our experiences with others. We could be leading by example.

For a community of people complaining that they’re not treated like professionals, we sure don’t act very professional. If this is the way we behave, can we honestly expect people to treat us with the respect that they treat doctors, accountants, teachers, and members of other professions?

If you want to be treated like a professional, it’s best to start acting like one first.

Take the high road for once. The view is much nicer.

Optional method parameters in Ruby

One of the things I love about Ruby is the flexibility it provides when it comes to method parameters. It’s dead simple to provide default values for one or more parameters, to handle variable length argument lists, and to pass blocks of code into a method. But perhaps my favorite is the ability to tack hash key/value pairs onto the end of a method call, and have those options combined into a Hash on the other side.

def some_method(required_1, required_2, options={})
  # Do something awesome!
end

some_method("foo", "bar")
some_method("foo", "bar", :option_1 => false, :option_2 => true)
some_method("foo", 
            "bar",
            :option_1 => false,
            :option_2 => true,
            :option_3 => "something",
            :option_4 => "something else")

This may not look like much. However, this feature alone is capable of producing some very readable code, and is used extensively in APIs throughout the Ruby ecosystem. Consider for a moment what these APIs would look like if Ruby did not have this capability, which isn’t hard to imagine for those of us with a background in a language like Java. You would either be forced to require that each parameter be specified:

# What is this code doing?  What do the nil values,
# or even the true and false values map to?
some_method("foo", "bar", false, nil, true, nil)

or accept a hash or a request object that contains all of the necessary parameters:

# This is much more readable, but requires that the
# options hash be created on its own line.
options = {:option_1 => true, :option_2 => false}
some_method("foo", "bar", options)

Providing optional parameters via hash key/value paris at the end of a method call produces code that is incredibly readable. You have the names of the attributes right next to their corresponding values! There is no ambiguity whatsoever as to which values match up with which parameters.

It is also very flexible. The order of the attributes in the hash does not matter, like it does for required attributes. And, it is very easy to add new options, or delete old ones.

This approach also makes it easy to specify default values for options that were not specified when calling the method:

def some_method(required_1, required_2, options={})
  defaults = {
    :option_1 => "option 1 default",
    :option_2 => "option 2 default",
    :option_3 => "option 3 default",
    :option_4 => "option 4 default"
  }
  options = defaults.merge(options)

  # Do something awesome!
end

There are however a few minor drawbacks to this approach. The first is documentation. Methods that take a hash of options as a parameter do not convey any information about the valid options in the method definition alone. And, it is possible that the method in question simply forwards the options to another method, sending you on a wild goose chase to determine the set of valid options the code supports.

# Looking for a list of valid option keys...no help here.
def some_method(required_1, required_2, options={})
  do_something_awesome_with_the_options(options)
end

This is why it is so important do document your public API if you are using this approach. Take a look at the ActiveRecord::Associations::ClassMethods documentation. This page documents, in a very clear and easy to read mannor, all of the supported options for each method.

It is also worth pointing out that while this approach is great for optional parameters, it is ill suited for required parameters. Required parameters should be specified outside of the options hash, making it clear that values for the required parameters must be provided. While it’s true that stuffing all of your parameters inside a hash means you’ll never have to look at another wrong number of arguments error again, it will make your code difficult to understand, and easy to misuse.

Introducing Tenacity – An ORM Independent Way to Manage Inter-database Relationships

I’m a big believer in polyglot persistence. There are so many (very different) production ready databases available today that’s it is becoming more and more common to find applications using more than one database, utilizing the strengths of each. Using the right tool for the job gives me a warm, fuzzy feeling inside.

However, polyglot persistence comes with its own set of drawbacks. One of those drawbacks is the loss of foreign keys, which are very important in maintaining data integrity. Another drawback is that Object/Relational Mapping (ORM) libraries typically focus on a specific database, or type of database. So, writing code that manages relationships between objects backed by different databases hasn’t been nearly as easy as writing code to manage relationships between objects in the same database.

Tenacity’s goal is to address some of these issues. Tenacity is a ruby gem that provides an ORM independent way of managing relationships between models backed by different databases.

Tenacity works by extending popular Ruby ORM libraries to respond to a set of methods that the tenacity core uses to build and manage relationships between objects. By extending the ORM libraries to implement this interface, tenacity is able work with the objects in a generic way, without having to know what database is backing the given objects. This approach also allows you to continue using your favorite ORM libraries. To use tenacity, you simply need to include Tenacity inside your model.

Tenacity is heavily based on ActiveRecord’s associations, and aims to behave in much the same way, supporting many of the same options.

This initial release of tenacity supports belongs_to, has_one, and has_many associations, and the ActiveRecord, CouchRest, and MongoMapper ORMs. However, there is still plenty of work to be done. Feedback, bug reports, and code contributions are always welcome.

Tenacity is free and open source, and can be found on GitHub at https://github.com/jwood/tenacity.

Example

Download

gem install tenacity