Bug #4487
closedrequire_relative fails in an eval'ed file
Description
=begin
Hello all.
$cat eval_me1.rb
eval(File.read('eval_me2.rb'), binding, File.expand_path('./eval_me2.rb'))
$cat eval_me2.rb
require_relative 'eval_me1.rb'
$ ruby eval_me1.rb
C:/dev/ruby/faster_require/spec/eval_me2.rb:1:in require_relative': cannot infer basepath (LoadError) from C:/dev/ruby/faster_require/spec/eval_me2.rb:1:in
'
from eval_me1.rb:1:in eval' from eval_me1.rb:1:in
'
I suppose was assuming that if eval included a filename, then require_relative would work from within it. Perhaps I am mistaken?
Thanks!
-r
=end
Updated by naruse (Yui NARUSE) over 13 years ago
- Status changed from Open to Assigned
- Assignee set to mame (Yusuke Endoh)
Updated by mame (Yusuke Endoh) over 13 years ago
- ruby -v changed from ruby 1.9.3dev (2011-03-04 trunk 31024) [i386-mingw32] to -
Hello,
 $cat eval_me1.rb
 eval(File.read('eval_me2.rb'), binding, File.expand_path('./eval_me2.rb'))
 $cat eval_me2.rb
 require_relative 'eval_me1.rb'
 $ ruby eval_me1.rb
 C:/dev/ruby/faster_require/spec/eval_me2.rb:1:inrequire_relative': cannot infer basepath (LoadError)     from C:/dev/ruby/faster_require/spec/eval_me2.rb:1:in
'
    from eval_me1.rb:1:ineval'     from eval_me1.rb:1:in
