Last active
December 18, 2015 13:59
-
-
Save tommeier/5794153 to your computer and use it in GitHub Desktop.
Append a gem dependency on installation of gem (example: RubyWMQ). The example being the dependency can only installed on deployed systems, and unable to install on development systems (ie: WMQ and developing on Mac)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rubygems' | |
require 'bundler' | |
Bundler.module_eval do | |
def self.append_gem(gem_name, options = {}) | |
return if gem_already_loaded?(gem_name, options[:version]) | |
version = options[:version] || '*' | |
spec_path = Dir.glob("#{Gem.dir}/specifications/#{gem_name}-#{version}.gemspec").last | |
if spec_path.nil? | |
warn "Couldn't find #{gem_name}@version:#{version}" | |
return | |
end | |
spec = Gem::Specification.load spec_path | |
spec.activate | |
begin | |
Kernel.require options[:require] || gem_name | |
yield if block_given? | |
rescue Exception => err | |
warn "Couldn't load #{gem_name}: #{err}" | |
end | |
end | |
def self.gem_already_loaded?(gem_name, version = nil) | |
spec = Gem.loaded_specs[gem_name] | |
version ? spec && spec.version == version : !!spec | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
describe Bundler do | |
describe "#gem_already_loaded?" do | |
let(:loaded_specs) { {} } | |
before do | |
Gem.stub(:loaded_specs) { loaded_specs } | |
end | |
context 'versioning' do | |
let(:loaded_specs) { | |
{ | |
'my_test' => mock('Gem::Specification', name: 'my_test', version: '0.0.5'), | |
'test_gem' => mock('Gem::Specification', name: 'test_gem', version: '1.2.3'), | |
'another_gem' => mock('Gem::Specification', name: 'another_gem', version: '1.2.4') | |
} | |
} | |
context "with specific version" do | |
it 'should return true when already loaded' do | |
Bundler.gem_already_loaded?('test_gem', '1.2.3').should be_true | |
end | |
it 'should return false when not loaded' do | |
Bundler.gem_already_loaded?('test_gem', '1.2.4').should be_false | |
end | |
end | |
context "with no specific version" do | |
it 'should return true when already loaded' do | |
Bundler.gem_already_loaded?('test_gem').should be_true | |
end | |
it 'should return false when not loaded' do | |
Bundler.gem_already_loaded?('unknown_gem').should be_false | |
end | |
end | |
end | |
end | |
describe "#append_gem" do | |
let(:gem_name) { 'test_gem_name' } | |
let(:gem_path) { '/some/file/location/test_gem_name-0.01.gem' } | |
let(:spec_path) { double('gem_spec', :activate => true) } | |
let(:options) { {} } | |
context 'with a single call' do | |
context 'cannot find a gem' do | |
before do | |
Dir.stub(:glob) { mock('ReturnedFileArray', :last => nil) } | |
end | |
context "with no version set" do | |
it 'should return nothing and make warning' do | |
Bundler.should_receive(:warn).with("Couldn't find #{gem_name}@version:*").once | |
end | |
end | |
context "with version info" do | |
let(:options) { {version: '1.2.3'} } | |
it 'should return nothing and make warning with version info' do | |
Bundler.should_receive(:warn).with("Couldn't find #{gem_name}@version:1.2.3").once | |
end | |
end | |
end | |
context "with a found gem" do | |
before do | |
Dir.stub(:glob) { mock('ReturnedFileArray', :last => gem_path) } | |
Gem.stub(:loaded_specs) { {} } | |
Gem::Specification.stub(:load) { spec_path } | |
end | |
context 'fail to load' do | |
it 'warns when loading' do | |
Kernel.stub(:require).and_raise(StandardError.new('Gem unable to load')) | |
Bundler.should_receive(:warn).with("Couldn't load #{gem_name}: Gem unable to load").once | |
end | |
end | |
context 'loading' do | |
it 'successfully loads and requires gem' do | |
Kernel.should_receive(:require).with(gem_name) { true } | |
end | |
it 'should return nothing if it is already loaded' do | |
Gem.stub(:loaded_specs) { { gem_name => double('Gem::Specification') } } | |
Kernel.should_not_receive(:require).with(gem_name) | |
Bundler.should_not_receive(:warn) | |
end | |
end | |
end | |
after do | |
Bundler.append_gem(gem_name, options) | |
end | |
end | |
context 'with optional require statement' do | |
before do | |
Dir.stub(:glob) { mock('ReturnedFileArray', :last => gem_path) } | |
Gem::Specification.stub(:load) { spec_path } | |
end | |
it 'should require a different name to the gem' do | |
Kernel.should_receive(:require).with('some_different_name') { true } | |
Bundler.append_gem(gem_name, :require => 'some_different_name') | |
end | |
end | |
context 'version specification' do | |
let(:root_path) { '/some/gem/location' } | |
let(:spec_path) { mock('GemSpecPath', last: "#{root_path}/#{gem_name}-1.2.3", activate: true )} | |
before do | |
Kernel.should_receive(:require).with(gem_name) { true } | |
end | |
context "with no version set" do | |
let(:options) {{}} | |
it 'should search for all versions of that gem' do | |
Dir.should_receive(:glob).with("#{Gem.dir}/specifications/#{gem_name}-*.gemspec").once { spec_path } | |
Gem::Specification.should_receive(:load).with(spec_path.last) { spec_path } | |
end | |
end | |
context "with specific version set" do | |
let(:options) {{ version: '1.2.3' }} | |
it 'should search and load the specific version of the gem' do | |
Dir.should_receive(:glob).with("#{Gem.dir}/specifications/#{gem_name}-1.2.3.gemspec").once { spec_path } | |
Gem::Specification.should_receive(:load).with(spec_path.last) { spec_path } | |
end | |
end | |
after do | |
Bundler.append_gem(gem_name, options) | |
end | |
end | |
context 'with an optional block' do | |
let(:passed_object_mock) { mock('SomeKlass') } | |
before do | |
Dir.stub(:glob) { mock('ReturnedFileArray', :last => gem_path) } | |
Gem::Specification.stub(:load) { spec_path } | |
Kernel.should_receive(:require).with(gem_name) { true } | |
end | |
it 'should yield any passed block' do | |
passed_object_mock.should_receive(:trigger_event).once { true } | |
Bundler.append_gem(gem_name) do | |
passed_object_mock.trigger_event | |
end | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- encoding: utf-8 -*- | |
lib = File.expand_path('../lib', __FILE__) | |
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) | |
Gem::Specification.new do |gem| | |
... | |
gem.extensions = ['ext/mkrf_conf.rb'] | |
... | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rubygems' | |
require 'rubygems/command.rb' | |
require 'rubygems/dependency.rb' | |
require 'rubygems/dependency_installer.rb' | |
def gem_cached?(gem_name, gem_version, dependency_options = {}) | |
Dir.chdir(File.join(Gem.dir, 'cache')) do | |
found_locally = Gem::DependencyInstaller.new(dependency_options).find_spec_by_name_and_version(gem_name, gem_version) | |
found_locally.any? { |gem_spec_array| gem_spec_array.first.version.to_s == gem_version.to_s } | |
end | |
rescue Gem::GemNotFoundException | |
false | |
end | |
def already_cached_locally?(gem_name, gem_version) | |
gem_cached?(gem_name, gem_version, {domain: :local}) || gem_cached?(gem_name, gem_version, {domain: :local, prerelease: true}) | |
end | |
def gem_required? | |
ENV['SKIP_GEM_APPEND'].nil? && RUBY_PLATFORM =~ /linux|mswin|windows|sunos|solaris/i | |
end | |
def print_out(output) | |
STDOUT.puts "[Appending Gem] #{output}" | |
end | |
begin | |
Gem::Command.build_args = ARGV | |
rescue NoMethodError | |
end | |
append_gem_name = 'example_gem' | |
append_gem_version = '2.0.4' | |
begin | |
dep = Gem::Dependency.new(append_gem_name, append_gem_version) | |
print_out "Installing Gem : #{dep.name} @ #{dep.requirement}" | |
inst = Gem::DependencyInstaller.new | |
inst.install dep | |
print_out "Gem Installed" | |
begin | |
#Initialise and activate correct version | |
gem dep.name, dep.requirement | |
require 'example_gem' | |
rescue LoadError | |
print_out "Error loading Gem (require 'example_gem')." | |
end | |
rescue Exception => e | |
print_out e | |
print_out e.backtrace.join "\n " | |
exit(1) | |
end if gem_required? && !already_cached_locally?(append_gem_name, append_gem_version) | |
f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w") # create dummy rakefile to indicate success | |
f.write("task :default\n") | |
f.close |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment