Project

General

Profile

Actions

Feature #4523

closed

Kernel#require to return the path of the loaded file

Added by regularfry (Alex Young) about 13 years ago. Updated about 12 years ago.

Status:
Rejected
Assignee:
-
Target version:
-
[ruby-core:35552]

Description

=begin
It's very useful to be able to tell which actual file on disc was loaded following a call to require, without having to manually traverse $LOAD_PATH. This information is also not guaranteed to be in $LOADED_FEATURES.

The attached patch alters rb_require_safe's return value to indicate the loaded file iff a file is actually loaded.
=end


Files

require-path.patch (260 Bytes) require-path.patch regularfry (Alex Young), 03/25/2011 07:18 AM

Updated by nobu (Nobuyoshi Nakada) over 12 years ago

  • Category set to core
  • Status changed from Open to Feedback
  • Target version set to 3.0

What do you expect when the library has loaded already?

Updated by regularfry (Alex Young) over 12 years ago

False, the same as currently.

Actions #4

Updated by naruse (Yui NARUSE) over 12 years ago

  • Project changed from Ruby master to 14
  • Category deleted (core)
  • Target version deleted (3.0)
Actions #5

Updated by naruse (Yui NARUSE) over 12 years ago

  • Project changed from 14 to Ruby master

Updated by nobu (Nobuyoshi Nakada) about 12 years ago

I don't think it's useful if it may return false.
What's the use case?
I agree that the way to know the loaded path would be useful sometimes, but this doesn't seem nice.

Updated by trans (Thomas Sawyer) about 12 years ago

I haven't worked on the project where such comes into play in a few months, so I can only recollect the obvious usecase at the moment -- When debugging a problem were you suspect the wrong file is being required. Then this could be very helpful. For instance I was recently having issues working on Test::Unit, running into cases were MiniTest's emulation lib was being loaded rather than from the gem. If I could have just put a p in front of the require 'test/unit' that would made it a quick check.

Updated by drbrain (Eric Hodel) about 12 years ago

If you have two files with the same name isn't gem which --all enough to discover the collision?

Updated by trans (Thomas Sawyer) about 12 years ago

No, b/c that's not running in the process and at the point in code which is in question.

Updated by regularfry (Alex Young) about 12 years ago

On 18/03/12 10:22, nobu wrote:

Issue #4523 has been updated by nobu.

I don't think it's useful if it may return false.

On the contrary - if it returns false, you know the set of loaded files
hasn't changed. You (should) know that no new ruby has been parsed.

What's the use case?
I agree that the way to know the loaded path would be useful sometimes, but this doesn't seem nice.

The specific thing I was trying to do was gather all the required files
into a SQLite database. Then a later process with an overridden
require can load precisely the same file content from that database,
without ambiguity.

Without this patch, in order to figure out which file was actually
loaded, you have to duplicate the $LOAD_PATH file search logic, which is
a nasty, hacky duplication of functionality which can break if
require's filename resolution logic ever changes. With it, you're
guaranteed a correct value. Given that it doesn't break anything (that
I know of), and it's such a tiny patch, I honestly don't see a down-side.

--
Alex


Feature #4523: Kernel#require to return the path of the loaded file
https://bugs.ruby-lang.org/issues/4523#change-24910

Author: regularfry
Status: Feedback
Priority: Normal
Assignee:
Category:
Target version:

=begin
It's very useful to be able to tell which actual file on disc was loaded following a call to require, without having to manually traverse $LOAD_PATH. This information is also not guaranteed to be in $LOADED_FEATURES.

The attached patch alters rb_require_safe's return value to indicate the loaded file iff a file is actually loaded.
=end

Updated by luislavena (Luis Lavena) about 12 years ago

On Mon, Mar 19, 2012 at 8:06 AM, Alex Young wrote:

On 18/03/12 10:22, nobu wrote:

Issue #4523 has been updated by nobu.

I don't think it's useful if it may return false.

On the contrary - if it returns false, you know the set of loaded files
hasn't changed.  You (should) know that no new ruby has been parsed.

What if your require triggers more requires inside? The usefulness of
you collecting the response of one require doesn't mean you have all
the files that were loaded.

