Bundler's :require option in a gemfile? - ruby

How would one go about using Bundler's :require=> in a gemspec? For instance, I would like to only use sinatra/base as a runtime dependency. This works in a gemfile:
gem 'sinatra', :require => 'sinatra/base'
but does not work in the gemspec (even when bundler is required in the gemspec):
s.add_runtime_dependency 'sintatra', :require => 'sinatra/base'
The error is "Illformed requirement [{:require=>"sinatra/base"}]"
Anybody else find themselves in a similar situation?

In the gemspec file you can specify the gem's dependencies only. This file doesn't do require for you. You should require dependencies in the ruby code.
On the other hand you can create a Gemfile to help you in the development environment. But the Gemfile is not loaded when you are using the gem on other projects.

Related

Optional runtime dependency for Ruby gem with executables

I'm writing a gem aipp which exposes a few executables, nothing fancy here:
#!/usr/bin/env ruby
require 'aipp'
AIPP::NOTAM::Executable.new(File.basename($0)).run
Parts of the gem optionally use database adapters (pg or ruby-mysql gem). But since these can be a pain in the butt when the gem is used on the cloud, I'd like to really make them optional and not require them as runtime dependency in the .gemspec.
So I require them conditionally at runtime:
require 'pg' if ENV['AIPP_POSTGRESQL_URL']
require 'mysql' if ENV['AIPP_MYSQL_URL']
Unfortunately, that doesn't work as expected. When either of the environment variables is set and the executable is used, the require fails – probably because there's no dependency declared.
I've tried an inline Gemfile on the executable like the following. Works in development (repo checkout), but not when the gem is intalled via Rubygems:
#!/usr/bin/env ruby
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'aipp'
gem 'pg', '~> 1' if ENV['AIPP_POSTGRESQL_URL']
gem 'ruby-mysql', '~> 3' if ENV['AIPP_MYSQL_URL']
end
AIPP::NOTAM::Executable.new(File.basename($0)).run
What's the correct approach to require gems which are not listed as runtime dependency but installed additionally (via gem install or Gemfile)?
Maybe somebody knows of an existing gem which has already solved this problem somehow.
Thanks for your help!
I would use bundler groups for that.
gemfile do
source 'https://rubygems.org'
gem 'aipp'
group :database do
gem 'pg', '~> 1'
gem 'ruby-mysql'
end
end
There is more info about how to use them in the link.

'Bundler.require' requiring all gems?

Trying to figure out Ruby's Bundler library. My understanding is we can require only certain groups, but my setup seems to be loading gems specified in other groups as well.
Gemfile
source 'https://rubygems.org'
# Specify your gem's dependencies in apple.gemspec
gemspec
group :production do
gem 'mail'
gem 'bundler'
gem 'pry'
gem 'commander'
gem 'fastlane'
gem 'spaceship'
gem 'highline'
gem 'terminal-table'
gem 'clipboard'
gem 'date'
gem 'mysql2'
gem 'fileutils'
gem 'redis'
gem 'json'
gem 'logger'
gem 'jira-ruby', :require => 'jira-ruby'
end
group :jenkins do
gem 'terminal-table'
gem 'pry'
gem 'mail'
gem 'jira-ruby'
gem 'spaceship'
end
test.rb
require 'pry'
binding.pry
require 'rubygems'
require 'bundler/setup'
Bundler.require(:jenkins) # I want this step to require only gems listed under 'jenkins' group in `Gemfile`.
...
When I run the code, it seems Bundler.require(:jenkins) step seems to be requiring all gems specified in Gemfile,
I am still in the process of understanding Bundler, pardon me if the question I asked is too obvious. Does anyone know how to only load the gems from bundler groups? Thanks in advance!!
This is kind of confusing, but as far as I can tell from using it myself, it only requires the gems in the given group even though it lists all of them.
It's pretty easy to see this for yourself, just try using one from the production group
Bundler.require(:jenkins)
Date.new # Should error
Really it seems like you may have noticed this yourself, but you just didn't realize.. If it was including all of them you wouldn't have needed to require pry in test.rb :)

Why do I get NameError with `bundle exec ruby [file]` given that the necessary gem is in Gemfile?

