Project

General

Profile

Actions

Feature #16796

closed

Assigning local variables when using `case when regexp`

Added by UlyssesZhan (Ulysses Zhan) about 4 years ago. Updated over 1 year ago.

Status:
Rejected
Assignee:
-
Target version:
-
[ruby-core:97935]

Description

I want to use

case "str"
when /s(?<mid>.)r/
  p mid
end

instead of

case
when /s(?<mid>.)r/ =~ "str"
  p mid
end

I also do not like using $1.

This feature is extremely useful when there are a lot of whens.

Updated by nobu (Nobuyoshi Nakada) about 4 years ago

It is because when calls === method but not =~.

Updated by sawa (Tsuyoshi Sawada) about 4 years ago

I have met such use cases, and agree this would be useful.

Alternatively, in order to access even unnamed matches, assigning the last matched data to a variable with the following syntax may be useful.

case "str"
when /s(?<mid>.)r/ => match_data
  match_data[:mid] # => "t"
end
case "str"
when /s(.)r/ => match_data
  match_data[1] # => "t"
end

Updated by shyouhei (Shyouhei Urabe) about 4 years ago

sawa (Tsuyoshi Sawada) wrote in #note-2:

Alternatively, in order to access even unnamed matches, assigning the last matched data to a variable with the following syntax may be useful.

case "str"
when /s(.)r/ => match_data
  match_data[1] # => "t"
end

That's too confusing. The following code works today.

case "str"
in /s(.)r/ => match_data
  match_data[1] # => "t"
end

Updated by shevegen (Robert A. Heiler) about 4 years ago

sawa wrote:

I have met such use cases, and agree this would be useful.

I don't disagree in the sense that there may be valid use cases,
but the syntax is kind of weird:

/s(?<mid>.)r/

I use regexes a lot of course, since they are useful. But do we
really gain a lot from making what used to be simple, harder?

I understand that you may avoid an extra step (assignment, after
the regex match), but to me personally I find that style so
much harder to read, compared to:

if /(foo.+)/
  mid = $1.to_s.dup # or something like that
end

Admittedly I am very much a very oldschool-ruby person. ;)

By the way, while I personally do not really like $ variables,
I actually use them a LOT, whereas I rarely use match_data[]
syntax style. Dunno why, perhaps a habit, but the $1 $2 etc..
are ony of the few (semi) global variables that I like.
(I write "semi" because they tend to be more volatile, which
is why I may tend to use .dup like a semi-crazy person a
lot, rather than fix a regex or handle nils - I .to_s.dup
all the things! ;) )

Updated by matz (Yukihiro Matsumoto) about 4 years ago

  • Status changed from Open to Rejected

Implicit assignment from regular expression matches has been a bad idea. I shouldn't have merged it at the first moment.
I'd like to remove it altogether if I have a chance. So I don't like to enhance it any further.

Matz.

Updated by milouse (Étienne Deparis) over 1 year ago

shyouhei (Shyouhei Urabe) wrote in #note-3:

sawa (Tsuyoshi Sawada) wrote in #note-2:

That's too confusing. The following code works today.

case "str"
in /s(.)r/ => match_data
  match_data[1] # => "t"
end

Not really (or at least it is not what I understand from the original request, as I felt on a similar issue today). You are just pointing out an edge case where match_data[1] will be t, not because it is actually a MatchData object, which first capturing group worth t, but just because the pattern matching feature select this branch and put the original String "str" onto match_data. Thus match_data[1] here only gives you the second char of the string match_data.

The previous example would have fail (in my understanding of the problem), with the following regexp:

case "str"
in /(.)tr/ => match_data
  match_data[1] # => "t" instead of the expected "s"
end

By the way, there is in fact a very simple way to achieve the initial goal (again, from my understanding of the problem):

case "str"
when /s(?<mid>.)r/
  match_data = Regexp.last_match
  p match_data[:mid]
end
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0