Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Making "require" just work with some dynamic load path manipulation

Reply
Thread Tools

Making "require" just work with some dynamic load path manipulation

 
 
Greg Hurrell
Guest
Posts: n/a
 
      03-07-2007
The problem:

If I have a simple file, "a.rb":

#!/usr/bin/env ruby
require 'b'

And it's companion, "b.rb":

puts "Hello, world!"

Running "a.rb" works fine if I start from the directory containing
those files. If I change to another directory, however, I get a
LoadError because Ruby doesn't know how to find "b.rb".

Workarounds:

1. Set or modify the RUBYLIB environment variable so that Ruby knows
which additional locations to search.
2. Manipulate the load path ($ from within the program itself.

These workarounds are fine for me because I understand the quirks of
Ruby's load path. But I am looking for a way to make this stuff just
work automatically for other users who don't necessarily understand
Ruby's load path and will expect "a" to be able to find "b" because
they're in the same directory, no matter what the current working
directory is at the time.

The solution:

So I already have a solution for this based on workaround "2" and I
wanted to get some feedback on whether this is a good idea or not. The
basic idea is to make a "custom_require" method which does the
following:

1. Try requiring the file normally.
2. On a LoadError, try adding the directory containing the file to the
load path (only if it's not already present).
3. Now try requiring it again.
4. If you get a second LoadError then put the load path back the way
it was and re-raise the original error.
5. If you succeed then put the load path back the way it was anyway.

So here's the basic code to do this. I try to make it as conservative
as possible by making the modifications to the load path temporary,
and always adding absolute paths so as to minimize the likelihood of
the same file being evaluated twice. The security of dynamically
modifying the load path is not really a concern because the users
running this scripts already have full write access to them anyway and
can therefore already do whatever they want, and they (and nobody
else) have full control over the directories in which the scripts are
stored.

To use the new method you would do:

custom_require 'b', __FILE__

The second parameter is necessary (as far as I can tell) because I
know of no other clean way for the "custom_require" method (itself in
a different file) to know which file was being evaluated when the call
to "custom_require" was made.

What I'd like to know is, is there a better way?

def custom_require(file, fallback)
begin
require file
rescue LoadError => e
candidate = Pathname.new(fallback).dirname.realpath
if $:.any? { |path| Pathname.new(path).realpath == candidate
rescue false }
raise e
else
begin
$:.push(candidate)
status = require file
rescue LoadError
raise e
ensure
$:.pop
status
end
end
end
end

 
Reply With Quote
 
 
 
 
Trans
Guest
Posts: n/a
 
      03-07-2007
Is there a reason you are not using setup.rb and/or gems?

T.


 
Reply With Quote
 
 
 
 
Greg Hurrell
Guest
Posts: n/a
 
      03-08-2007
On 7 mar, 22:01, "Trans" <(E-Mail Removed)> wrote:
> Is there a reason you are not using setup.rb and/or gems?
>
> T.


Neither of those is really appropriate because the files "a.rb" and
"b.rb" are dynamically generated and probably not very long lived (the
typical cycle will be: generate, use, throw away) and definitely not
worth installing permanently. The thing that generates those files is
actually distributed as a gem so there are no problems at that level;
I just want the generated files to be as easy to use for end users as
possible.

Cheers,
Greg

 
Reply With Quote
 
Ezra Zygmuntowicz
Guest
Posts: n/a
 
      03-08-2007

On Mar 7, 2007, at 6:00 PM, Greg Hurrell wrote:

> On 7 mar, 22:01, "Trans" <(E-Mail Removed)> wrote:
>> Is there a reason you are not using setup.rb and/or gems?
>>
>> T.

>
> Neither of those is really appropriate because the files "a.rb" and
> "b.rb" are dynamically generated and probably not very long lived (the
> typical cycle will be: generate, use, throw away) and definitely not
> worth installing permanently. The thing that generates those files is
> actually distributed as a gem so there are no problems at that level;
> I just want the generated files to be as easy to use for end users as
> possible.
>
> Cheers,
> Greg



IF you want to garauntee to require b in the same dir as a you can
do this:

# a.rb
puts "in a.rb"
require File.join(FIle.dirname(__FILE__), 'b')

# b.rb
puts "in b.rb"

Cheers-

-- Ezra Zygmuntowicz
-- Lead Rails Evangelist
-- http://www.velocityreviews.com/forums/(E-Mail Removed)
-- Engine Yard, Serious Rails Hosting
-- (866) 518-YARD (9273)



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
FileUpload control doesn't work (fail in client side early stages) when path is relative i.e "\\path.." Oren ASP .Net 1 04-29-2007 04:20 PM
Windows/X-plaiform file path manipulation -- how do you deal with it? Graham Wideman Ruby 3 09-02-2006 10:18 AM
AS-Path Manipulation ryanfinnerty@hotmail.com Cisco 6 04-07-2006 08:11 AM
Two Browsers work! Two browsers won't load. Internet game service won't load jimmie Computer Support 1 02-26-2006 08:36 AM
Compiling when libedit is in path Is there a trick to compiling Ruby when libedit must exist in the search path? Can you statically link to readline 5.0 in some manner? -- Lon Baker Lon Baker Ruby 1 03-21-2005 08:57 AM



Advertisments