[#117021] [Ruby master Feature#20318] Pattern matching `case ... in` support for triple-dot arguments — "bradgessler (Brad Gessler) via ruby-core" <ruby-core@...>

Issue #20318 has been reported by bradgessler (Brad Gessler).

11 messages 2024/03/01

[#117027] [Ruby master Bug#20319] Singleton class is being frozen lazily in some cases — "andrykonchin (Andrew Konchin) via ruby-core" <ruby-core@...>

Issue #20319 has been reported by andrykonchin (Andrew Konchin).

8 messages 2024/03/01

[#117036] [Ruby master Bug#20321] `require': cannot load such file — "Justman10000 (Justin Nogossek) via ruby-core" <ruby-core@...>

Issue #20321 has been reported by Justman10000 (Justin Nogossek).

14 messages 2024/03/01

[#117067] [Ruby master Feature#20326] Add an `undefined` for use as a default argument. — "shan (Shannon Skipper) via ruby-core" <ruby-core@...>

Issue #20326 has been reported by shan (Shannon Skipper).

7 messages 2024/03/06

[#117115] [Ruby master Feature#20331] Should parser warn hash duplication and when clause? — "yui-knk (Kaneko Yuichiro) via ruby-core" <ruby-core@...>

Issue #20331 has been reported by yui-knk (Kaneko Yuichiro).

11 messages 2024/03/12

[#117147] [Ruby master Feature#20335] `Thread.each_caller_location` should accept the same arguments as `caller` and `caller_locations` — "byroot (Jean Boussier) via ruby-core" <ruby-core@...>

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

13 messages 2024/03/14

[#117157] [Ruby master Misc#20336] DevMeeting-2024-04-17 — "mame (Yusuke Endoh) via ruby-core" <ruby-core@...>

Issue #20336 has been reported by mame (Yusuke Endoh).

15 messages 2024/03/14

[#117212] [Ruby master Feature#20345] Add `--target-rbconfig` option to mkmf — "katei (Yuta Saito) via ruby-core" <ruby-core@...>

Issue #20345 has been reported by katei (Yuta Saito).

9 messages 2024/03/18

[#117240] [Ruby master Feature#20350] Return chilled string from Symbol#to_s — "Dan0042 (Daniel DeLorme) via ruby-core" <ruby-core@...>

Issue #20350 has been reported by Dan0042 (Daniel DeLorme).

10 messages 2024/03/19

[#117288] [Ruby master Misc#20387] Meta-ticket for ASAN support — "kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core" <ruby-core@...>

Issue #20387 has been reported by kjtsanaktsidis (KJ Tsanaktsidis).

10 messages 2024/03/22

[#117321] [Ruby master Bug#20393] `after_fork_ruby` clears all pending interrupts for both parent and child process. — "ioquatix (Samuel Williams) via ruby-core" <ruby-core@...>

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

6 messages 2024/03/26

[#117324] [Ruby master Feature#20394] Add an offset parameter to `String#to_i` — "byroot (Jean Boussier) via ruby-core" <ruby-core@...>

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

16 messages 2024/03/26

[#117341] [Ruby master Feature#20396] ObjectSpace.dump_all(string_value: false): skip dumping the String contents — "byroot (Jean Boussier) via ruby-core" <ruby-core@...>

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

8 messages 2024/03/27

[#117390] [Ruby master Feature#20404] `2pi` — "mame (Yusuke Endoh) via ruby-core" <ruby-core@...>

Issue #20404 has been reported by mame (Yusuke Endoh).

9 messages 2024/03/31

[ruby-core:117041] [Ruby master Feature#20318] Pattern matching `case ... in` support for triple-dot arguments

From: "nobu (Nobuyoshi Nakada) via ruby-core" <ruby-core@...>
Date: 2024-03-03 05:16:42 UTC
List: ruby-core #117041
Issue #20318 has been updated by nobu (Nobuyoshi Nakada).


A patch for @ko1 style.

Probably the code generation would be more efficient in compile.c.

```diff
commit dcf97d47ad721bfbdae230234056df8a02044c7d
Author:     Nobuyoshi Nakada (nobu) <nobu@ruby-lang.org>
AuthorDate: 2024-03-03 14:13:23 +0900
Commit:     Nobuyoshi Nakada (nobu) <nobu@ruby-lang.org>
CommitDate: 2024-03-03 14:13:23 +0900

    [Feature #20318] Method dispatch per `in`

diff --git a/parse.y b/parse.y
index de90ee797ff..6623a5bffa0 100644
--- a/parse.y
+++ b/parse.y
@@ -1581,6 +1581,7 @@ static NODE *new_args_forward_call(struct parser_params*, NODE*, const YYLTYPE*,
 static int check_forwarding_args(struct parser_params*);
 static void add_forwarding_args(struct parser_params *p);
 static void forwarding_arg_check(struct parser_params *p, ID arg, ID all, const char *var);
+static NODE *new_method_case_args(struct parser_params *p);
 
 static const struct vtable *dyna_push(struct parser_params *);
 static void dyna_pop(struct parser_params*, const struct vtable *);
@@ -2740,7 +2741,7 @@ rb_parser_string_hash_cmp(rb_parser_string_t *str1, rb_parser_string_t *str2)
 %type <node> literal numeric simple_numeric ssym dsym symbol cpath
 %type <node_def_temp> defn_head defs_head k_def
 %type <node_exits> block_open k_while k_until k_for allow_exits
-%type <node> top_compstmt top_stmts top_stmt begin_block endless_arg endless_command
+%type <node> top_compstmt top_stmts top_stmt begin_block endless_arg endless_command method_body
 %type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call
 %type <node> expr_value expr_value_do arg_value primary_value rel_expr
 %type <node_fcall> fcall
@@ -2980,6 +2981,14 @@ bodystmt	: compstmt[body]
                     }
                 ;
 
+method_body	: bodystmt
+                | p_case_body[body]
+                    {
+                        $$ = NEW_CASE3(new_method_case_args(p), $body, &@body);
+                    /*% ripper: case!(Qnil, $:body) %*/
+                    }
+                ;
+
 compstmt	: stmts terms?
                     {
                         $$ = void_stmts(p, $1);
@@ -4604,7 +4613,7 @@ primary		: literal
                     {
                         push_end_expect_token_locations(p, &@head.beg_pos);
                     }
-                  bodystmt
+                  method_body[bodystmt]
                   k_end
                     {
                         restore_defun(p, $head);
@@ -4619,7 +4628,7 @@ primary		: literal
                     {
                         push_end_expect_token_locations(p, &@head.beg_pos);
                     }
-                  bodystmt
+                  method_body[bodystmt]
                   k_end
                     {
                         restore_defun(p, $head);
@@ -15543,6 +15552,33 @@ new_args_forward_call(struct parser_params *p, NODE *leading, const YYLTYPE *loc
     return arg_blk_pass(args, block);
 }
 
+static NODE *
+new_method_case_args(struct parser_params *p)
+{
+    if (!local_id(p, idFWD_ALL)) {
+        compile_error(p, "not defined with ...");
+        return Qnone;
+    }
+
+    const YYLTYPE *loc = &NULL_LOC;
+    NODE *rest = NEW_LVAR(idFWD_REST, loc);
+#ifndef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
+    NODE *kwrest = NEW_LVAR(idFWD_KWREST, loc);
+#endif
+    NODE *block = NEW_LVAR(idFWD_BLOCK, loc);
+
+    NODE *args = NEW_SPLAT(rest, loc);
+#ifndef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
+    NODE *kwsplat = list_append(p, NEW_LIST(0, loc), kwrest);
+    args = NEW_ARGSPUSH(args, NEW_HASH(kwsplat, loc), loc);
+#endif
+    args = NEW_ARGSCAT(args, NEW_SPLAT(block, loc), loc);
+
+    NODE *cond = NEW_AND(NEW_CALL(rest, idEmptyP, 0, loc),
+                         NEW_CALL(block, '!', 0, loc), loc);
+    return NEW_IF(cond, kwrest, args, loc);
+}
+
 static NODE *
 numparam_push(struct parser_params *p)
 {
```


----------------------------------------
Feature #20318: Pattern matching `case ... in` support for triple-dot arguments
https://bugs.ruby-lang.org/issues/20318#change-107111

* Author: bradgessler (Brad Gessler)
* Status: Open
----------------------------------------

# Premise

Sometimes when I'm creating a method for an API, I'd like to do pattern matching against the arguments. Today I have to do something like this:

```ruby
def foo(*args, **kwargs, &block)
  case { args:, kwargs:, block: }
    in args: [name]
      puts name
    in args: [first_name, last_name]
      puts "Hi there #{first_name} #{last_name}"
    in kwargs: {greeting:}
      puts "Hello #{greeting}"
    else
      puts "No match: #{args}"
  end
end

foo "Hi"
foo "Brad", "Gessler"
foo greeting: "Brad"
```

Or an array like this:

```ruby
def bar(*args, **kwargs, &block)
  case [args, kwargs, block]
    in [name], {}, nil
      puts name
    in [first_name, last_name], {}, nil
      puts "Hi there #{first_name} #{last_name}"
    in [], {greeting:}, nil
      puts "Hello #{greeting}"
    else
      puts "No match: #{args}, #{kwargs}"
  end
end

bar "Howdy"
bar "Bradley", "Gessler"
bar greeting: "Bradley"
```

# Proposal

I'd like to propose the same thing, but for `...`, like this:

```ruby
def foo(...)
  case ...
    in args: [name]
      puts name
    in args: [first_name, last_name]
      puts "Hi there #{first_name} #{last_name}"
    in kwargs: {greeting:}
      puts "Hello #{greeting}"
    else
      puts "No match: #{args}"
  end
end

foo "Hi"
foo "Brad", "Gessler"
foo greeting: "Brad"
```

One thing I'm not sure sure about: the `args`, `kwargs`, and `block` names appear out of thin air, so ideally those could somehow be named or have a syntax that doesn't require those names.

The array would look like this:

```ruby
def bar(...)
  case ...
    in [name], {}, nil
      puts name
    in [first_name, last_name], {}, nil
      puts "Hi there #{first_name} #{last_name}"
    in [], {greeting:}, nil
      puts "Hello #{greeting}"
    else
      puts "No match: #{args}, #{kwargs}"
  end
end

bar "Howdy"
bar "Bradley", "Gessler"
bar greeting: "Bradley"
```



-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

In This Thread