Scott Schulthess
Scott Schulthess

Reputation: 2923

User-level bundler Gemfile

I'd love to have a Gemfile in Bundler that just sets my own personal Gemfiles to always be bult into bundles...

aka ruby-debug, interactive-editor, and so forth.

Any idea how to do this?

Upvotes: 9

Views: 1362

Answers (5)

Povilas Jurčys
Povilas Jurčys

Reputation: 176

The cleanest solution I found so far is to use a separate Gemfile.personal and use a custom Gemfile path. I like this solution because you can use it in any project without modifying project code at all.

1. Add Gemfile.personal in to project root dir

# /path/to/your_ruby_project/Gemfile.personal
eval File.read('Gemfile') # use all gems from Gemfile

gem 'personal-gem1'
gem 'personal-gem2'

2. Install gems using Gemfile.personal file

BUNDLE_GEMFILE="Gemfile.personal" bundle install
# or
bundle install --gemfile=Gemfile.personal

Just remember to specify BUNDLE_GEMFILE every time you execute commands with bundler.

I personally put BUNDLE_GEMFILE=Gemfile.personal env variable in .env file using dotenv which ensures that Gemfile.personal is always used when I execute any command with bundler so I do not need to put it manually every time.

3. Put Gemfile.personal and Gemfile.personal.lock to .gitignore

For linux users:

touch ~/.gitignore
echo "Gemfile.personal\nGemfile.personal.lock" >> ~/.gitignore

This will affect all projects, so you do not need to update each project .gitignore separately.

Upvotes: 1

skalee
skalee

Reputation: 12675

My proposition does not depend on Bundler. As such does not clutter Gemfile* with your private gems for the price being a bit less convenient than answer by @ScottSchulthess.

How Bundler works

There is an array stored in $LOAD_PATH global variable which is a "load path for scripts and binary modules by load or require" (see Ruby docs) and Bundler modifies this array.

If you're developing a gem, $LOAD_PATH it will contain paths to all gems in the system. You can simply write e.g. require "pry" somewhere and pry gem will be loaded properly even if it's not mentioned in gemspec nor Gemfile. You don't have to add it to dependencies. (Of course it has to be already installed with gem install pry.)

A very different strategy Bundler takes when you're developing an application. In such case most of $LOAD_PATH will be removed on require bundler/setup (Rails calls it in config/boot.rb). Only essential paths and those pointing to gems specified in Gemfile.lock will remain there. So if you want to use pry without adding it to Gemfile, you got to append it to $LOAD_PATH before requiring it.

Solution for applications

gems_root = $LOAD_PATH.detect{ |p| %r{/bundler-} =~ p}.sub(%r{/bundler-.*}, "")

additional_gems = {
  "pry" => "pry-0.10.1/lib",
  "pry-rails" => "pry-rails-0.3.2/lib",
}

load_paths = additional_gems.values.map{ |p| File.join gems_root, p }
$LOAD_PATH.unshift *load_paths
additional_gems.keys.each{ |r| require r }

If you're using Rails, then save it in /config/initializers/00_custom_gems.rb and that's all. Outside Rails you additionally need to require it, preferably right after require "bundler/setup":

require "path/to/it" if File.exists? "path/to/it"

Remember to mention this file in .gitignore.

Sometimes proper gem path does not end with /lib but with architecture name. The easiest way to learn it is to add it for a moment to Gemfile and do puts $LOAD_PATH in aforementioned initializer. You can also learn those dirs from gemspec.

Solution for gems

When developing gem, you don't need to enhance $LOAD_PATH, only to require gems you want. If you need custom gems in tests and you're using RSpec, it can be done somewhere in /spec/support.

Another (less sane) idea is to add a file lib/development.rb:

require_relative "my_gem_name"
require "path/to/private/requires" if File.exists? "path/to/private/requires"

and refer to this file instead of to "my_gem_name" in your tests, demo application etc..

Upvotes: 0

Scott Schulthess
Scott Schulthess

Reputation: 2923

One way to do this is to create different evnironments

group :scott do 
end

Then

bundle --with-env=scott

Upvotes: 2

BuGo
BuGo

Reputation: 51

We use this technique. Puth this in your Gemfile:

eval File.read(File.expand_path("Gemfile.personal")) if File.exists?(File.expand_path("Gemfile.personal"))

And then add your personal gems to Gemfile.personal. Of course exclude Gemfile.personal from your version control.

Upvotes: 3

Henry Collingridge
Henry Collingridge

Reputation: 1970

I'm not 100% sure what it is you are trying to achieve, but;

If you just want to specify a number of development-only gems, you can specify a development group that can be excluded from deployments:

group :development do
  gem "ruby-debug"
  gem "interactive-editor"
end

Then on production or test you would do:

bundle install --without development

Upvotes: 1

Related Questions