On Fri, 4 May 2007, George wrote:

> On 5/4/07, Hugh Sasse <hgs / dmu.ac.uk> wrote:
> > I'm trying to debug a Rails application which complains about an
> > undefined constant when `rake db:migrate` is invoked.  The rakefile
> > that comes with rails modifies $:, then does several more requires.
> > Given the length of $: it is tedious to find which files are
> > require`d.   Clearly this is not a rails specific difficulty: it is
> > common to understanding anyone's code making sufficiently extensive
> > use of require.  So my question is this:
> > Would it be practical to modify require so that it accepts a block,
> > to which it would pass the path of the object it successfully
> > require`d?  Then, to find the files I must read to understand what
> > is happening I could change
> > 
> > -  require 'tasks/rails'
> > +  require 'tasks/rails' {|path| $stderr.puts "require`d #{path]"}
> > 
> 
> Hi Hugh,
> 
> A rudimentary lookup isn't too much more work, is it?
> 
>  $stderr.puts $:.find{|path| File.exist? "#{path}/tasks/rails.rb"}

No, not too much work (even though it's not just that tasks/rails.rb):


module Kernel
  alias :old_require :require
  def require(f)
    if old_require(f)
      path = $:.find do |p|
        pf = File.join(p,f)
        File.exist?(pf)
      end
      if path
        pf = File.join(path,f)
        puts "require`d #{pf}"
      end
    end
  end
end

is what I have come up with so far.  But I've not addressed
subtleties like the ability to require ".rb" and ".so" files, and
platform specific variations of the above.  And I'm sure there are
plenty of ways to botch implementing that.  And coding it myself repeats
a search the system has already done.

In fact I've just found another bug in my code above: it doesn't
actually return the value returned by the original require.

> Particularly if you wrap it around #require and keep it as a debugging
> method somewhere.
> 
> Your proposal strikes me as a rather arbitrary use of a block.  I

That's the point of blocks, isn't it?  You can use them for what you
like.  require doesn't take one now, so existing code won't break.
methods given a block that don't actually take one ignore it.  Blast!
Irb says this isn't true for require:

irb(main):005:0> def interrogate
irb(main):006:1> end
=> nil
irb(main):007:0> interrogate {|x| print "What do you want to drink?!?!"}
=> nil
irb(main):008:0> require "footlewuddlewix" {|x| puts "got #{x}" }
SyntaxError: compile error
(irb):8: syntax error, unexpected '{', expecting $end
require "footlewuddlewix" {|x| puts "got #{x}" }
                           ^
        from (irb):8
        from :0
irb(main):009:0> 

so new code won't slip past old ruby implementations unseen.

> might expect it to be run in the event that the require fails, for

No, if require fails it raises an exception:

irb(main):003:0> require "footlewuddlewix"
LoadError: no such file to load -- footlewuddlewix
        from (irb):3:in `require'
        from (irb):3
        from :0
irb(main):004:0>

which is already handled in many programs perfectly well.

> example, or for something to be done after the block finishes.  It
> doesn't have my vote just yet (for the little that's worth :-).

Also require just takes a string, can occur anywhere in the code, so 
all sorts of machinations could go on besides altering $: before something
is hunted down.
> 
> Regards,
> George.
> 
r> 
        Hugh