What's the use case?
I agree that the way to know the loaded path would be useful sometimes,
but this doesn't seem nice.

The specific thing I was trying to do was gather all the required files into
a SQLite database.  Then a later process with an overridden require can
load precisely the same file content from that database, without
ambiguity.

Are you trying to build a list of all the files that were require'd ?

If so, why not use $LOADED_FEATURES with at_exit?

$LOADED_FEATURES include full paths so you can use that combined with
$LOAD_PATH to determine the require itself.

--
Luis Lavena
AREA 17

Perfection in design is achieved not when there is nothing more to add,
but rather when there is nothing more to take away.
Antoine de Saint-Exupéry

Updated by regularfry (Alex Young) about 12 years ago

On 19/03/12 11:58, Luis Lavena wrote:

On Mon, Mar 19, 2012 at 8:06 AM, Alex Young wrote:

On 18/03/12 10:22, nobu wrote:

Issue #4523 has been updated by nobu.

I don't think it's useful if it may return false.

On the contrary - if it returns false, you know the set of loaded files
hasn't changed. You (should) know that no new ruby has been parsed.

What if your require triggers more requires inside? The usefulness of
you collecting the response of one require doesn't mean you have all
the files that were loaded.

This is the sort of thing I have in mind:

module CollectingRequire
  def require( *args )
    filename = super(*args)
    __log( filename )
    filename
  end

  def __log(filename)
    (@__loaded ||= []) << filename
  end

  def all_loaded
    @__loaded
  end
end

extend( CollectingRequire )

require 'highline'

all_loaded
  # => [all the files]

That's the sort of arrangement I'd need; I'm sure there are uses which
don't involve monkeypatching.

I could do just as well with a post-require hook of some sort, but
that's way more intrusive. If that's what's needed, though, I'm happy
to take a look at an implementation.

What's the use case?
I agree that the way to know the loaded path would be useful sometimes,
but this doesn't seem nice.

The specific thing I was trying to do was gather all the required files into
a SQLite database. Then a later process with an overridden require can
load precisely the same file content from that database, without
ambiguity.

Are you trying to build a list of all the files that were require'd ?

If so, why not use $LOADED_FEATURES with at_exit?

Because when I opened this feature request a year ago $LOADED_FEATURES
didn't seem to include full paths, so I didn't want to rely on it.

$LOADED_FEATURES include full paths

Does it? Is that now part of the spec? Neither rubinius nor jruby seem
to make that guarantee, nor is it true for 1.8.7. And if it is...

$ irb
1.9.3p125 :001 > $LOADED_FEATURES.first
=> "enumerator.so"

Is that a bug?

so you can use that combined with $LOAD_PATH to determine the require itself.

I can, and do, already do something like this. The point is that by
adding this information to the API, I don't have to - I get a known-good
value directly from where it's generated, rather than recreating it (and
possibly screwing it up). I'm sure I'm not the only one who'd find this
handy.

If anyone can spot how this proposal can possibly be harmful, I'm all
ears. As far as I can see it's an unintrusive, useful improvement.

--
Alex

Updated by drbrain (Eric Hodel) about 12 years ago

On Mar 19, 2012, at 10:16 AM, Alex Young wrote:

On 19/03/12 11:58, Luis Lavena wrote:

On Mon, Mar 19, 2012 at 8:06 AM, Alex Young wrote:

On 18/03/12 10:22, nobu wrote:

Issue #4523 has been updated by nobu.

I don't think it's useful if it may return false.

On the contrary - if it returns false, you know the set of loaded files
hasn't changed. You (should) know that no new ruby has been parsed.

What if your require triggers more requires inside? The usefulness of
you collecting the response of one require doesn't mean you have all
the files that were loaded.

This is the sort of thing I have in mind:

module CollectingRequire
def require( *args )
filename = super(*args)
__log( filename )
filename
end

def __log(filename)
(@__loaded ||= []) << filename
end

def all_loaded
@__loaded
end
end

extend( CollectingRequire )

require 'highline'

all_loaded

=> [all the files]

