Issue #19107 has been updated by matz (Yukihiro Matsumoto).
I don't care for consistency here (since formal arguments and actual arguments are different).
I am not sure for convenience. Compare to actual arguments, there's less chance to rewrite/update formal arguments.
Is there an actual case where this proposal is convenient?
Matz.
----------------------------------------
Feature #19107: Allow trailing comma in method signature
https://bugs.ruby-lang.org/issues/19107#change-100385
* Author: byroot (Jean Boussier)
* Status: Open
* Priority: Normal
----------------------------------------
A popular style for multiline arrays, hashes or method calls, is to use trailing commas:
```ruby
array = [
1,
2,
3,
]
hash = {
foo: 1,
bar: 2,
baz: 3,
}
Some.method(
1,
2,
foo: 3,
)
```
The main reason to do this is to avoid unnecessary noise when adding one extra element:
```diff
diff --git a/foo.rb b/foo.rb
index b2689a7e4f..ddb7dc3552 100644
--- a/foo.rb
+++ b/foo.rb
@@ -1,4 +1,5 @@
Foo.bar(
foo: 1,
- bar: 2
+ bar: 2,
+ baz: 3
)
```
However, this pattern doesn't work with method declarations:
```ruby
def foo(bar:,) # syntax error, unexpected ')'
```
### Proposal
For consistency and convenience I propose to allow trailing commas in method declarations.
--
https://bugs.ruby-lang.org/
Issue #18951 has been updated by byroot (Jean Boussier).
Thank you Matz.
If it's not desired in ruby-core, I can add it to Active Support, that's no problem.
----------------------------------------
Feature #18951: Object#with to set and restore attributes around a block
https://bugs.ruby-lang.org/issues/18951#change-100384
* Author: byroot (Jean Boussier)
* Status: Open
* Priority: Normal
----------------------------------------
### Use case
A very common pattern in Ruby, especially in testing is to save the value of an attribute, set a new value, and then restore the old value in an `ensure` clause.
e.g. in unit tests
```ruby
def test_something_when_enabled
enabled_was, SomeLibrary.enabled = SomeLibrary.enabled, true
# test things
ensure
SomeLibrary.enabled = enabled_was
end
```
Or sometime in actual APIs:
```ruby
def with_something_enabled
enabled_was = @enabled
@enabled = true
yield
ensure
@enabled = enabled_was
end
```
There is no inherent problem with this pattern, but it can be easy to make a mistake, for instance the unit test example:
```ruby
def test_something_when_enabled
some_call_that_may_raise
enabled_was, SomeLibrary.enabled = SomeLibrary.enabled, true
# test things
ensure
SomeLibrary.enabled = enabled_was
end
```
In the above if `some_call_that_may_raise` actually raises, `SomeLibrary.enabled` is set back to `nil` rather than its original value. I've seen this mistake quite frequently.
### Proposal
I think it would be very useful to have a method on Object to implement this pattern in a correct and easy to use way. The naive Ruby implementation would be:
```ruby
class Object
def with(**attributes)
old_values = {}
attributes.each_key do |key|
old_values[key] = public_send(key)
end
begin
attributes.each do |key, value|
public_send("#{key}=", value)
end
yield
ensure
old_values.each do |key, old_value|
public_send("#{key}=", old_value)
end
end
end
end
```
NB: `public_send` is used because I don't think such method should be usable if the accessors are private.
With usage:
```ruby
def test_something_when_enabled
SomeLibrary.with(enabled: true) do
# test things
end
end
```
```ruby
GC.with(measure_total_time: true, auto_compact: false) do
# do something
end
```
### Alternate names and signatures
If `#with` isn't good, I can also think of:
- `Object#set`
- `Object#apply`
But the `with_` prefix is by far the most used one when implementing methods that follow this pattern.
Also if accepting a Hash is dimmed too much, alternative signatures could be:
- `Object#set(attr_name, value)`
- `Object#set(attr1, value1, [attr2, value2], ...)`
# Some real world code example that could be simplified with method
- `redis-client` `with_timeout` https://github.com/redis-rb/redis-client/blob/23a5c1e2ff688518904f206df8d4a…
- Lots of tests in Rails's codebase:
- Changing `Thread.report_on_exception`: https://github.com/rails/rails/blob/2d2fdc941e7497ca77f99ce5ad404b6e58f043e…
- Changing a class attribute: https://github.com/rails/rails/blob/2d2fdc941e7497ca77f99ce5ad404b6e58f043e…
--
https://bugs.ruby-lang.org/
Issue #18951 has been updated by matz (Yukihiro Matsumoto).
* `with_attr` is better than plain `with`
* this method can be useful for some cases, but I am not sure if it should be a method of Object class
* maybe it should be a utility method in a gem (e.g. `save_current_attr(obj, **kw) {....}`)
Matz.
----------------------------------------
Feature #18951: Object#with to set and restore attributes around a block
https://bugs.ruby-lang.org/issues/18951#change-100383
* Author: byroot (Jean Boussier)
* Status: Open
* Priority: Normal
----------------------------------------
### Use case
A very common pattern in Ruby, especially in testing is to save the value of an attribute, set a new value, and then restore the old value in an `ensure` clause.
e.g. in unit tests
```ruby
def test_something_when_enabled
enabled_was, SomeLibrary.enabled = SomeLibrary.enabled, true
# test things
ensure
SomeLibrary.enabled = enabled_was
end
```
Or sometime in actual APIs:
```ruby
def with_something_enabled
enabled_was = @enabled
@enabled = true
yield
ensure
@enabled = enabled_was
end
```
There is no inherent problem with this pattern, but it can be easy to make a mistake, for instance the unit test example:
```ruby
def test_something_when_enabled
some_call_that_may_raise
enabled_was, SomeLibrary.enabled = SomeLibrary.enabled, true
# test things
ensure
SomeLibrary.enabled = enabled_was
end
```
In the above if `some_call_that_may_raise` actually raises, `SomeLibrary.enabled` is set back to `nil` rather than its original value. I've seen this mistake quite frequently.
### Proposal
I think it would be very useful to have a method on Object to implement this pattern in a correct and easy to use way. The naive Ruby implementation would be:
```ruby
class Object
def with(**attributes)
old_values = {}
attributes.each_key do |key|
old_values[key] = public_send(key)
end
begin
attributes.each do |key, value|
public_send("#{key}=", value)
end
yield
ensure
old_values.each do |key, old_value|
public_send("#{key}=", old_value)
end
end
end
end
```
NB: `public_send` is used because I don't think such method should be usable if the accessors are private.
With usage:
```ruby
def test_something_when_enabled
SomeLibrary.with(enabled: true) do
# test things
end
end
```
```ruby
GC.with(measure_total_time: true, auto_compact: false) do
# do something
end
```
### Alternate names and signatures
If `#with` isn't good, I can also think of:
- `Object#set`
- `Object#apply`
But the `with_` prefix is by far the most used one when implementing methods that follow this pattern.
Also if accepting a Hash is dimmed too much, alternative signatures could be:
- `Object#set(attr_name, value)`
- `Object#set(attr1, value1, [attr2, value2], ...)`
# Some real world code example that could be simplified with method
- `redis-client` `with_timeout` https://github.com/redis-rb/redis-client/blob/23a5c1e2ff688518904f206df8d4a…
- Lots of tests in Rails's codebase:
- Changing `Thread.report_on_exception`: https://github.com/rails/rails/blob/2d2fdc941e7497ca77f99ce5ad404b6e58f043e…
- Changing a class attribute: https://github.com/rails/rails/blob/2d2fdc941e7497ca77f99ce5ad404b6e58f043e…
--
https://bugs.ruby-lang.org/
Issue #19036 has been updated by ioquatix (Samuel Williams).
Ruby IO is a rich object and has an internal path. It seems reasonable that `IO.new` or `IO.for_fd` can set it. I don't think this is something specific to `File` in the way Ruby thinks about IO.
----------------------------------------
Feature #19036: Provide a way to set path for File instances created with for_fd
https://bugs.ruby-lang.org/issues/19036#change-100382
* Author: headius (Charles Nutter)
* Status: Open
* Priority: Normal
----------------------------------------
Ruby provides `IO.for_fd` to instantiate an IO object from an existing file descriptor value. The logic for this simply calls the base `IO.new` logic, which for all IO and subtypes simply wraps the given file descriptor.
When called against File, or other subtypes of IO, this has the side effect of creating an IO instance with that type, e.g. `File.for_fd` will behave identically to `IO.for_fd` except that the class of the resulting object will be File.
Unfortunately, this results in a File object that does not have any `path` associated with it:
```
3.1.2 :001 > f = File.open('README.md')
=> #<File:README.md>
3.1.2 :002 > f.path
=> "README.md"
3.1.2 :003 > f2 = File.for_fd(f.fileno)
=> #<File:fd 5>
3.1.2 :004 > f2.path
(irb):4:in `path': File is unnamed (TMPFILE?) (IOError)
from (irb):4:in `<main>'
from /home/headius/.rvm/rubies/ruby-3.1.2/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>'
from /home/headius/.rvm/rubies/ruby-3.1.2/bin/irb:25:in `load'
from /home/headius/.rvm/rubies/ruby-3.1.2/bin/irb:25:in `<main>'
```
I propose that there should be a way, via an extra parameter or a keyword argument, to provide a path when constructing a new File via `for_fd`.
Possible forms:
* `File.for_fd(fileno, "my/path")`
* `File.for_fd(fileno, path: "my/path")`
This would necessitate a separate implementation for `File.for_fd` unless we want to make it possible to set a path for all `for_fd` calls (which may not make sense for many of them).
This came up while trying to implement a pure-Ruby (plus FFI) version of the "pty" library. Without overriding the `path` function, it is not possible for the File object returned by `PTY.open` to gain the "masterpty:<slavename>" filename, and therefore it does not clearly indicate it is from a PTY.
See https://github.com/jruby/jruby/pull/7391, an attempt to match inspect output for these return values using `define_singleton_method`. Providing a way to set the path would make this automatic without the singleton definition.
--
https://bugs.ruby-lang.org/
Issue #18980 has been updated by maedi (Maedi Prichard).
How about `_@`? It's your friendly neighborhood local-instance variable. I'm half joking but it is a local variable that refers to instances.
It's nice and illegal:
```ruby
[1, 2, 3].each { puts _@ }
```
Looks better when it's not an outlaw:
```
[1, 2, 3].each { puts _@ }
```
I've always liked just `@` but I see the point that it can be confused with instance variables, especially when it's written as `@.size` (is `_@.size` better?). But I'm hoping that the local nature of `_` can help combat that, and it fits within the existing style of `_1`, `_2` and `_3`, yet actually feels unique and like something you would want to use. Call it a "local at"?
----------------------------------------
Feature #18980: Re-reconsider numbered parameters: `it` as a default block parameter
https://bugs.ruby-lang.org/issues/18980#change-100379
* Author: k0kubun (Takashi Kokubun)
* Status: Open
* Priority: Normal
----------------------------------------
## Problem
Numbered parameters (`_1`, `_2`, ...) look like unused local variables and I don't feel motivated to use them, even though I need this feature very often and always come up with `_1`.
```rb
[1, 2, 3].each { puts _1 }
```
I have barely used it in the last 2~3 years because it looks like a compromised syntax. I even hesitate to use it on IRB.
### Why I don't use `_1`
I'm not clever enough to remember the order of parameters. Therefore, when a block has multiple parameters, I'd always want to name those parameters because which is `_1` or `_2` is not immediately obvious. Thus I would use this feature only when a block takes a single argument, which is actually pretty common.
If I use `_1`, it feels like there might be a second argument, and you might waste time to think about `_2`, even if `_2` doesn't exist, which is a cognitive overhead. If you use `it`, it kinda implies there's only a single argument, so you don't need to spend time remembering whether `_2` exists or not. It is important for me that there's no number in `it`.
## Proposal
Hoping to introduce `it` as an alternative to `_1` later, experiment with warning `#it` method calls without any arguments or blocks.
If nobody sees serious problems after some warning period, we'll implement `it` as follows:
### Specification
```rb
[1, 2, 3].each { puts it }
```
`it`s behavior should be as close to `_1` as possible. `it` should treat array arguments in the same way as `_1`. `it` doesn't work in a block when an ordinary parameter is defined. `it` is implemented as a special case of `getlocal` insn, not a method. `it` without an argument is considered `_1` or a normal local variable if defined. `it` is considered a method call only when it has any positional/keyword/block arguments.
## Past discussions
* [Feature #4475] default variable name for parameter: Proposed `it`, and merged as `@1`.
* 2019/03/13: [DevelopersMeeting20190311Japan](https://docs.google.com/document/d/e/2PACX-…
* 2019/04/17: [DevelopersMeeting20190417Japan](https://docs.google.com/document/d/1hw6Xca8…
* 2019/04/20: [Ruby Committers vs the World](https://youtu.be/5eAXAUTtNYU?t=3118)
* [Feature #15723] Reconsider numbered parameters: Renamed `@1` to `_1`.
* 2019/08/29: [DevelopersMeeting20190829Japan](https://docs.google.com/document/d/1XypDO1c…
* [Feature #15897] `it` as a default block parameter: Proposed `it`, and got closed because `_1` was merged.
### Compatibility
`it` has not necessarily been rejected by Matz; he just said [it's difficult to keep compatibility](https://bugs.ruby-lang.org/issues/4475#note-6) and [`it` or `this` _could_ break existing code](https://bugs.ruby-lang.org/issues/15723#note-2). It feels like everybody thinks `it` is the most beautiful option but is not sure if `it` breaks compatibility. But, in reality, does `it`?
The following cases have been discussed:
* `it` method, most famously in RSpec: You almost always pass a positional and/or block argument to RSpec's `it`, so the conflict is avoided with my proposal. You virtually never use a completely naked `it` ([comment](https://bugs.ruby-lang.org/issues/15897#note-29)).
* `it` local variable: With the specification in my proposal, the existing code can continue to work if we consider `it` as a local variable when defined.
With the specification in my proposal, existing code seems to break if and only if you call a method `#it` without an argument. But it seems pretty rare (reminder: a block given to an RSpec test case is also an argument). It almost feels like people are too afraid of compatibility problems that barely exist or have not really thought about options to address them.
Also, you could always experiment with just showing warnings, which doesn't break any compatibility. Even if it takes 2~3 years of a warning period, I'd be happy to use that in 3 years.
### Confusion
We should separately discuss incompatible cases and "works but confusing" cases. Potential confusion points:
* RSpec's `it "tests something" do ... end` vs `it` inside the `do ... end`
* `it` could be a local variable or `_1`, depending on the situation
My two cents: You'd rarely need to write `it` directly under RSpec's `it` block, and you would just name a block argument for that case. In a nested block under a test case, I don't think you'd feel `it` is RSpec's. When you use a local variable `it = 1`, you'd use the local variable in a very small scope or few lines because otherwise, it'd be very hard to figure out what the local variable has anyway. So you'd likely see the assignment `it = 1` near the use of the local variable and you could easily notice `it` is not `_1`. If not, such code would be confusing and fragile even without this feature. The same applies when `it` is a method/block argument.
I believe it wouldn't be as confusing as some people think, and you can always choose to not use `it` in places where `it` is confusing.
--
https://bugs.ruby-lang.org/
Issue #19143 has been updated by nobu (Nobuyoshi Nakada).
It is intended.
`*.so` files are architecture-dependent, which are "tainted" in other words, while `lib` directories are architecture-independent, "untainted".
"Tainted" files should not infect "untainted" directories.
----------------------------------------
Bug #19143: Windows - bundled extension gems compile, but don't copy *.so files to lib folder
https://bugs.ruby-lang.org/issues/19143#change-100378
* Author: MSP-Greg (Greg L)
* Status: Closed
* Priority: Normal
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
Just finished updating ruby-loco's mswin build to use a system similar to the ucrt & mingw builds.
Confirmed something I noticed previously, and also occurs with the RubyInstaller2 head build.
On Windows, bundled extension gems (debug, rbs) compile their extension in the `ext` folder, but do not copy them to the `lib` folder. So, the *.so file is created, but not copied.
I think this was working correctly on Ruby 3.1?
--
https://bugs.ruby-lang.org/
Issue #18751 has been updated by matz (Yukihiro Matsumoto).
This should be fixed by #18798 which is accepted.
Matz.
----------------------------------------
Bug #18751: Regression on master for Method#== when comparing public with private method
https://bugs.ruby-lang.org/issues/18751#change-100377
* Author: Eregon (Benoit Daloze)
* Status: Closed
* Priority: Normal
* Assignee: Eregon (Benoit Daloze)
* ruby -v: ruby 3.2.0dev (2022-04-23T02:59:20Z master e142bea799) [x86_64-linux]
* Backport: 2.7: DONTNEED, 3.0: DONTNEED, 3.1: DONTNEED
----------------------------------------
This script repros:
```ruby
class C
class << self
alias_method :n, :new
private :new
end
end
p C.method(:n) == C.method(:new) # => true
puts
p C.method(:n) == Class.method(:new) # => false
p C.method(:n) == Class.method(:new).unbind.bind(C) # => true
puts
p C.method(:new) == Class.method(:new) # => false
p C.method(:new) == Class.method(:new).unbind.bind(C) # => true, BUT false on master
p C.method(:new) == Class.instance_method(:new).bind(C) # => true, BUT false on master
p [C.method(:new), Class.instance_method(:new).bind(C)] # => [#<Method: #<Class:C>(Class)#new(*)>, #<Method: #<Class:C>(Class)#new(*)>]
```
So this prints the expected results on 2.7.5, 3.0.3, 3.1.1 but not on master, which seems a regression.
Notably this breaks the pattern discussed in https://bugs.ruby-lang.org/issues/18729#note-5, and it means there is no way to find out if two methods share the same "definition/logic/def", which is a big limitation.
--
https://bugs.ruby-lang.org/
Issue #18798 has been updated by matz (Yukihiro Matsumoto).
LGTM.
Matz.
----------------------------------------
Feature #18798: `UnboundMethod#==` with inherited classes
https://bugs.ruby-lang.org/issues/18798#change-100374
* Author: ko1 (Koichi Sasada)
* Status: Open
* Priority: Normal
----------------------------------------
Now `UnboundMethod` for a same method from a superclass and an inherited class are not `==`.
```ruby
class C
def foo = :C
$mc = instance_method(:foo)
end
class D < C
$md = instance_method(:foo)
end
p $mc == $md #=> false
p $mc.owner #=> C
p $mc.owner == $md.owner #=> true
p $mc.source_location == $md.source_location #=> true
p $mc.inspect #=> "#<UnboundMethod: C#foo() t.rb:3>"
p $md.inspect #=> "#<UnboundMethod: D(C)#foo() t.rb:3>"
```
How about to make it `UnboundMethod#==` return true for this case?
Rule: "return true if the UnboundMethod objects point to a same method definition" seems simple.
FYI: On aliased unbound methods point to a same method are `==`.
```ruby
class C
def foo = :C
alias bar foo
$mfoo = instance_method(:foo)
$mbar = instance_method(:bar)
end
p $mfoo, $mbar
#=> #<UnboundMethod: C#foo() t.rb:2>
#=> #<UnboundMethod: C#bar(foo)() t.rb:2>
p $mfoo == $mbar #=> true
```
--
https://bugs.ruby-lang.org/
Issue #19047 has been updated by matz (Yukihiro Matsumoto).
Sorry, but by this change, we missed the warnings from DelegateClass misuse. We will revert this change.
Matz.
----------------------------------------
Bug #19047: DelegateClass displays "method redefined" warning when overriding methods
https://bugs.ruby-lang.org/issues/19047#change-100373
* Author: jonathanhefner (Jonathan Hefner)
* Status: Closed
* Priority: Normal
* ruby -v: ruby 3.1.2p20
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
Perhaps this is not a bug, but it does seem unexpected.
When creating a `DelegateClass` class without an intervening ancestor, overriding a method displays "method redefined" warning:
```ruby
Base = Class.new do
def foo
"foo"
end
end
Delegate1 = DelegateClass(Base) do
def foo
super + "1"
end
end
# warning: method redefined; discarding old foo
Delegate2 = Class.new(DelegateClass(Base)) do
def foo
super + "2"
end
end
# no warning
Delegate1.new(Base.new).foo
# => "foo1"
Delegate2.new(Base.new).foo
# => "foo2"
```
One possible solution would be to evaluate the `DelegateClass` block in a separate module, and prepend that module to the returned class.
Another possible solution would be to silence warnings around [when the block is evaluated](https://github.com/ruby/delegate/blob/df2283b8d8874446086b80355c….
I would be happy to submit a PR to https://github.com/ruby/delegate if this is something we want to address.
--
https://bugs.ruby-lang.org/