[#109844] [Ruby master Feature#18996] Proposal: Introduce new APIs to reline for changing dialog UI colours — "st0012 (Stan Lo)" <noreply@...>

Issue #18996 has been reported by st0012 (Stan Lo).

14 messages 2022/09/07

[#109850] [Ruby master Feature#19000] Data: Add "Copy with changes method" [Follow-on to #16122 Data: simple immutable value object] — "RubyBugs (A Nonymous)" <noreply@...>

Issue #19000 has been reported by RubyBugs (A Nonymous).

42 messages 2022/09/08

[#109905] [Ruby master Bug#19005] Ruby interpreter compiled XCode 14 cannot build some native gems on macOS — "stanhu (Stan Hu)" <noreply@...>

Issue #19005 has been reported by stanhu (Stan Hu).

28 messages 2022/09/15

[#109930] [Ruby master Bug#19007] Unicode tables differences from Unicode.org 14.0 data and removed properties since 13.0 — "nobu (Nobuyoshi Nakada)" <noreply@...>

Issue #19007 has been reported by nobu (Nobuyoshi Nakada).

8 messages 2022/09/17

[#109937] [Ruby master Feature#19008] Introduce coverage support for `eval`. — "ioquatix (Samuel Williams)" <noreply@...>

Issue #19008 has been reported by ioquatix (Samuel Williams).

23 messages 2022/09/17

[#109961] [Ruby master Bug#19012] BasicSocket#recv* methods return an empty packet instead of nil on closed connections — "byroot (Jean Boussier)" <noreply@...>

Issue #19012 has been reported by byroot (Jean Boussier).

8 messages 2022/09/20

[#109985] [Ruby master Feature#19015] Language extension by a heredoc — "ko1 (Koichi Sasada)" <noreply@...>

Issue #19015 has been reported by ko1 (Koichi Sasada).

14 messages 2022/09/22

[#109995] [Ruby master Bug#19016] syntax_suggest is not working with Ruby 3.2.0-preview2 — "hsbt (Hiroshi SHIBATA)" <noreply@...>

Issue #19016 has been reported by hsbt (Hiroshi SHIBATA).

9 messages 2022/09/22

[#110097] [Ruby master Feature#19024] Proposal: Import Modules — "shioyama (Chris Salzberg)" <noreply@...>

SXNzdWUgIzE5MDI0IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IHNoaW95YW1hIChDaHJpcyBTYWx6YmVy

27 messages 2022/09/27

[#110119] [Ruby master Bug#19026] Add `Coverage.supported?(x)` to detect support for `eval` coverage flag. — "ioquatix (Samuel Williams)" <noreply@...>

SXNzdWUgIzE5MDI2IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGlvcXVhdGl4IChTYW11ZWwgV2lsbGlh

10 messages 2022/09/28

[#110133] [Ruby master Bug#19028] GCC12 Introduces new warn flags `-Wuse-after-free` — "eightbitraptor (Matthew Valentine-House)" <noreply@...>

SXNzdWUgIzE5MDI4IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGVpZ2h0Yml0cmFwdG9yIChNYXR0aGV3

8 messages 2022/09/28

[#110145] [Ruby master Misc#19030] [ANN] Migrate lists.ruby-lang.org to Google Groups — "hsbt (Hiroshi SHIBATA)" <noreply@...>

SXNzdWUgIzE5MDMwIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGhzYnQgKEhpcm9zaGkgU0hJQkFUQSku

12 messages 2022/09/29

[#110154] [Ruby master Bug#19033] One-liner pattern match as Boolean arg syntax error — "baweaver (Brandon Weaver)" <noreply@...>

SXNzdWUgIzE5MDMzIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGJhd2VhdmVyIChCcmFuZG9uIFdlYXZl

7 messages 2022/09/30

[ruby-core:109809] [Ruby master Feature#18951] Object#with to set and restore attributes around a block

From: "p8 (Petrik de Heus)" <noreply@...>
Date: 2022-09-01 10:37:15 UTC
List: ruby-core #109809
Issue #18951 has been updated by p8 (Petrik de Heus).


Or maybe making the restore more explicit
``` ruby
obj.assign_attrs(foo: "bar") do
  # do something
end.restore

```

``` ruby
obj.assign_attrs(foo: "bar") do |restorable|
  # do something
ensure
  restorable.restore
end
```

----------------------------------------
Feature #18951: Object#with to set and restore attributes around a block
https://bugs.ruby-lang.org/issues/18951#change-99049

* 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], ...)`





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