Project

General

Profile

Bug #11205

Problem with __dir__ or it's description

Added by gam3 (Allen Morris) over 4 years ago. Updated 4 months ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:69431]

Description

Kernel#__dir__

Returns the canonicalized absolute path of the directory of the file from which this method is called. It means symlinks in the path is resolved. If __FILE__ is nil, it returns nil. The return value equals to File.dirname(File.realpath(__FILE__)).

Here is a script that shows the problem.

def mytest(&block)
  ret = block.binding.eval( '[ __FILE__, __dir__ ]' )
  assert_equal("bill", __dir__)
end
dir = __dir__
eval(%q(
  ret = mytest { }
  ret[0] == '/bill/bill'
  ret[1] == dir          # where it shoudl == '/bill'
  # 
), nil, '/bill/bill', 1)

Even without the binding problem it is clear from the current ruby tests that
__dir__ is not equal to File.realpath(__FILE__).

  def test___dir__
    assert_instance_of String, __dir__
    assert_equal(File.dirname(File.realpath(__FILE__)), __dir__)
    bug8436 = '[ruby-core:55123] [Bug #8436]'
    assert_equal(__dir__, eval("__dir__", binding), bug8436)
    bug8662 = '[ruby-core:56099] [Bug #8662]'
    assert_equal("arbitrary", eval("__dir__", binding, "arbitrary/file.rb"), bug8662)
    assert_equal("arbitrary", Object.new.instance_eval("__dir__", "arbitrary/file.rb"), bug8662)
  end

possible solution:
Fix eval so that it never affects Kernel#__dir__ and add a Kernel#__file__ method and rewrite the description as:

Kernel#__dir__

Returns the canonicalized absolute path of the directory of the file from which this method is called. It means symlinks in the path is resolved. The return value equals to File.dirname(File.realpath(__file__)).

And a definition for __file__

Kernel#__file__

Returns the canonicalized absolute path of the directory of the file from which this method is called. It means symlinks in the path is resolved. The return value equals to File.dirname(File.realpath(__file__)).
Note: __file__ is equal to __FILE__ except inside of #eval and #eval_instance.

This assumes that the purpose of __dir__ is to find files in the current filesystem, and not for the purpose of debugging.


Files

patch (900 Bytes) patch test_method patch gam3 (Allen Morris), 06/01/2015 02:48 PM

History

#1

Updated by gam3 (Allen Morris) over 4 years ago

  • Assignee set to ruby-core

Updated by gam3 (Allen Morris) over 4 years ago

Note that require_relative uses __dir__ as the base to generate an absolute path.

Updated by nobu (Nobuyoshi Nakada) over 4 years ago

  • Description updated (diff)
#4

Updated by naruse (Yui NARUSE) over 3 years ago

  • Assignee deleted (ruby-core)

Updated by jeremyevans0 (Jeremy Evans) 4 months ago

  • Status changed from Open to Closed

I don't think this is a bug in __dir__. It's just that __FILE__ inside eval depends on either the binding or file argument given to eval (in Ruby 3, it will only depend on the file argument, see #4352).

If you rewrite your example to correctly set __FILE__ inside the call to eval in mytest:

def mytest(&block)
  block.binding.eval( '[ __FILE__, __dir__ ]', block.binding.local_variable_get('f'))
end
eval(%q( f = __FILE__; p mytest {}), nil, '/bill/bill', 1)

You can see that __dir__ is accurate, as the output of the program is:

["/bill/bill", "/bill"]

Also available in: Atom PDF