'I suppose was assuming that if eval included a filename, then require_relative would work from within it. Perhaps I am mistaken?
I think your expectation is reasonable, though I personally dislike
the eval's feature to fake filepath.
The following patch makes require_relative use the given file path.
I'm afraid if I should include this patch in 1.9.3 because I can't
estimate the impact of this patch. What do you think?
diff --git a/vm_eval.c b/vm_eval.c
index 7df7f5f..3710401 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1007,7 +1007,7 @@ eval_string_with_cref(VALUE self, VALUE src,
VALUE scope, NODE cref, const char
/ make eval iseq */
th->parse_in_eval++;
th->mild_compile_error++;
- iseqval
Updated by mame (Yusuke Endoh) over 13 years ago
- Assignee changed from mame (Yusuke Endoh) to matz (Yukihiro Matsumoto)
Updated by LTe (Piotr Niełacny) over 12 years ago
=begin
If in irb we can execute
(({load("file.rb")}))
why we can't
(({require_relative("file")}))
Ruby just return exception (LoadError: cannot infer basepath). Unfortunately, this is a 'lie' because ruby can recognize basepath.
=end
Updated by shyouhei (Shyouhei Urabe) over 12 years ago
=begin
@LTe (Piotr Niełacny) sorry, I can't get it. load loads from $LOAD_PATH, while require_relative requires from relative path. They are different.
=end
Updated by LTe (Piotr Niełacny) over 12 years ago
@shyouhei (Shyouhei Urabe) yes I agree but load method tries to load file from relative path. When load method can't find file in relative path it loads from $LOAD_PATH. The same can be done by require_relative (recognize path).
Updated by shyouhei (Shyouhei Urabe) over 12 years ago
=begin
@LTe (Piotr Niełacny) I'd rather ask you "require_relative loads something relative from WHAT?"
Obviously it is not relative from your mind :)
Current require_relative loads relative from where the require_relative command is written. So when in IRB sessions, it fails to infer where it is beacuse the command is written in a non-file (console).
OTOH load loads from process PWD, which is possible in IRB.
So the point is, if you want require_relative to work on an IRB session, you have to define "from where require_relative should search relativeness".
=end
Updated by Eregon (Benoit Daloze) over 12 years ago
shyouhei (Shyouhei Urabe) wrote:
Current require_relative loads relative from where the require_relative command is written. So when in IRB sessions, it fails to infer where it is beacuse the command is written in a non-file (console).
OTOH load loads from process PWD, which is possible in IRB.
So the point is, if you want require_relative to work on an IRB session, you have to define "from where require_relative should search relativeness".
From the process current working directory I guess, especially since you almost always launch IRB from a terminal.
Personally I'm doing require './myfile'
which is not the most elegant, but if you don't have completion in IRB, that's shorter to type.
Otherwise, there's always the option to do irb -I.
and use plain require
.
Updated by naruse (Yui NARUSE) over 12 years ago
Eregon (Benoit Daloze) wrote:
shyouhei (Shyouhei Urabe) wrote:
Current require_relative loads relative from where the require_relative command is written. So when in IRB sessions, it fails to infer where it is beacuse the command is written in a non-file (console).
OTOH load loads from process PWD, which is possible in IRB.
So the point is, if you want require_relative to work on an IRB session, you have to define "from where require_relative should search relativeness".
From the process current working directory I guess, especially since you almost always launch IRB from a terminal.
Personally I'm doing
require './myfile'
which is not the most elegant, but if you don't have completion in IRB, that's shorter to type.Otherwise, there's always the option to do
irb -I.
and use plainrequire
.
require_relative is introduced to avoid accidentally require a malicious file on the current working directory.
So it can't be acceptable.
Use require or load on such case.
Updated by shyouhei (Shyouhei Urabe) over 12 years ago
naruse (Yui NARUSE) wrote:
require_relative is introduced to avoid accidentally require a malicious file on the current working directory.
So it can't be acceptable.
Use require or load on such case.
I'm not pretty sure about this. Is there a chance for a (proposed behaviour of) require_relative to require a malicious file on the current directory?
Because you are on an IRB session and intentionally emitting require_relative (not require), I doubt the danger you say.
Updated by naruse (Yui NARUSE) over 12 years ago
shyouhei (Shyouhei Urabe) wrote:
naruse (Yui NARUSE) wrote:
require_relative is introduced to avoid accidentally require a malicious file on the current working directory.
So it can't be acceptable.
Use require or load on such case.I'm not pretty sure about this. Is there a chance for a (proposed behaviour of) require_relative to require a malicious file on the current directory?
Because you are on an IRB session and intentionally emitting require_relative (not require), I doubt the danger you say.
- irb is not the only user of eval.
- A user won't always use require_relative intentionally.
- There is a suitable another way: require './myfile'
With those reason, I don't think require_relative should be changed.
Updated by Eregon (Benoit Daloze) over 12 years ago
naruse (Yui NARUSE) wrote:
Eregon (Benoit Daloze) wrote:
From the process current working directory I guess, especially since you almost always launch IRB from a terminal.
require_relative is introduced to avoid accidentally require a malicious file on the current working directory.
So it can't be acceptable.
Use require or load on such case.
I see, you're right.
Indeed, with this in mind I think it's not worth changing, and the actual require_relative behavior is clearer (relative to "this file" directory, if there is no accurate "this file", just #raise).
Updated by ko1 (Koichi Sasada) over 12 years ago
- Assignee changed from matz (Yukihiro Matsumoto) to mame (Yusuke Endoh)
mame-san, please ask matz.
Updated by mame (Yusuke Endoh) almost 12 years ago
- Subject changed from require_relative fails in an eval'ed file to require_relative fails in an eval'ed file
- Assignee changed from mame (Yusuke Endoh) to matz (Yukihiro Matsumoto)
- Target version set to 2.6
Updated by Conrad.Irwin (Conrad Irwin) over 11 years ago
This bug also affects pry: https://github.com/pry/pry/issues/880. Our use-case is slightly different because we are doing TOPLEVEL_BINDING.eval("some code", "/absolute/path.rb").
I think that when an absolute path is set in eval, then require_relative should use it.
Updated by julik (Julik Tarkhanov) over 9 years ago
This is actually very pertinent for Rack as well, because currently config.ru does not support require_relative which is very counterintuitive.
Updated by mame (Yusuke Endoh) about 7 years ago
- Status changed from Assigned to Closed
Now, it works. I'm unsure who changed the behavior... Anyway, closing.