Why is bundler loading all my gems instead of specific ones - ruby

I have a Sinatra application and I'm trying to use groups in my Gemfile in order to load only specified gems. But, when I restrict loading to just one group bundler still loads every gem in the file. Here's my Gemfile:
source 'https://rubygems.org'
group :one do
gem 'sinatra'
end
group :two do
gem 'bitly'
end
And here's my application:
require 'bundler/setup'
Bundler.require(:one)
class App < Sinatra::Base
configure do
puts Gem.loaded_specs.keys.sort.join("\t")
end
get '/foo' do
end
end
And I can clearly see the Bitly gem loaded when the application starts. What am I doing wrong?

Use
require 'bundler'
instead of
require 'bundler/setup'
The last one automatically loads all gems in Gemfile: Why do you need "require 'bundler/setup'"?

Related

Bundler how to require gems separately in Gemfile just in one file?

I have a conflict between rspec and mocha (rspec is not using mocha but other minitest tests are).
If I put mocha in my gemfile (even with require: false) it gets loaded by activesupport/test_case.rb:15
silence_warnings { require 'mocha/setup' }
which then causes rspec to barf.
So, I'd like to just require it in my test_setup file from my system gems but I can't figure out how to load a gem outside of bundler.
Other ideas on how to get these gems to play nice are welcome.
You can use groups in your Gemfile: http://bundler.io/v1.3/groups.html
Require the gems in particular groups, noting that gems outside of a
named group are in the :default group
Bundler.require(:default, :development)
Require the default gems, plus the gems in a group
named the same as the current Rails environment
Bundler.require(:default, Rails.env)
Restrict the groups of gems that
you want to add to the load path. Only gems in these groups will be
require'able
require 'rubygems'
require 'bundler'
Bundler.setup(:default, :ci)
require 'nokogiri'
Could you just install gem and require it?
$ gem install my_gem
and in testfile:
require 'full/path/to/my_gem.rb'

Error while running a Sinatra Application

I'm trying to run a Sinatra application with the most basic app.rb:
require 'sinatra/activerecord/rake'
require 'bundler/setup'
Bundler.require(:default)
require_relative './config'
require_relative './models/star'
require_relative './models/planet'
require_relative './models/moon'
require_relative './models/astronaut'
get '/' do
erb :index
end
After using Bundle and creating Gemfile.lock I'm keep getting this error:
You have already activated activesupport 4.0.2, but your Gemfile requires activesupport 3.2.16. Using bundle exec may solve this. (Gem::LoadError)
My Rakefile is:
source 'https://rubygems.org'
gem 'sinatra'
gem 'sinatra-reloader'
gem 'sinatra-activerecord'
gem 'activerecord', '~> 3.2.13'
gem 'rake'
gem 'pg'
gem 'pry'
I'll be grateful for any suggestions.
You have both ActiveRecord 4.0.2 and 3.2.13 installed on your system. The first line of your app requires sinatra/activerecord/rake which in turn requires activerecord, without specifying which version. This activates and loads 4.0.2 – the latest version.
In the next line you try to set up Bundler. Bundler now tries to activate version 3.2.13 of ActiveRecord as specified in your Gemfile, but can’t since a version is already activated, so you get an error.
To fix, simply make sure you call require 'bundler/setup' first, before you require any other files. This will ensure any files you require will be compatible with your Gemfile.
Alternatively you could remove the call to require bundler/setup and make sure you always start your app using bundle exec.

Ruby: What does 'require: false' in Gemfile mean?

