# Where the Required Things Are (#175)

**URL:** <https://www.ruby-forum.com/t/where-the-required-things-are-175/147714>\
**Category:** Ruby\
**Created:** [September 4, 2008, 3:51pm UTC](https://www.ruby-forum.com/t/where-the-required-things-are-175/147714 "2008-09-04T15:51:20Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![mansfiem](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/fbc32d/32.png) [@mansfiem](https://www.ruby-forum.com/u/mansfiem)\
**Post date:** [September 4, 2008, 3:51pm UTC](https://www.ruby-forum.com/t/where-the-required-things-are-175/147714/1 "2008-09-04T15:51:20Z")

</div>

Great job on this quiz, everyone who submitted. I know I’ll be adding  
at least one of these submissions to my toolbox.

Ten solutions were provided this week. I downloaded them all and  
tested each one in the manner requested in the extra credit. (For  
anyone who did not attempt the extra credit, make sure to look at the  
other solutions; adding this capability is only a small amount of  
extra code.) To test, I used the sample file provided by Michal  
Suchanek, shown here.

```
require 'date'
require 'readline'
require 'matrix'
require 'rubygems'
require 'time'
require 'hpricot'
require 'rubyforge'
require 'hoe'
require 'curses'

```

I made all modules were installed before testing. (Actually, some  
tests were done with missing modules, with mostly expected results. In  
the end, it was more interesting to see which solutions worked with a  
set of requires that did exist.) A more extensive set of tests would  
be appropriate to bullet-proof any solutions, but this is sufficient  
for this quiz.

Ten solutions were provided from nine users (Suchanek providing two  
solutions). Of those ten, three failed with errors (Shelly, Stevens,  
Suchanek #2). Two solutions stumbled a bit when rubygems got involved.  
The first (Bilkovich) failed to find any of the gems: `hpricot`,  
`rubyforge` and `hoe`. The second (Reitinger) found `rubygems` but  
failed on the next (non-gem) require, `time`; since `rubygems` does  
its own thing to `require`, this is a possible source of problems to  
be addressed.

It’s possible these problems might be caused by platform differences;  
I am running ruby 1.8.6 (MacPorts install) on Mac OS X 10.4.11. I  
didn’t have time to dig into these errors, but if you care to know the  
specific error, let me know.

The next problem I found was that three solutions (Morin, Phillips,  
Wille) did not report the locations of the `readline` and `etc`  
modules. The likely cause here is, again, platform differences. These  
two modules in Mac OS X are “.bundle” files. One solution (Wille)  
reported the modules as not found, while the other two (Morin,  
Phillips) simply reported nothing for those two modules.

Interestingly, the “cheat” provided by Wille, `gem which`, was also  
unable to locate `readline` and `etc`.

That leaves us with two “winners” for this week: _Jesse M._ and  
_Michal S._ (his first solution). Both solutions found all the  
required modules, recursively, including the .bundle files, and didn’t  
get confused by `rubygems`. I’m going to look here at Jesse’s  
solution.

```
module Kernel
  alias :require_orig :require

  def require mod
    if success = require_orig(mod)
      file = $".last

      $:.each do |dir|
        path = "#{dir}/#{file}"
        if File.readable?(path)
          puts "require #{mod} => #{path}"
          break
        end
      end
    end

    success
  end
end

```

`require` is a `Kernel` method, so the first thing Jesse does is open  
the `Kernel` module and keep track of the original `require` method  
via an alias. Next, the new `require` method is defined, and the first  
thing it does is to call the original method, which is why the alias  
was needed.

There are three possible results. First, if `require_orig` throws an  
exception… well, nothing gets done here. The exception throws out of  
this method, reproducing the standard behavior. Second, if  
`require_orig` returns false (and sets `success` accordingly), the the  
body is skipped and false is returned. Again, standard behavior has  
been maintained. The good stuff is what happens when `require_orig`  
returns true.

Jesse makes use of two predefined global variables. `$"` is an array  
containing module names loaded by `require`; calling `last` on that  
array gets the most recently loaded module. `$:` is also an array, but  
contains the search paths for modules.

So once a file is successfully loaded via a call to `require_orig`,  
Jesse checks through the module search paths, and builds a full path  
for the loaded module, checking that path against `File.readable?`. If  
so, the information is printed to standard output and the loop ends.

Finally, most of you should recognize the standard technique for  
knowing when a script is run rather than loaded via `require`:

```
if __FILE__ == $0
  ARGV.each { |mod| require mod }
end

```

Make sure to look at Michal S.'s solution as well. The use of  
module `rbconfig` and method binding were new to me.

One final note: my machine is running Mac OS X, so of course, all my  
testing has been using that. This has two implications: some programs  
may not have worked (pehaps some that I mentioned above), and also  
that the two “complete” solutions (Merriman, Suchanek) could quite  
possibly be broken on other platforms. I don’t know. (I’m a bit  
occupied this week.🙂 A 100% solid solution should account for all  
these things.

---

<div class="post-metadata">

**Author:** ![mansfiem](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/fbc32d/32.png) [@mansfiem](https://www.ruby-forum.com/u/mansfiem)\
**Post date:** [September 4, 2008, 4:03pm UTC](https://www.ruby-forum.com/t/where-the-required-things-are-175/147714/2 "2008-09-04T16:03:04Z")

</div>

hi matthew!

thanks for the fun quiz 🙂

Matthew M. [2008-09-04 15:45]:

> Interestingly, the “cheat” provided by Wille, `gem which`, was  
> also unable to locate `readline` and `etc`.  
> well, it does on my machine. which is why i added it as a  
> “fallback”. the problem with my approach is that SCRIPT\_LINES\_\_  
> doesn’t include binary files (.so, .bundle, …).

~/devel/scratch [git:master@60eb300]\> ruby -rmodwhich.rb -e ‘require  
“readline”; require “etc”’  
require ‘readline’ =\> /usr/lib/ruby/1.8/x86\_64-linux/readline.so  
require ‘fileutils’ =\> /usr/lib/ruby/1.8/fileutils.rb  
require ‘etc’ =\> /usr/lib/ruby/1.8/x86\_64-linux/etc.so

cheers  
jens

---

<div class="post-metadata">

**Author:** ![mansfiem](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/fbc32d/32.png) [@mansfiem](https://www.ruby-forum.com/u/mansfiem)\
**Post date:** [September 4, 2008, 4:51pm UTC](https://www.ruby-forum.com/t/where-the-required-things-are-175/147714/3 "2008-09-04T16:51:10Z")

</div>

On 04-09-2008, at 9:45, Matthew M. wrote:

> That leaves us with two “winners” for this week: _Jesse M._ and  
> _Michal S._ (his first solution). Both solutions found all the  
> required modules, recursively, including the .bundle files, and didn’t  
> get confused by `rubygems`.

hey, what about my solution? 😛  
it also solves the test:

rolando:Desktop rolando$ cat test\_quiz175.rb  
require ‘date’  
require ‘readline’  
require ‘matrix’  
require ‘rubygems’  
require ‘time’  
require ‘hpricot’  
require ‘rubyforge’  
require ‘hoe’  
require ‘curses’

rolando:Desktop rolando$ ruby -r quiz175 test\_quiz175.rb  
require ‘date’ =\> /usr/local/lib/ruby/1.8/date.rb  
require ‘readline’ =\> /usr/local/lib/ruby/1.8/i686-darwin9.2.2/  
readline.bundle  
require ‘matrix’ =\> /usr/local/lib/ruby/1.8/matrix.rb  
require ‘rubygems’ =\> /usr/local/lib/ruby/site\_ruby/1.8/rubygems.rb  
require ‘time’ =\> /usr/local/lib/ruby/1.8/time.rb  
require ‘hpricot’ =\> /usr/local/lib/ruby/gems/1.8/gems/hpricot-0.6/  
lib/hpricot.rb  
require ‘rubyforge’ =\> /usr/local/lib/ruby/gems/1.8/gems/  
rubyforge-1.0.0/lib/rubyforge.rb  
require ‘hoe’ =\> /usr/local/lib/ruby/gems/1.8/gems/hoe-1.7.0/lib/  
hoe.rb  
require ‘curses’ =\> /usr/local/lib/ruby/1.8/i686-darwin9.2.2/  
curses.bundle

> –  
> Matthew M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

regards,

---

<div class="post-metadata">

**Author:** ![mansfiem](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/fbc32d/32.png) [@mansfiem](https://www.ruby-forum.com/u/mansfiem)\
**Post date:** [September 4, 2008, 5:39pm UTC](https://www.ruby-forum.com/t/where-the-required-things-are-175/147714/4 "2008-09-04T17:39:14Z")

</div>

> hey, what about my solution? 😛  
> it also solves the test:

Sorry, don’t know how I missed that…

Yup, passed test, all found, non-recursively. Very good.

Hmmm… methinks I may have messed up a couple of my tests with other  
folks. I initially got errors from yours, Rolando, until I realized  
that I had bad line breaks after copying from google groups. Apologies  
to any folks whose solutions I called broken that actually aren’t!

---

<div class="post-metadata">

**Author:** ![mansfiem](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/fbc32d/32.png) [@mansfiem](https://www.ruby-forum.com/u/mansfiem)\
**Post date:** [September 5, 2008, 12:15am UTC](https://www.ruby-forum.com/t/where-the-required-things-are-175/147714/5 "2008-09-05T00:15:23Z")

</div>

> the two “complete” solutions (Merriman, Suchanek) could quite  
> possibly be broken on other platforms. I don’t know. (I’m a bit  
> occupied this week.🙂 A 100% solid solution should account for all  
> these things.

Both Michal’s and mine work on my Linux box:

jesse@ricercar $ uname -a  
Linux ricercar 2.6.25-gentoo-r7 #2 SMP PREEMPT Thu Aug 14 18:28:35 EDT  
2008 i686 Intel® Core™2 CPU 6600 @ 2.40GHz GenuineIntel GNU/Linux  
jesse@ricercar $ ruby -v  
ruby 1.8.6 (2008-03-03 patchlevel 114) [i686-linux]

> Finally, most of you should recognize the standard technique for  
> knowing when a script is run rather than loaded via `require`:
> 
> ```
> if __FILE__ == $0
> ARGV.each { |mod| require mod }
> end
> 
> ```

There is some danger though…

jesse@ricercar $ ./modwhich.rb modwhich.rb  
./modwhich.rb:8:in `require_orig': stack level too deep (SystemStackError) from ./modwhich.rb:8:in`require\_orig’  
from ./modwhich.rb:8:in `require' from ./modwhich.rb:25 from ./modwhich.rb:25:in`each’  
from ./modwhich.rb:25  
from  
/usr/lib/ruby/site\_ruby/1.8/rubygems/custom\_require.rb:27:in  
`gem_original_require' from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in`require\_orig’  
from ./modwhich.rb:8:in `require' from ./modwhich.rb:25 from ./modwhich.rb:25:in`each’  
from ./modwhich.rb:25