That's the sort of arrangement I'd need; I'm sure there are uses which don't involve monkeypatching.

I could do just as well with a post-require hook of some sort, but that's way more intrusive. If that's what's needed, though, I'm happy to take a look at an implementation.

There's an easier way that works without any monkey patching or new features.

ruby -e 'loaded = $LOADED_FEATURES.dup; require "highline"; p $LOADED_FEATURES - loaded'

What's the use case?
I agree that the way to know the loaded path would be useful sometimes,
but this doesn't seem nice.

The specific thing I was trying to do was gather all the required files into
a SQLite database. Then a later process with an overridden require can
load precisely the same file content from that database, without
ambiguity.

Are you trying to build a list of all the files that were require'd ?

If so, why not use $LOADED_FEATURES with at_exit?

Because when I opened this feature request a year ago $LOADED_FEATURES didn't seem to include full paths, so I didn't want to rely on it.

$LOADED_FEATURES include full paths

Does it? Is that now part of the spec?

Yes.

Neither rubinius nor jruby seem to make that guarantee,

They do.

nor is it true for 1.8.7.

1.9.1, 1.9.2 and 1.9.3 have been released since 1.8.7, so I don't know why you would check 1.8.7 for new features. jruby and rubinius follow the 1.8 spec when run in 1.8 mode, and the 1.9 spec when run in 1.9 mode.

And if it is...

$ irb
1.9.3p125 :001 > $LOADED_FEATURES.first
=> "enumerator.so"

Is that a bug?

I would argue no as enumerator.so is a dummy require:

rb_provide("enumerator.so"); /* for backward compatibility */

to allow old 1.8 programs to continue to require 'enumerator' which is now built-in in ruby 1.9.

so you can use that combined with $LOAD_PATH to determine the require itself.

I can, and do, already do something like this. The point is that by adding this information to the API, I don't have to - I get a known-good value directly from where it's generated, rather than recreating it (and possibly screwing it up). I'm sure I'm not the only one who'd find this handy.

If anyone can spot how this proposal can possibly be harmful, I'm all ears. As far as I can see it's an unintrusive, useful improvement.

It only returns the filename directly loaded, not the complete set of files required, so can only return limited information.

It only returns the filename if this was the first time the file was required. It feels bad that this feature would only work on the first require which the user may not be able to control.

It promotes needless monkey patching or overriding of require when there is a simple solution to retrieve the information you desire (the set of files loaded, per your example above).

For these reasons, I don't think it encourages good use of ruby.

Updated by regularfry (Alex Young) about 12 years ago

On 19/03/12 23:24, Eric Hodel wrote:

On Mar 19, 2012, at 10:16 AM, Alex Young wrote:

On 19/03/12 11:58, Luis Lavena wrote:

>>> $LOADED_FEATURES include full paths >> >> Does it? Is that now part of the spec? > > Yes.

Fine. Close the issue, this feature isn't needed any more. At the time
I was trying to get code together which would work on both 1.8 and 1.9
and, for a reason I cannot now fathom, thought this might be generally
viewed as a useful thing to have.

Neither rubinius nor jruby seem to make that guarantee,

They do.

nor is it true for 1.8.7.

1.9.1, 1.9.2 and 1.9.3 have been released since 1.8.7, so I don't know why you would check 1.8.7 for new features.

Please don't be condescending. If I don't know it's a new feature, how
do I know where to look for it? If I don't know it's not an accidental
behaviour, how do I know it's guaranteed to be the same across 1.8.7
patch levels - the last of which is well after I opened this ticket?

And if it is...

$ irb
1.9.3p125 :001> $LOADED_FEATURES.first
=> "enumerator.so"

Is that a bug?

I would argue no as enumerator.so is a dummy require:

rb_provide("enumerator.so"); /* for backward compatibility */

to allow old 1.8 programs to continue to require 'enumerator' which is now built-in in ruby 1.9.

I'm not arguing that it's not useful. I'm saying that it breaks the
guarantee you're saying $LOADED_FEATURES provides.

--
Alex

Actions #15

Updated by nobu (Nobuyoshi Nakada) about 12 years ago

  • Status changed from Feedback to Rejected
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0