Posts tagged with: "gems"

August 23, 2010

bundler ruby gems

Fixing Common Bundler Problems

Mini

by Jerry Cheung

When bundler first came out, I really wanted to like it. It promised a clean way to declare dependencies for your application in a single and definitive place, regardless of what kind of box your app was running on. Unfortunately, bundler has not lived up to the hype, and I've had plenty of headaches from bundler problems. Read on for a list of tips I've pulled together to save you some headache.

Ensure your local bundler is the same version as your server

Different versions of bundler may act differently:

bundle --version  # on your local machine and your server
sudo gem install bundler --version="0.9.26"

Explicitly specify gem versions

Did you know in HTTParty 0.4.5, there is no 'parsed_response' method on a response object? Well, neither did I when it worked fine on my local laptop (0.6.1), but not on the server (0.4.5)

gem "httparty"  # bad times if your system gem is out of date...
gem "httparty", "~> 0.6.1"  # better, but...
gem "httparty", "0.6.1"     # ...why not just specify the version everyone should use?

Check that you are actually using gems installed by bundler

Once in a while, bundler will report success on install, but you'll get the wrong gems loaded in your load path. Grep your load path to double check libraries you're having trouble with:

# in script/console
>> $:.grep /http/
=> ["/Users/jch/.bundle/ruby/1.8/gems/httparty-0.6.1/lib"]

Gemfile conditionals

bundler allows you to specify groups so only gems you need in one environment are loaded:

# we don't call the group :test because we don't want them auto-required
group :test do
  gem 'database_cleaner', '~> 0.5.0'
  gem 'rspec'
  gem 'rspec-rails', '~> 1.3.2', :require => 'spec/rails'
end

All gems you specify in your Gemfile WILL be installed regardless of what RAILS_ENV you're currently on. There's a very deceptively named option called --without that does not work as you would expect:

# weird, but this will install gems in group test
bundle install --without=test

This can turn out to be a disaster if your linux production environment tries to install a OSX specific gem with native extensions that you use for development. An ugly fix in the meantime is to add conditionals that look for an environment variable:

if ['test', 'cucumber'].include?(ENV['RAILS_ENV'])
  group :test do
    # your gems
  end
end

Update your capistrano

Don't forget to bundle when you deploy:

after  "deploy:update_code", "deploy:bundle"
namespace :deploy do
  desc "Freeze dependencies"
  task :bundle, :roles => :app do
    run "cd #{release_path} && bundle install --relock --without=test"
  end
end

NameErrors and autoloading issues

For some gems, bundler will not autoload properly. If you start getting NameErrors or LoadErrors for a gem, read this issue. The fix is to skip the require in your Gemfile and manually do the require in your environment.rb:

# Gemfile
gem 'misbehaving_gem', :require_as => []

# environment.rb
Rails::Initializer.run do |config|
  # ...
  config.gem 'misbehaving_gem'
  # ...
end

Nuke .bundle

When all else fails, and you've pulled out what precious little hair you have left:

rm -rf RAILS_ROOT/.bundle      # removes gems for this project
rm -rf ~/.bundle               # removes cached gems for your current user
rm -rf RAILS_ROOT/Gemfile.lock # lets you do a fresh 'bundle install'

# do a fresh bundle install
bundle install

Other

Bundler is in its infancy, and it continues to get better with each release, so many of these issues might not exist in the near future. In the meantime, I hope this list will save you some time with bundler related headaches. Let me know in the comments if you've encountered other tips for resolving these problems.

Comment | 

Hashie: The Hash Toolkit

Mini

by Michael Bleigh

One of my earliest gems was Mash, a useful tool for creating mocking objects as a Hash. One of the most common problems people had with Mash was a simple one: it conflicted with another class of the same name in extlib! To address this problem as well as give the project some room to grow, Mash is now part of a new toolkit called Hashie. Hashie is available now via Gemcutter and the source, as always, is available on GitHub. To install:

gem install hashie

Hello, Hashie

Hashie is, right now, simply the former Mash code along with a new extended Hash called a Dash. A Dash is a “discrete hash” that has pre-defined properties. It can be used as a dead-simple data object when even something like DataMapper is too heavy, but a Struct is too light (Dash gives you the ability to set per-property defaults as well as initialize from an attributes Hash). For example:

class Person < Hashie::Dash
  property :name
  property :email
  property :occupation, :default => 'Rubyist'
end

p = Person.new
p.name # => nil
p.occupation # => 'Rubyist'
p.email = 'abc@def.com'
p.email # => 'abc@def.com'
p['awesome'] # => NoMethodError

p = Person.new(:name => "Awesome Guy")
p.name # => "Awesome Guy"
p.occupation # => "Rubyist"

