I’ve created my gem, but can’t require it
Creating gems is easy, all you need is a gemspec:
Gem::Specification.new do |spec| spec.name = 'chubby-bat' spec.version = '0.0.1337' spec.files = [ './lib/chubby_rain.rb', './lib/crack_murphy.rb', ] spec.summary = 'An example gem' spec.author = 'Ben Biddington' end
And then to build it:
$ gem build chubby-bat.gemspec
And then to install it:
$ gem install chubby-bat-0.0.1337.gem
No such file to load — xxx
Trouble is, when requiring the new gem, you may encounter an error like:
irb(main):001:0> require 'chubby-bat' LoadError: no such file to load -- chubby-bat from C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require' from C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require' from (irb):1 irb(main):002:0>
I found this pretty confusing, until I realised the interpreter is looking for a file called chubby-bat.
In short, a gem needs to contain a file with the same name as the gem itself in its lib folder:
And gemspec becomes:
Gem::Specification.new do |spec| spec.name = 'chubby-bat' spec.version = '0.0.1337' spec.files = [ './lib/chubby-bat.rb', './lib/chubby_rain.rb', './lib/crack_murphy.rb', ] spec.summary = 'An example gem' spec.author = 'Ben Biddington' end
The comment in rubygems custom_require explains:
# See: path/to/Ruby/lib/ruby/site_ruby/1.8/rubygems, custom_require ## # When RubyGems is required, Kernel#require is replaced with our own which # is capable of loading gems on demand. # # When you call require 'x', this is what happens: # * If the file can be loaded from the existing Ruby loadpath, it # is. # * Otherwise, installed gems are searched for a file that matches. # If it's found in gem 'y', that gem is activated (added to the # loadpath). # # The normal require functionality of returning false if # that file has already been loaded is preserved.
Ruby loadpath, gem install and Kernel#require
Installing a gem simply copies files to somewhere in $LOAD_PATH, and invoking require triggers a file search within these locations.
Kernel require does the following:
- Ruby tries to load the library named string, returning true if successful.
- If the filename does not resolve to an absolute path, it will be searched for in the directories listed in $:.
- If the file has the extension “.rb’’, it is loaded as a source file; if the extension is “.so’’, “.o’’, or “.dll’’,or whatever the default shared library extension is on the current platform, Ruby loads the shared library as a Ruby extension. Otherwise, Ruby tries adding “.rb’’, “.so’’, and so on to the name.
- The name of the loaded feature is added to the array in $”.
- A feature will not be loaded if it‘s name already appears in $”.
This means if you print out the contents of $”, you’ll see chubby-bat.rb in there.