Require when Executed file is required by another file.

Discussion in 'Ruby' started by Zev Blut, Feb 18, 2005.

  1. Zev Blut

    Zev Blut Guest

    Hello,

    My colleagues and I just encountered an interesting gotcha with
    "require".

    Put the following in a file called "req1.rb"

    -------------- [req1.rb]
    #!/usr/local/bin/ruby1.8 -w

    puts "$0 #{$0}"
    base = $0.split("/")
    PATH = base[0...(base.size - 1)].join("/")

    def jump
    require "req2"
    end

    puts "Fun"

    if __FILE__ == $0
    puts "Require 1"
    jump
    end
    ---------- [req1.rb]

    And then put the following in another file called "req2.rb"

    ---------- [req2.rb]
    require "#{PATH}/req1"

    puts "Require 2"
    ---------- [req2.rb]

    Now run req1.rb from the full path.

    Here is an example of my output:
    ========
    $ /home/zev/projects/rubyplay/recurse_require/req1.rb
    $0 /home/zev/projects/rubyplay/recurse_require/req1.rb
    Fun
    Require 1
    $0 /home/zev/projects/rubyplay/recurse_require/req1.rb
    /home/zev/projects/rubyplay/recurse_require/req1.rb:5: warning:
    already initialized constant PATH

    /home/zev/projects/rubyplay/recurse_require/req1.rb:7: warning: method
    redefined; discarding old jump

    Fun
    Require 1
    Require 2
    =========

    Notice that the __FILE__ == $0 gets called twice!
    Also the fact that PATH and jump get redefined too...

    Is there a way to easily stop this?

    Thanks,
    Zev
     
    Zev Blut, Feb 18, 2005
    #1
    1. Advertising

  2. Zev Blut

    Nospam Guest

    It seems that although require normally makes sure a certain files only
    gets included once require somehow doesn't take into account the file
    the interpreter first included.

    Regards,

    Peter
     
    Nospam, Feb 18, 2005
    #2
    1. Advertising

  3. Zev Blut

    Zev Blut Guest

    On Fri, 18 Feb 2005 21:09:47 +0900, Nospam
    <-nonsense.org> wrote:

    > It seems that although require normally makes sure a certain files only
    > gets included once require somehow doesn't take into account the file
    > the interpreter first included.


    Exactly, but should this be the case?

    Cheers,
    Zev
     
    Zev Blut, Feb 18, 2005
    #3
  4. On Feb 18, 2005, at 4:59 AM, Zev Blut wrote:

    > On Fri, 18 Feb 2005 21:09:47 +0900, Nospam
    > <-nonsense.org> wrote:
    >
    >> It seems that although require normally makes sure a certain files
    >> only gets included once require somehow doesn't take into account the
    >> file the interpreter first included.

    >
    > Exactly, but should this be the case?


    require provides a simple mechanism trying to prevent multiple file
    loads -- it keeps loaded file paths in array $" just as given
    (appending a proper extension - .rb, .so, etc. - if it is missing) and
    does not load a file if the same path is already present in the array.
    It is very easy to trick it by requiring the same file using different
    paths, like in "test.rb", "./test.rb", "././test.rb".

    In general, it is very hard and time consuming to determine that
    different paths refer to the same file, so require does not even try to
    pretend that it is robust.

    Knowing how require works, you can easily implement some work around
    for your particular case.

    >
    > Cheers,
    > Zev
    >
    >
    >


    Sincerely,
    Gennady Bystritsky
     
    Gennady Bystritsky, Feb 19, 2005
    #4
  5. Zev Blut

    Zev Blut Guest

    Hello,

    On Sat, 19 Feb 2005 15:19:59 +0900, Gennady Bystritsky <>
    wrote:

    > In general, it is very hard and time consuming to determine that
    > different paths refer to the same file, so require does not even try to
    > pretend that it is robust.


    It certainly appears to be a bit tricky. Although, it would be nice
    if the executed program was added to $" so that it could prevent being
    required again.


    > Knowing how require works, you can easily implement some work around for
    > your particular case.


    The solution for the day is probably that my colleagues and I need to
    make all executable programs thin wrappers that only require the main
    code and implement the __FILE__ == $0 logic.

    Best,
    Zev
     
    Zev Blut, Feb 21, 2005
    #5
  6. > In general, it is very hard and time consuming to determine that
    > different paths refer to the same file, so require does not even try to
    > pretend that it is robust.


    Why not calculate a hash of the file and use this in the check. This
    would make the whole thing independent from the actual path, and allows
    to re-require a file if its content changes.

    martinus
     
    Martin Ankerl, Feb 21, 2005
    #6
  7. Zev Blut

    Zev Blut Guest

    On Mon, 21 Feb 2005 20:00:37 +0900, Martin Ankerl
    <> wrote:

    >> In general, it is very hard and time consuming to determine that
    >> different paths refer to the same file, so require does not even try to
    >> pretend that it is robust.

    >
    > Why not calculate a hash of the file and use this in the check. This
    > would make the whole thing independent from the actual path, and allows
    > to re-require a file if its content changes.


    Interesting solution! Although, I am sure some people may not like the
    potential performance hit. Also the re-require could be good and it
    could be bad, depending upon various situations.

    A coworker of mine just commented why not just use File.expand_path for
    the required file? Is there any reason not to do this?

    Cheers,
    Zev
     
    Zev Blut, Feb 21, 2005
    #7
  8. Zev Blut wrote:
    > A coworker of mine just commented why not just use File.expand_path for
    > the required file? Is there any reason not to do this?


    Symlinks...

    $ cd /tmp
    $ touch foo
    $ ln -s foo bar
    $ ruby -e 'p File.expand_path("foo")'
    "/tmp/foo"
    $ ruby -e 'p File.expand_path("bar")'
    "/tmp/bar"

    It might not be very portable, but there is File::Stat#ino:

    $ ruby -e 'p File.stat("foo").ino'
    1239183
    $ ruby -e 'p File.stat("foo").dev'
    776
    $ ruby -e 'p File.stat("bar").ino'
    1239183
    $ ruby -e 'p File.stat("bar").dev'
    776
     
    Joel VanderWerf, Feb 21, 2005
    #8
  9. Zev Blut

    Zev Blut Guest

    On Tue, 22 Feb 2005 04:42:03 +0900, Joel VanderWerf
    <> wrote:

    > Zev Blut wrote:
    >> A coworker of mine just commented why not just use File.expand_path for
    >> the required file? Is there any reason not to do this?

    >
    > Symlinks...
    >
    > $ cd /tmp
    > $ touch foo
    > $ ln -s foo bar
    > $ ruby -e 'p File.expand_path("foo")'
    > "/tmp/foo"
    > $ ruby -e 'p File.expand_path("bar")'
    > "/tmp/bar"


    Yes that is true, but I noticed if you actually go to directory with
    a symlink, it will expand to the true path. Like so:

    $ cd /tmp/
    $ mkdir foo
    $ ln -s foo bar
    $ touch foo/baz.rb
    $ ruby -e 'Dir.chdir("foo") ;p File.expand_path("baz.rb")'
    "/tmp/foo/baz.rb"
    $ ruby -e 'Dir.chdir("bar") ;p File.expand_path("baz.rb")'
    "/tmp/foo/baz.rb"

    Is this portable or are there other problems with doing it this way?

    Best,
    Zev
     
    Zev Blut, Feb 22, 2005
    #9
  10. Zev Blut wrote:
    > On Tue, 22 Feb 2005 04:42:03 +0900, Joel VanderWerf
    > <> wrote:
    >
    >> Zev Blut wrote:
    >>
    >>> A coworker of mine just commented why not just use File.expand_path for
    >>> the required file? Is there any reason not to do this?

    >>
    >>
    >> Symlinks...
    >>
    >> $ cd /tmp
    >> $ touch foo
    >> $ ln -s foo bar
    >> $ ruby -e 'p File.expand_path("foo")'
    >> "/tmp/foo"
    >> $ ruby -e 'p File.expand_path("bar")'
    >> "/tmp/bar"

    >
    >
    > Yes that is true, but I noticed if you actually go to directory with
    > a symlink, it will expand to the true path. Like so:
    >
    > $ cd /tmp/
    > $ mkdir foo
    > $ ln -s foo bar
    > $ touch foo/baz.rb
    > $ ruby -e 'Dir.chdir("foo") ;p File.expand_path("baz.rb")'
    > "/tmp/foo/baz.rb"
    > $ ruby -e 'Dir.chdir("bar") ;p File.expand_path("baz.rb")'
    > "/tmp/foo/baz.rb"
    >
    > Is this portable or are there other problems with doing it this way?


    Hm, I didn't expect that. And also:

    $ ruby -e 'Dir.chdir("bar") ;p Dir.pwd'
    "/tmp/foo"

    In the shell (using linux, zsh) it works differently:

    $ cd bar
    $ pwd
    /tmp/bar

    Another data point:

    $ ruby -e 'Dir.chdir("bar"); puts `pwd`'
    /tmp/foo

    I guess ruby follows symlinks when doing Dir.chdir?

    Anyway, it doesn't solve the problem of a symlinked .rb file, if that's
    a problem.
     
    Joel VanderWerf, Feb 22, 2005
    #10
  11. Zev Blut

    Zev Blut Guest

    Hello,

    On Tue, 22 Feb 2005 15:18:55 +0900, Joel VanderWerf
    <> wrote:

    > Zev Blut wrote:


    >> Yes that is true, but I noticed if you actually go to directory with
    >> a symlink, it will expand to the true path. Like so:
    >> [Snip examples]
    >>

    > Hm, I didn't expect that. And also:
    >
    > [Snip more examples]
    >
    > I guess ruby follows symlinks when doing Dir.chdir?
    >
    > Anyway, it doesn't solve the problem of a symlinked .rb file, if that's
    > a problem.


    Yes unfortunately it does not...
    Personally I use require with symlinks to directories, but not files.
    Although, I am sure someone does require symlinked files.

    Your File.stat suggestion looks good, but I just confirmed, as you
    suggested,
    that it is not portable to a Windows environment.

    I suppose Martin Ankerl's suggestion of computing a hash of each file is
    the
    most robust.

    Looking at the ToDo in Ruby I noticed this:

    * save both "feature names" and "normalized path" in $"

    Maybe, there is already a better solution and it just waits for
    implementation :)

    Zev
     
    Zev Blut, Feb 23, 2005
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. EvgueniB
    Replies:
    1
    Views:
    663
    Anthony Borla
    Dec 15, 2003
  2. Germán Diago
    Replies:
    0
    Views:
    369
    Germán Diago
    Oct 20, 2009
  3. Eddy Xu
    Replies:
    5
    Views:
    137
    Eddy Xu
    Apr 11, 2008
  4. I. E. Smith-Heisters

    detect if required or executed?

    I. E. Smith-Heisters, Jun 17, 2008, in forum: Ruby
    Replies:
    4
    Views:
    123
    I. E. Smith-Heisters
    Jun 17, 2008
  5. Sarah Allen
    Replies:
    3
    Views:
    151
    Jörg W Mittag
    Sep 8, 2010
Loading...

Share This Page