Hakanai
Hakanai

Reputation: 12728

Bundler.require doesn't require dependencies which are in the gemspec

I have an application using bundler which works fine at the moment but I have to run it out of the project's bin directory. Now I'm trying to convert it to a gem.

bin/myexecutable (no changes):

#!/usr/bin/env ruby
require 'mygem'
MyGem::MyExecutable.new.main(ARGV)

lib/mygem.rb (no changes):

require 'rubygems'
require 'bundler/setup'
Bundler.require

require 'mygem/version'
require 'mygem/my_executable'

mygem.gemspec (new):

# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'mygem/version'

Gem::Specification.new do |spec|
  # ... omitting boilerplate specs of gem ...

  spec.files         = `git ls-files`.split($/)
  spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
  spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
  spec.require_paths = ['lib']

  spec.add_development_dependency 'bundler', '~> 1.3'
  spec.add_development_dependency 'rake'

  spec.add_runtime_dependency 'bindata'
end

Gemfile (moved dependencies to mygem.gemspec):

source 'https://rubygems.org'
gemspec

When I install the gem and attempt to run the executable, I get:

.../resource_file.rb:2:in `<class:ResourceFile>': uninitialized constant ResourceFile::BinData (NameError)

Copying the dependencies back to Gemfile makes it work again, but now I have redundant declarations of the same dependencies in two locations.

Why doesn't it work when using the gemspec declaration?

Upvotes: 4

Views: 1648

Answers (1)

Tim Moore
Tim Moore

Reputation: 9492

You need to call require 'bindata' at the top of lib/mygem.rb.

In addition, I recommend removing these lines from mygem.rb:

require 'rubygems'
require 'bundler/setup'
Bundler.require

Bundler expects that gems require their own dependencies (so that they still work when you require them without Bundler, too). When you have gemspec in your Gemfile, Bundler.require directly requires your gem, but not any of its dependencies. Putting that into a gem will cause it to interact poorly with apps that already use Bundler, and creates a runtime dependency from your gem to Bundler (which is not declared in your gemspec).

This is intentional behavior. There is some discussion on these Bundler issues:

Upvotes: 4

Related Questions