I'm doing some messing around to try to understand better how bundler works. I have just three files in my working directory:
Gemfile Gemfile.lock test.rb
All the Gemfile has is gem "slop" and test.rb looks like this:
puts Slop.parse
When I run bundle exec test.rb I get a NameError due to not having a require statement:
[ec2-user#xx my_app]$ bundle exec ruby test.rb
test.rb:1:in `<main>': uninitialized constant Slop (NameError)
But if I run bundle console, Bundler loads the gem correctly and I can run Slop.parse from the console without having to explicitly type require "slop":
[ec2-user#xx my_app]$ bundle console
irb(main):001:0> Slop.parse
=> #<Slop::Result:0x00000001339838...
So what am I missing? I was under the impression that since I don't have require: false in my Gemfile, Slop should be loaded when I run bundle exec ruby test.rb and I shouldn't need to put the require "slop" line in the file.
You need to config bundler to require all gems on your Gemfile like this:
require 'rubygems'
require 'bundler/setup'
Bundler.require(:default)
Check the docs at http://bundler.io/v1.12/bundler_setup.html
I was under the impression that since I don't have require: false in
my Gemfile, Slop should be loaded when I run bundle exec ruby test.rb
and I shouldn't need to put the require "slop" line in the file.
The bundler docs say:
Specify your dependencies in a Gemfile in your project's root:
source 'https://rubygems.org'
gem 'nokogiri' #<======HERE
Inside your app, load up the bundled environment:
require 'rubygems'
require 'bundler/setup'
# require your gems as usual
require 'nokogiri' #<========AND HERE
As for this:
I was under the impression that since I don't have require: false in
my Gemfile, Slop should be loaded when I run bundle exec ruby test.rb
and I shouldn't need to put the require "slop" line in the file.
The bundler docs are horrible on this point. As far as I can tell, :require => false is a Rails specific thing, which is used to decrease load times on project startup. In a rails app, specifying require: false means that the gem won't be loaded until you manually require the gem. If you don't specify :require => false, then the gem will be loaded automatically--however that is because rails code is written to do that automatic loading. Your app has no code that performs a similar function.
Edit: Made a mistake while testing. So here's the way it works: In a non rails app, e.g. in your test.rb, if you want to automatically require all the gems specified in your Gemfile, you need to write:
Bundler.require :default
The Bundler docs mention that in the fine print here:
Specify :require => false to prevent bundler from requiring the gem,
but still install it and maintain dependencies.
gem 'rspec', :require => false
gem 'sqlite3'
In order to require gems in your Gemfile, you will need to call Bundler.require in your application.
I'm not sure why that requirement was only mentioned in conjunction with require: false instead of being stated at the outset.
And, in your Gemfile if you specify:
gem 'slop', :require => false
(as well as Bundler.require :default in test.rb), then you also have to explicitly require the slop gem in test.rb:
require 'slop'
In other words, Bundler.require :default automatically requires all the gems in your Gemfile except the gems marked with require: false. For gems marked with require: false, you have to manually write require 'gem_name' in your app.
Therefore, neydroid posted the correct solution.
* In your Gemfile, you can nest gems in groups, which affects how Bundler.require() works. See the Bundler docs on groups.
You should add the require "slop" inside your test.rb

Bundler gem installed from github get installed in a different location

I am trying to install a gem from github like this:
gem 'omniauth', :git => "git://github.com/intridea/omniauth.git", :require => "omniauth"
The problem is that the gem is not actually being loaded. The ruby objects are not there.
So, bundle show omniauth shows me: Users/felipe/.rvm/gems/ruby-1.9.2-p136/bundler/gems/omniauth-5972c94792cf
The problem is that the gem is being installed to a different location from the regular ones. I expected it to be `/Users/felipe/.rvm/gems/ruby-1.9.2-p136/gems/``
Any idea on how to fix this?
I think you're missing these two lines:
require "rubygems"
require "bundler/setup"
as you can see in Bundler's source code, "bundler/setup" is going to put gems managed by Bundler in the Ruby's load path:
https://github.com/carlhuda/bundler/blob/1-0-stable/lib/bundler/setup.rb#L22
Hope this helps :)
try changing the bundler line to.
gem 'omniauth', :git => "git://github.com/intridea/omniauth.git", :require => 'oa-oauth'
The problem is that your :require property was pointing to the wrong file to load. It is not always the same name as the library, by the way, when both lib name and require are the same you don't need to specify it, only when they differs.

Gem development with Bundler: include or exclude Gemfile?

I'm developing a gem locally. It's a command-line utility that only has test dependencies, and my Gemfile looks like this:
source :rubygems
gemspec
group :test do
gem "cucumber"
gem "aruba"
gem "rspec"
end
My gemspec looks like this:
Gem::Specification.new do |s|
# authorship stuff...
s.files = `git ls-files`.split("\n")
end
That's the default gemspec created by Bundler. I know we're supposed to keep Gemfile and Gemfile.lock in source control, but I'm wondering about including them in the packaged gem through the Gem::Specification#files attribute. Are there arguments for/against including Gemfile and Gemfile.lock in the distributed gem? It seems weird or at least unnecessary to me.
Yehuda Katz just blogged on this topic! : Clarifying the Roles of the .gemspec and Gemfile

Resources