[ruby-core:94313] [Ruby master Bug#11205] Problem with __dir__ or it's description

From: merch-redmine@...
Date: 2019-08-12 23:21:17 UTC
List: ruby-core #94313
Issue #11205 has been updated by jeremyevans0 (Jeremy Evans).

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`:

```ruby
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"]
```

----------------------------------------
Bug #11205: Problem with __dir__ or it's description
https://bugs.ruby-lang.org/issues/11205#change-80667

* Author: gam3 (Allen Morris)
* Status: Closed
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: 
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
~~~
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.

~~~ruby
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)


-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>

In This Thread

Prev Next