Require, from within lib, files located under the local path

Hi.

Here’s an issue I’ve not been able to solve for some time now.

Let’s say I designed a tiny library, following a standard structure:

$ tree
.
|-- LICENSE
|-- README.md
|-- Rakefile
|-- VERSION
|-- lib
| |-- mylib
| | -- core.rb |– metamorphosis.rb
|-- metamorphosis.gemspec
`-- test

Using Jeweler to build and install the gem (successfully), it goes into
(for instance): home/YOU/.rvm/gems/ruby-1.9.1-p378/gems/mylib-0.1.0/

The purpose of mylib involves allowing the user who will eventually
perform a require ‘mylib’, to create, along the file.rb performing the
require, a folder (let’s call it mylib_stuff). So the user sets up the
following structure:

$ tree
.
|-- main.rb
-- mylib_stuff |-- a_piece_of stuff.rb |-- ...– another_piece_of_stuff.rb

The core.rb file needs to use what’s inside mylib_stuff/*. Using the
standard technique: require File.expand_path("…/…/mylib_stuff",
FILE), you end up with the following error: no such file to load –
/home/YOU/.rvm/gems/ruby-1.9.1-p378/gems/mylib-0.1.0/mylib_stuff/[foobar]

That’s because FILE is core.rb. So what I’d like to do is passing
require a path which would be aware of the location the gem mylib is
used from, so it’ll access this particular path. Another script using
mylib would trigger different require statements in core.rb, involving
it’s very own mylib_stuff local directory.

Thank you!

s/along the file.rb/along the main.rb/

Ok so here’s what I eventually did:

require ‘pathname’ # I love it :slight_smile:
module MyLib
def self.extended base #:nodoc:
# the receiver is the extended module or class
@receiver = base

# paths of the receiver file and receiver stuff
@base_path  = Pathname.new(File.expand_path($0)).dirname
@stuff_path = @base_path + "mylib_stuff"

# ... do whatever with base and the paths

end

end

I don’t know if this practice of relying on $0 is solid, though.
Any hint?

Jean-denis Vauguet wrote:

I don’t know if this practice of relying on $0 is solid, though.

It’s very risky:

  • on many platforms it’s truncated
  • the script which the user started running isn’t necessarily the file
    which is requiring your code

I suggest you look at Kernel#caller instead.

Unfortunately it just gives you strings which you have to parse
yourself, and you’ll probably need to grep out all the rubygems-related
paths.

For an example, look in the sinatra gem (lib/sinatra/base.rb,
specifically methods caller_locations and caller_files). Sinatra uses
this to locate the application source code, for reading inline
templates.

Brian C. wrote:

I suggest you look at Kernel#caller instead.

Unfortunately it just gives you strings which you have to parse
yourself, and you’ll probably need to grep out all the rubygems-related
paths.

For an example, look in the sinatra gem (lib/sinatra/base.rb,
specifically methods caller_locations and caller_files). Sinatra uses
this to locate the application source code, for reading inline
templates.

Thank you so much :slight_smile: