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 dobundle 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?
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] .
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.
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
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
@zed_0xff: found a similar approach in an older rspec-core
commit:
if RUBY_PLATFORM =~ /darwin/
gem 'foo'
end
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With