[ruby-core:77334] [Ruby trunk Bug#12521] Syntax for retrieving argument without removing it from double-splat catch-all
From:
eregontp@...
Date:
2016-09-21 11:13:34 UTC
List:
ruby-core #77334
Issue #12521 has been updated by Benoit Daloze.
Tomohiro Hashidate wrote:
> I want this feature.
> Keyword argument is safer and more explanatory than splat style.
> But I sometimes want to pass whole arguments to other methods.
>
> Example.
> CLI gem that uses AWS api and accepts api key, secret key, region, and endpoint as command options.
>
> ~~~ ruby
> class KMS
> def initialize(key_id, region:, access_key_id: nil, secret_access_key: nil)
> @client = Aws::KMS::Client.new({
> region: region,
> access_key_id: access_key_id,
> secret_access_key: secret_access_key,
> })
> @key_id = key_id
> end
> # ...
> end
> ~~~
>
> If I can use `__keyargs__` (tentative name), I can omit redundant lines.
>
> ~~~ ruby
> class KMS
> def initialize(key_id, region:, access_key_id: nil, secret_access_key: nil)
> @client = Aws::KMS::Client.new(__keyargs__) # simple
> @key_id = key_id
> end
>
> # ...
> ~~~
Why is it better than this?
~~~ ruby
class KMS
def initialize(key_id, **auth)
@client = Aws::KMS::Client.new(**auth) # simple
@key_id = key_id
end
# ...
~~~
It seems to me the Aws::KMS::Client should validate its arguments anyway, and this also reduces duplication.
If a different API must be provided for KMS#initialize, then I think the explicit style is much better as it's less magic and error-prone.
----------------------------------------
Bug #12521: Syntax for retrieving argument without removing it from double-splat catch-all
https://bugs.ruby-lang.org/issues/12521#change-60580
* Author: Guyren Howe
* Status: Closed
* Priority: Normal
* Assignee:
* ruby -v:
* Backport: 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN
----------------------------------------
There is an interesting style of programming that is *almost* really easy to do in Ruby. It would work elegantly with a simple change. A double-colon keyword argument should be available that will still leave the same argument captured by a double-splat argument if present. With this available, it becomes easy to pass down a "context" through a call chain.
Consider this:
```ruby
def controller name::, **context
…
log_then_render something:, name:, **context
end
def log_then_render **context
log context
complex_logic_then_render **context
end
def complex_logic_then_render name::, **context
…
Bunch of further calls
def render name::, something::, **context
…
end
```
Now assume I decide render needs a foo argument, that I obtain in my controller. The only functions that are aware of or have any need for the argument are controller and render. With functions written in this style, I only need to modify the two functions that need to know about the argument:
```ruby
def controller name::, **context
…
log_then_render something:, name:, foo: foo_value, **context
end
… no changes …
def render name::, something::, foo:: **context
… now use foo …
end
```
This is, I accept, unusual. I've not seen a language that offers this sort of feature (I call them, for various reason I don't have time to go into now, FREST functions). I can basically implement this now with a decorator, but it's a little ugly and slow.
It just occurred to me that an alternative would be a triple-splat final argument (or some such) that gathers all the keywords.
There is a related problem with the way double-splat and regular keyword arguments interact that should be fixed anyway.
--
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>