Does this:
gem 'whenever', require: false
mean that the gem needs to be installed, or does it mean it is not required?
This means install the gem, but do not call require when you start Bundler. So you will need to manually call
require "whenever"
if you want to use the library.
If you were to do
gem "whenever", require: "whereever"
then bundler would download the gem named whenever, but would call
require "whereever"
This is often used if the name of library to require is different than the name of the gem.
You use :require => false when you want the gem to be installed but not "required".
So in the example you gave:
gem 'whenever', :require => false
when someone runs bundle install the whenever gem would be installed as with gem install whenever. Whenever is used to create cron jobs by running a rake task but isn't usually used from within the rails (or other framework if not rails) application.
So you can use :require => false for anything that you need to run from the command line but don't need within your code.
require: false tells Bundler.require not to require that specific gem: the gem must be required explicitly via require 'gem'.
This option does not affect:
bundle install: the gem will get installed regardless
the require search path setup by bundler.
Bundler adds things to the path when you do either of:
Bundle.setup
which is called by require bundler/setup
which is called by bundle exec
Example
Gemfile
source 'https://rubygems.org'
gem 'haml'
gem 'faker', require: false
main.rb
# Fail because we haven't done Bundler.require yet.
# bundle exec does not automatically require anything for us,
# it only puts them in the require path.
begin Haml; rescue NameError; else raise; end
begin Faker; rescue NameError; else raise; end
# The Bundler object is automatically required on `bundle exec`.
Bundler.require
Haml
# Not required because of the require: false on the Gemfile.
# THIS is what `require: false` does.
begin Faker; rescue NameError; else raise; end
# Faker is in the path because Bundle.setup is done automatically
# when we use `bundle exec`. This is not affected by `require: false`.
require 'faker'
Faker
Then the following won't raise exceptions:
bundle install --path=.bundle
bundle exec ruby main.rb
On GitHub for you to play with it.
Rails usage
As explained in the initialization tutorial, the default Rails template runs on startup:
config/boot.rb
config/application.rb
config/boot.rb contains:
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
which does the require 'bundler/setup' and sets up the require path.
config/application.rb does:
Bundler.require(:default, Rails.env)
which actually requires the gems.
Whenever you specify a Gem in your Gemfile and run bundle install, bundler will go and install specified gem and load code for that Gem in you app by putting require 'whenever' this way bundler will load code for all of your Gems in your Rails app, and you can call any method from any Gem without any pain, like you do most of the time.
but Gems like whenever, faker or capistrano are something which you do not need in your app code you need whenever code in your schedule.rb file to manage crons and capistrano code in deploy.rb file to customize deployment recipe so you need not to load code for these gems in your app code
and wherever you want to call any method from these Gems you can manually require thsese gems by yourself by putting require "whenever" . so you put :require => false in your Gemfile for these Gems, this way bundler will install that Gem but not load code for that Gem itself, you can do it whenever you want by simply putting like require 'whenever' in your case.
Analogy to Explain
## Gemfile
gem "university_degree", require: false
gem "dealing_with_boss"
"dealing_with_boss" - loaded into memory and ready to go.
degree gem - not "needed"....you need to manually require it, in order to use it.
In order to require gems in your Gemfile, you will need to call Bundler.require.
You can prevent bundler from requiring the gem with require: false, but it will still install and maintain the gem. Check this out for a more detailed explanation.

Sinatra + Bundler?

