gem install bundler
is much to ask for on freshly set up operating system or from an unexperienced user. Founder will on-the-fly download and run bundler so that your code gets all dependencies it needs.
That means git clone
and bin/yourexecutable
is all your end-users need to know.
Founder was created for the following use case:
-
You created a CLI tool written in Ruby and you want to share it with the world.
-
Your code has a Gemfile and depends on some gems.
-
You expect someone to be able to clone your repository and run the executable.
In other words, you want to create an out-of-the-box experience running your tool (for non-Rubyist and on pristine operating systems).
Good examples are running chef, dotfiles or similar bootstrapping kind of scripts on unprepared machines.
When someone wants to use your code, they'd first have to run gem install bundler
and bundle install
.
Unfortunately, that's doomed to fail on most operating systems (I won't go into the details why).
macOS: ERROR: While executing gem ... (Gem::FilePermissionError)
Debian/Ubuntu: -bash: bundle: command not found
That's dissatisfactory and, in the worst case, leaves a bad impression for both Ruby and your tool.
Ruby ships with the operating system, it's just not at your finger tips in the shell.
Programmatically, you could download bundler and use it to download your gem dependencies.
That's what Founder intends to do for you under the hood:
-
Given the basic Ruby interpreter, a gem can be downloaded using
Gem::Commands::InstallCommand
, that's how we obtain the Bundler gem. -
Once Bundler is available, we use
Bundler::CLI
to process yourGemfile
and download all relevant gems. -
Using
Bundler.setup
these gems will be added to your$LOAD_PATH
.
If you're targeting experienced Ruby users, who already have Ruby set up properly and installed the Bundler gem, you wouldn't need Founder.
But if you target a wider audience, you should use a Ruby interpreter that exists on the target system, such as #!/usr/bin/ruby
You won't have a cutting edge version, but most likely
That should be good enough for most use cases. Founder itself is tested on Ruby 2.3.3
.
-
Copy-and-paste the file
founder.rb
into yourlib
directory.It doesn't have to be the
lib
directory, but that's ususally where your Ruby code goes. You'll always find the latest version offounder.rb
in this Github repository. -
Create a
Gemfile
andGemfile.lock
in the usual way.I strongly recommend placing both of them into a subdirectoy
vendor
, because all the gems will be downloaded into the same directory where theGemfile
is located. By default, Founder looks it invendor/Gemfile
.
-
require 'founder'
This is assuming that your executable set up the
$LOAD_PATH
in a way thatfounder.rb
can be required via yourlib
directory. You might userequire_relative
instead. -
Run
Founder.install
This will download all gems specified in the
Gemfile
and append them to your$LOAD_PATH
. -
Now you can
require
any gem you specified in yourGemfile
.That means that you now can continue your code execution as usual, now having all relevant gems at your disposal.
Before running Founder.install
you might want to configure its behavior:
Founder.configure do |config|
# The full path to the Gemfile (and Gemfile.lock).
# Defaults to `../vendor/Gemfile` relative to `founder.rb` like so:
config.gemfile_path = ::File.expand_path('../vendor/Gemfile', __dir__)
# Where all gems will be installed to.
# Defaults to `../vendor` relative to `founder.rb` like so:
config.download_path = config.gemfile_path.parent
# Which version of Bundler to download.
# Defaults to something recent.
config.bundler_version = '2.0.1'
# Whether or not to show extra logging output.
# Defaults to true if `--debug` or DEBUG=1 is provided.
config.debug = ARGV.dup.delete('--debug') || ENV['DEBUG']
# Which logger to use.
# Defaults to `/dev/null`.
# Defaults to `STDOUT` if `config.debug` is true.
config.logger = config.debug ? ::Logger.new($stdout) : ::Logger.new('/dev/null')
end
Founder.install
downloads bundler, installs the gems, and adds them to your load path. All in one go.
You can use Founder.download
to only download bundler and the specified gems. You can then run Founder.setup
to add them to your load path.
Eventually RubyGems and Bundler will become one and recent versions of Ruby already include Bundler. That will make things a lot easier, but until then, it's useful to resort to Founder.
MIT (see header in founder.rb
)