The other advantage Hashie has over Mash is that it’s built from the ground up to avoid conflicts. Instead of adding stringify_keys methods to the Hash class, it’s instead added to a Hashie::Hash subclass. You can, however, get Hashie’s few Hash extensions in the Hash class by including the HashExtensions:

Hash.send :include, Hashie::HashExtensions

Hopefully the move will make it easier for everyone to use it in their projects without fear of running into conflicts, and hopefully you’ll also find the Dash useful. Over time the functionality of Hashie may grow to encompass additional simple and useful extensions of Hash. So install Hashie, your friendly neighborhood Hash toolkit, today!

Comment | 

Mash - Mocking Hash for total poser objects

Mini

by Michael Bleigh

Note: Development of Mash has now moved to Hashie, a generic Hash toolkit.

There are a number of times when I need something like an OpenStruct with a little more power. Often times this is for API-esque calls that don’t merit a full on ActiveResource. I wrote a small class for use with my ruby-github library and wanted to make it a separate gem because I think it’s pretty useful to have around.

Usage

Basically a Mash is a Hash that acts a little more like a full-fledged object when it comes to the keyed values. Using Ruby’s method punctuation idioms, you can easily create pseudo-objects that store information in a clean, easy way. At a basic level this just means writing and reading arbitrary attributes, like so:

author = Mash.new
author.name # => nil
author.name = "Michael Bleigh"
author.name # => "Michael Bleigh"
author.email = "michael@intridea.com"
author.inspect # => <Mock name="Michael Bleigh" email="michael@intridea.com">

So far that’s pretty much how an OpenStruct behaves. And, like an OpenStruct, you can pass in a hash and it will convert it. Unlike an OpenStruct, however, Mash will recursively descend, converting Hashes into Mashes so you can assign multiple levels from a single source hash. Take this as an example:

hash = { :author => {:name => "Michael Bleigh", :email => "michael@intridea.com"},
       :gems => [{:name => "ruby-github", :id => 1}, {:name => "mash", :id => 2}]}

mash = Mash.new(hash)
mash.author.name # => "Michael Bleigh"
mash.gems.first.name # => "ruby-github"

This can be really useful if you have just parsed out XML or JSON into a hash and just want to dump it into a richer format. It’s just that easy! You can use the ? operator at the end to check for whether or not an attribute has already been assigned:

mash = Mash.new
mash.name? # => false
mash.name = "Michael Bleigh"
mash.name? # => true

A final, and a little more difficult to understand, method modifier is a bang (!) at the end of the method. This essentially forces the Mash to initialize that value as a Mash if it isn’t already initialized (it will return the existing value if one does exist). Using this method, you can set ‘deep’ values without the hassle of going through many lines of code. Example:

mash = Mash.new
mash.author!.name = "Michael Bleigh"
mash.author.info!.url = "http://www.mbleigh.com/"
mash.inspect # => <Mash author=<Mash name="Michael Bleigh" info=<Mash url="http://www.mbleigh.com/">>>
mash.author.info.url # => "http://www.mbleigh.com/"

One final useful way to use the Mash library is by extending it! Subclassing Mash can give you some nice easy ways to create simple record-like objects:

class Person < Mash
  def full_name
    "#{first_name}#{" " if first_name? && last_name?}#{last_name}"
  end
end

bob = Person.new(:first_name => "Bob", :last_name => "Bobson")
bob.full_name # => "Michael Bleigh"

For advanced usage that I’m not quite ready to tackle in a blog post, you can override assignment methods (such as name= and this behavior will be picked up even when the Mash is being initialized by cloning a Hash.

Installation

It’s available as a gem on Rubyforge, so your easiest method will be:

sudo gem install mash

If you prefer to clone the GitHub source directly:

git clone git://github.com/mbleigh/mash.git

This is all very simple but also very powerful. I have a number of projects that will be getting some Mashes now that I’ve written the library, and maybe you’ll find a use for it as well.

Comment | 

Words we've written view all blog posts »

Featured Article

Intridea at Lonestar Ruby Conference

by Renae Bair on August 18, 2010

For the third straight year in a row, senior-level developers from the Intridea team will be at the Lonestar Ruby Conference, on Thursday, August 26th, teaching students about Ruby. Students attending the Ruby Intrigue class will work with our Director of Mobile Development, Brendan Lim, our Director of Development, Adam Bair, and our Director of Research and Development, Pradeep Elankumaran. Continue reading »

Recent Blog Posts

FlockFeeds Launches From Node Knockout

by Intridea on August 30, 2010

Using NPM with Heroku Node.js

by Michael Bleigh on August 24, 2010

Fixing Common Bundler Problems

by Jerry Cheung on August 23, 2010