Issue #12719 has been updated by marcotc (Marco Costa).


To add a real-world use-case: in the [`ddtrace gem`](https://github.com/DataDog/dd-trace-rb) we have a [configuration Struct called `AgentSettings`](https://github.com/DataDog/dd-trace-rb/blob/b1bd0c025e26d47508996c0b7928fcc366cc0fad/lib/ddtrace/configuration/agent_settings_resolver.rb#L22-L42) that holds the global defaults for our configuration:

``` ruby
AgentSettings = Struct.new(
  :ssl,
  :hostname,
  :port,
  :timeout_seconds,
  :deprecated_for_removal_transport_configuration_proc,
  :deprecated_for_removal_transport_configuration_options
) do
  def initialize(
    ssl:,
    hostname:,
    port:,
    timeout_seconds:,
    deprecated_for_removal_transport_configuration_proc:,
    deprecated_for_removal_transport_configuration_options:,
  )
    super(ssl, hostname, port, timeout_seconds, deprecated_for_removal_transport_configuration_proc, \
              deprecated_for_removal_transport_configuration_options)
    freeze
  end
end
```

But in a few places we want to [override some of the default configuration values](https://github.com/DataDog/dd-trace-rb/blob/e391d2eb64d3c6151a4bdd2710c6a8c7c1d57457/lib/ddtrace/profiling/transport/http.rb#L76-L81):

```ruby
transport.adapter(
  default_adapter,
  agent_settings.hostname,
  agent_settings.port,
  # We explicitly use profiling_upload_timeout_seconds instead of agent_settings.timeout because profile
  # uploads are bigger and thus we employ a separate configuration.
  timeout: profiling_upload_timeout_seconds,
  ssl: agent_settings.ssl
)
```

Today we resort to unpacking the Struct and effectively transferring the values to a hash (in the form of keyword arguments). We don't actually want our Struct to become a hash (or keyword arguments) when we pass it to `#adapter` in the example above, we would like a `AgentSettings` struct to be passed but with `timeout` overridden.

----------------------------------------
Feature #12719: `Struct#merge` for partial updates
https://bugs.ruby-lang.org/issues/12719#change-93944

* Author: halogenandtoast (Matthew Mongeau)
* Status: Feedback
* Priority: Normal
----------------------------------------
Other languages have operators for performing partial updates on maps. I feel like Struct could be more useful if it provided an easy way of performing partial (or full) updates.

After the change you can do the following:

~~~ ruby
Point = Struct.new(:x, :y)

p = Point.new(1, 2)
p2 = p.merge(y: 4)
p3 = p2.merge(x: 10)

p.inspect     # => #<struct Point x=1, y=2>
p2.inspect   # => #<struct Point x=1, y=4>
p3.inspect   # => #<struct Point x=10, y=4>

p.merge!("x" => 9)

p.inspect    # => #<struct Point x=9, y=2>
~~~

---Files--------------------------------
struct_merge.patch (2.93 KB)


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