Ben Biddington

Whatever it is, it's not about "coding"

I’ve created my gem, but can’t require it

with one comment

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

Rubygems require

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.

Advertisements

Written by benbiddington

12 January, 2010 at 13:37

Posted in development

Tagged with , , , ,

One Response

Subscribe to comments with RSS.

  1. Thanks! Stumbled upon this for a while….. Thought I had messed up my rvm env but this explains my confusion clearly!

    Fredrik Rubensson (@froderik)

    6 September, 2011 at 08:25


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: