Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add Mac-specific gems to bundle on Mac but not on Linux?

I'm developing a Rails app on a Mac, and I'm new to testing, so I just added these gems to my Gemfile:

group :test, :development do
  gem 'rspec-rails'     
  gem 'rb-fsevent'
  gem 'growl'
end

But my production server runs Linux, so even if they aren't grouped in :production, bundler (v1.0.21) still attempts to install them. ...and fails, obviously!
extconf.rb:19:in '<main>': Only Darwin (Mac OS X) systems are supported (RuntimeError)

Setting RAILS_ENV to production before running bundle install doesn't work.

It worked by running bundle install --without development test, but how can these gems be taken into consideration by bundler only based on your OS?


Edit: The bundler wiki provides details on how to use platform as a parameter.
The same solution is given in bundler issue #663, so I tried:

group :test, :development do
  gem 'rspec-rails'     
  platforms :darwin do
    gem 'rb-fsevent'
    gem 'growl'
  end 
end

bundle install does not work, but even if we go back to square one and do
bundle install --without darwin, the result is 'darwin' is not a valid platform.
The available options are: [:ruby, :ruby_18, :ruby_19, :mri, :mri_18, :mri_19, :rbx, :jruby, :mswin, :mingw, :mingw_18, :mingw_19]


Any other (elegant) approaches?

like image 395
Marius Butuc Avatar asked Dec 07 '11 18:12

Marius Butuc


People also ask

How do I install specific gems?

Using gem search -r , you can search RubyGems' repository. For instance, gem search -r rails will return a list of Rails-related gems. With the --local ( -l ) option, you would perform a local search through your installed gems. To install a gem, use gem install [gem] .

What is the difference between gem install and bundle install?

Almost seems like running 'gem install' adds it to the global available gems (and hence terminal can run the package's commands), whereas adding it to the gemfile and running bundle install only adds it to the application. Similar to npm install --global. that's basically it.


5 Answers

The Bundler wiki has a method that adds all gems to Gemfile.lock regardless of platform. It sets require => false depending on the system so you don't need to be able to actually run the gems:

gem 'rb-inotify', :require => RUBY_PLATFORM.include?('linux') && 'rb-inotify'

And they provide helper methods to make this clean:

def os_is(re)
  RbConfig::CONFIG['host_os'] =~ re
end

gem 'rb-fsevent', "~> 0.9.3", platforms: :ruby, install_if: os_is(/darwin/)
gem 'rb-inotify', "~> 0.8.8", platforms: :ruby, install_if: os_is(/linux/)
gem 'wdm',        "~> 0.1.0", platforms: [:mswin, :mingw. :x64_mingw], install_if: os_is(/mingw|mswin/i)

On my Windows 7 x64 system running Ubuntu 12.04 in a Vagrant VM, this worked fine, but the :platforms setting was required - the Linux bundler choked on the 'win32console' gem:

Console.c:1:21: fatal error: windows.h: No such file or directory
like image 199
iono Avatar answered Oct 08 '22 10:10

iono


Gemfile actually is a regular ruby file, so you can use something like

case RUBY_PLATFORM
when /darwin/
  gem 'foo'
when /win32/
  gem 'bar'
end
like image 36
zed_0xff Avatar answered Oct 08 '22 11:10

zed_0xff


@zed_0xff: found a similar approach in an older rspec-core commit:

if RUBY_PLATFORM =~ /darwin/
  gem 'foo'
end
like image 20
Marius Butuc Avatar answered Oct 08 '22 09:10

Marius Butuc


You can use :install_if method which accepts arbitrary lambda.

Following example comes directly from Gemfile's man pages:

install_if -> { RUBY_PLATFORM =~ /darwin/ } do
  gem "pasteboard"
end

It is much better than control flow constructs (e.g. if) as it maintains dependencies correctly and keeps Gemfile.lock uniform on all machines.

like image 45
skalee Avatar answered Oct 08 '22 10:10

skalee


According to the Bundler docs, you need to use the platforms directive:

#Gemfile
platforms :mswin do
  gem "x"
end

gem "weakling",   :platforms => :jruby
gem "ruby-debug", :platforms => :mri_18
gem "nokogiri",   :platforms => [:mri_18, :jruby]

There are a number of Gemfile platforms:

ruby C Ruby (MRI) or Rubinius, but NOT Windows

ruby_18 ruby AND version 1.8

ruby_19 ruby AND version 1.9

ruby_20 ruby AND version 2.0

mri Same as ruby, but not Rubinius

mri_18 mri AND version 1.8

mri_19 mri AND version 1.9

mri_20 mri AND version 2.0 rbx Same as ruby, but only Rubinius (not MRI

jruby JRuby

mswin Windows

mingw Windows 'mingw32' platform (aka RubyInstaller)

mingw_18 mingw AND version 1.8

mingw_19 mingw AND version 1.9 mingw_20 mingw AND version 2.0

like image 23
Richard Peck Avatar answered Oct 08 '22 09:10

Richard Peck