I'm wondering how one can use Bundler with Sinatra. The idea is to use the gems that Bundler downloads inside the .gems folder.
Inside your Sinatra app, you just have to require the bundler setup:
require "bundler/setup"
require "sinatra"
get "/" do
"Hello world!"
end
Alternatively, if you don't want to add the additional require "bundler/setup" at the top of your app, you can instead invoke sinatra via bundle exec (e.g. bundle exec ruby myapp.rb)
This assumes that you have a Gemfile in the root of your application. It might look like this:
source "http://rubygems.org"
gem "sinatra"
This also assumes that you've already installed bundler (gem install bundler) and that you ran bundle install to install all the gem dependencies.
I believe the best way is described here on EngineYard blog:
# This makes sure the bundled gems are in our $LOAD_PATH
require File.expand_path(File.join(File.dirname(__FILE__), 'vendor', 'gems', 'environment'))
# This actually requires the bundled gems
Bundler.require_env
class MyApp < Sinatra::Base
# stuff
end
As my original answer was quite old but there seems to be still attention to this topic here's the latest version of bundler/sinatra setup which will cover most of the use case:
A minimal config.ru
require './my_sinatra_app'
run MySinatraApp
An environment env.rb file that requires all the bundled gems (also supports loading the current environment's group):
require 'bundler/setup'
APP_ENV = ENV["RACK_ENV"] || "development"
Bundler.require :default, APP_ENV.to_sym
Then your app file (requiring the environment) with your sinatra app (Sinatra::Base):
require_relative 'env'
class MyApp < Sinatra::Base
get "/" do
"hello world"
end
end
Start your development server with rackup, and Sinatra will be loaded via Bundler, your app will be accessible from http://localhost:9292.
$ rackup
or bundle exec rackup if needed
Make sure you have a Gemfile like the following one and you run the bundle command before starting the app
source "https://rubygems.org"
gem "sinatra"
gem "puma" # a better rack server than the default webrick
+1 for the guide on the bundler website, but if you have a simple app and use Sinatra's dsl at the top level, then you need to do the following:
in your Gemfile (tell bundler not require sinatra):
gem 'sinatra', :require => false
and in the app's file (explicitly require sinatra):
require 'rubygems'
require 'bundler'
Bundler.require
require 'sinatra'
get '/' do
'hello world'
end
To use bundler with a Sinatra application, you only need to do two things. First, create a Gemfile.
gem 'sinatra'
Then, set up your config.ru file to load the bundle before it loads your Sinatra app.
require 'rubygems'
require 'bundler'
Bundler.require
require './my_sinatra_app'
run MySinatraApp
Start your development server with rackup, and Sinatra will be loaded via Bundler.
rackup
source bundler docs

Deploying Sinatra app on Dreamhost/Passenger with custom gems

I've got a Sinatra app that I'm trying to run on Dreamhost that makes use of pony to send email. In order to get the application up and running at the very beginning (before adding pony), I had to gem unpack rack and gem unpack sinatra into the vendor/ directory, so this was my config.ru:
require 'vendor/rack/lib/rack'
require 'vendor/sinatra/lib/sinatra'
set :run, false
set :environment, :production
set :views, "views"
require 'public/myapp.rb'
run Sinatra::Application
I have already done gem install pony and gem unpack pony (into vendor/). Afterwards, I tried adding require 'vendor/sinatra/lib/pony' to config.ru only to have Passenger complain about pony's dependencies (mime-types, tmail) not being found either!
There has to be a better way to use other gems and tone down those long, ugly, redundant requires. Any thoughts?
I'd recommend creating your own gem path "somewhere" then adding it in your config.ru
like:
ENV['GEM_PATH'] = xxx
Gem.clear_paths
then install your gems into that
Install Ruby gems on dreamhost
https://c.kat.pe/installing-ruby-gems-on-dreamhost
Change config.ru (works for Sinatra 1.0)
require 'rubygems'
require 'vendor/sinatra/lib/sinatra.rb'
ENV['GEM_HOME'] = '/home/username/.gems'
ENV['GEM_PATH'] = '$GEM_HOME:/usr/lib/ruby/gems/1.8'
require 'rubygems'
Gem.clear_paths
disable :run, :reload
set :environment, :production
require 'yourapp'
run Sinatra::Application
Hope it helps someone.
I am using pony and a lot of other gems for my Sinatra. It should work well for you too. It's just those two lines (GEM_HOME and GEM_PATH) you have to add on your config.
It took me ages to find that you can simply use "gem install sinatra" and gem will figure out (because the system directories are read-only) that you will need to use a local gem install directory. As of now, there seems to be no need to set any special environment at all. It figures out to use $HOME/.gem as the local gem path and everything just works. No need for require 'vendor/stuff' at all. I did find I had to add $HOME/.gem/ruby/1.8/bin to my path in order to execute binaries installed by gems.
Here's my config.ru (for Dreamhost)
## Passenger should set RACK_ENV for Sinatra
require 'test'
set :environment, :development
run Sinatra::Application
Later edit: This is all well and fine, but there remains the issue that Passenger can't find my gems when the job initially starts up.
My config.ru is just simple as:
require 'rubygems'
require 'vendor/sinatra/lib/sinatra.rb'
require 'app.rb'
and app.rb head:
require 'yaml'
require 'haml'
require 'ostruct'
require 'date'
require 'pp'
module FlytoFB
log = File.new("sinatra.log", "a")
STDOUT.reopen(log)
STDERR.reopen(log)
configure do
enable :logging, :dump_errors
set :app_file, __FILE__
set :reload, true
set :root, File.dirname(__FILE__)
set :environment, :production
set :env, :production
set :run, false
set :raise_errors, true
set :public, 'public'
error do
e = request.env['sinatra.error']
puts e.to_s
puts e.backtrace.join("\n")
"Application Error!"
end
not_found do
"Page not found!"
end

Resources