From: eregontp@... Date: 2016-09-21T11:13:34+00:00 Subject: [ruby-core:77334] [Ruby trunk Bug#12521] Syntax for retrieving argument without removing it from double-splat catch-all 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: