Is it possible to use 'bundle exec' functionality from code? - ruby

I'm building a web interface to a few tools and I'd like to be able to run commands or gems within a Bundler context, like the 'bundle exec' command does, except from within my code.
So usually, I'd write on the command line:
bundle exec rspec
Is there a way I can achieve the same thing, but programatically?

If you want to run some ruby with bundled gems you can just require "bundler/setup":
require 'bundler/setup'
require 'rspec' # loads the version specified in Gemfile

You can wrap shell commands in backticks (`) in Ruby.
def run_specs
`bundle exec rspec | grep foo`
end

Related

Require files from gem in Ruby script without bundle exec

I have a script that needs to require specific files out of gems defined in the project Gemfile.
#!/usr/bin/env ruby
require 'some_gem/helpers/some_helper'
... rest of script
When I run the script, I get an error about not being able to load some_helper.rb. If I run with bundle exec command... then everything works.
I understand that bundle exec exposes the Gems to the $LOAD_PATH which lets require work. Is there a way to move that capability into the script so users don't have to type bundle exec?
Do I just need to add require "bundler/setup" to the script before I require the gem files?
http://bundler.io/v1.12/#getting-started
:)
#!/usr/bin/env ruby
require 'rubygems' # because reasons.. most probably it is not needed unless you are using really old ruby where it is not loaded by default
# also at the moment rubygems and bundler are being merged :)
require 'bundler/setup' # for things installed with bundler
require 'some_gem/helpers/some_helper'
You can also check e.g. http://mislav.net/2013/01/understanding-binstubs/

Why do I need bundle exec to require this rubygem?

I have a Rails app with some non-Rails-dependent files under `lib/services'. One of these files uses the Domainatrix gem.
require "domainatrix"
class SuggestionParser
# various suggestion parsing methods
end
I have an empty spec for this file under spec/lib.
require "services/suggestion_parser"
describe SuggestionParser do
end
Unfortunately, when I try to run that spec without bundle exec I hit an error:
$: rspec spec/lib/services/suggestion_parser_spec.rb
-> /Users/davidtuite/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:55:in `require': cannot load such file -- domainatrix (LoadError)
Every other spec and gem in my project will run without using bundle exec. Why do I need to prefix this one in order to get it to run?
For convenience, here's a link to the Domainatrix gemspec.
My guess would be that domainatrix is declared using the :path or :git options in the Gemfile, neither of which install the gem in a way that makes it accessible to rubygems.
This could be confirmed if you post the line for domainatrix from the Gemfile.
try running the following commands:
$ rvm get head && rvm reload
$ chmod +x $rvm_path/hooks/after_cd_bundler
$ bundle install --without production --binstubs=./bundler_stubs
This won't solve the specific problem with your gem, but it will take away the necessity to type in bundle exec every time you run your tests if you're using rvm.

How to run a ruby script within bundler context?

I have a Ruby script called foo.rb, and I want to run it within the context of the bundler environment. How?
bundle exec foo.rb doesn't work, because exec expects a shell script.
Pass the script name to the ruby command:
bundle exec ruby script_name
If you also want the Rails environment:
bundle exec rails runner script_name
For instance, I wanted to use the same version of Rubocop as my Rails app and not the latest system one, so doing this in a script:
require 'bundler'
Bundler.require
# ...
Allowed me to use my app's version of rubocop.
You can just make it a script - add
#!/usr/bin/env ruby
to the start of the file, and make it executable. Then bundle exec foo.rb will work as expected.
(This is on unix or OSX - not sure about Windows)
See http://bundler.io/v1.15/man/bundle-exec.1.html#Loading
Also see https://coderwall.com/p/kfyzcw/execute-ruby-scripts-directly-without-bundler-exec for how to run ruby scripts with bundled dependencies, without needing bundle exec
If you want to create a script that you can run in bundle context within a project, you can invoke Bundler programmatically. E.g., given a project:
foo
├── Gemfile
└── bar
└── baz.rb
you can put the following at the top of baz.rb to give it access to the gems in the Gemfile:
#!/usr/bin/env ruby
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup'
# ...etc.
With that, you can invoke the script directly without using bundle exec, and you also don't have to invoke it from within the project directory.

deploy rake task as if it were a common script

I like the rake task structure and rake utilities.. I want to create a script that can do many things, and rake seems the logical choice.
I want to know how can I make it look like a regular script:
./myscript.rb cake:bake
as opposed to
rake -f myscript.rb cake:bake
any idea? Of course, rake must still be installed etc.. simply to make it easier to use...
myscript.rb:
#!/usr/bin/ruby
require 'rubygems'
require 'rake'
namespace :cake do
task :bake do
puts "Baking cake..."
end
end
Rake::Task[ARGV.first].execute
Then on the command line:
chmod +x myscript.rb
./myscript.rb cake:bake
I found this for cygwin / windows
http://errtheblog.com/posts/60-sake-bomb
removes the dependency on rails and let's you have rake tasks installed and available globally

How can I write a hook that gets called when a RubyGem is installed?

I'd like to write a Ruby snippet that gets run when my Gem is first installed via [sudo ]gem install mygem. Can it be done?
It doesn't look like it's really supported. I found a "post_install_message" attribute that you should be able to set in the gem spec, but that won't execute code.
You may be able to do it by packaging your on-install code as an extension in your gem (as if it were a native extension), and providing a Rakefile to "build" the extension (i.e. call your code).
I had the same problem. The best solution that I found is as follows:
# your_gem.gemspec
Gem::Specification.new do |spec|
# ...
spec.extensions = ['Rakefile']
end
-
# Rakefile
task :prepare do
# Execute your post-installation code here
end
task default: :prepare
You can try to do this using call of OS commands. I'll quote eample from irb but you can do same in your scripts too.
irb(main):001:0> system 'gem list | grep rails'
rails (2.1.1, 2.1.0)
=> true
irb(main):002:0> system 'gem list | grep railssssss'
=> false
You can use result of this command as the condition of your snippet execution.

Resources