Have you ever wanted to use Bundler’s internals in your codebase? Here is how how to start by creating your Gemfile.lock, locking the environment and reading back the locked dependencies.
Creating Gemfile
Creating Gemfile is nothing harder than creating a regular file called Gemfile
. Bundler creates Gemfile only through the CLI, which is probably not ideal for direct use from your code, but if you are wondering, here’s how to do it:
irb(main):001:0> require 'bundler/cli'
=> false
irb(main):002:0> require 'bundler/cli/init'
=> true
irb(main):003:0> Bundler::CLI::Init.new({ gemspec: 'actionmailer.gemspec' }).run
Writing new Gemfile to /home/strzibny/tmp/Gemfile
=> #
This creates a Gemfile based on .gemspec
. Specifying no options will simply create a blank Gemfile. A better way how to do it is to use simple Ruby directly:
require 'rubygems'
require 'bundler'
spec = Gem::Specification.load('actionmailer.gemspec')
File.open('Gemfile', 'wb') do |file|
file << "# Generated from #{gemspec}\n"
file << spec.to_gemfile
end
Gem::Specification.load
comes from RubyGems, but the #to_gemfile
method is added by Bundler, therefore the Bundler requirement. Also note that you probably want to mention RubyGems.org as a source and not :gemcutter
in your Gemfile.
Creating Gemfile.lock and installing dependencies
Once we have our Gemfile, we can create Gemfile.lock. This is essentially bundle install
.
require 'bundler'
gemfile = 'Gemfile'
definition = Bundler::Definition.build(gemfile, "#{gemfile}.lock", false)
Bundler::Installer.install('.', definition, { "local" => true })
Gemfile.lock
is here an empty file, but can be existing one as well. The third parameter of Bundler::Definition.build
method is called unlock
. This defines whether some gems should be updated or not. You can pass it a hash of gems to update or set it to true
if all gems should be updated.
Bundler::Installer.install
then creates our new Gemfile.lock
after it installs required gems and their dependencies. As you can see the first argument is a directory path and we can also pass some additional options such as --local
(this will use already installed gems only).
Locking the dependencies with bundle exec
Locking down the dependencies can be done easily by Bundler.setup
and you can also specify a certain groups from your Gemfile.lock:
require 'bundler'
begin
Bundler.setup(:default, :my_group)
# What if we don't have some gems installed?
rescue Bundler::GemNotFound
end
But remember! Bundler handles $LOAD_PATH
for you, but can’t change $LOADED_FEATURES
– the code that you required before running Bundler.setup
is already in memory and not going away!
Alternatively you can just require 'bundler/setup'
.
Reading the Gemfile.lock
If you want to get the dependencies out of Gemfile.lock, perhaps to recreate the Gemfile, you can use Bundler’s LockfileParser
:
require 'bundler'
gemfile_lock = Bundler::LockfileParser.new(Bundler.read_file("Gemfile.lock"))
# To get the specification objects
gemfile_lock.specs
So, that was the basics on how to start with Bundler from your Ruby scripts and programs. Read more in the documentation.