Issue #12745 has been updated by shugo (Shugo Maeda).


jeremyevans0 (Jeremy Evans) wrote:
> * Passing a second argument to the block breaks if the block is a lambda.
> * A keyword argument via `:md` is currently allowed but ignored.  I don't think that breaks compatibility, but with the discussion of keyword arguments in #14183, introducing an `:md` keyword argument may make it harder to transition such code to Ruby 3. 
> * `subm` and `gsubm` are both fairly cryptic in terms of method names, but compared to other approaches, new method names seem to be the best way to handle this if we want to add support for it.

I prefer to the last approach, but don't like names `subm` and `gsubm`.

How about `repl` and `repl_all`?
JavaScripts's `replace` is similar to Ruby's `sub`, but Ruby has already `replace` and it's destructive.
`repl` is an abbreviation for replace. `grepl` is confusing with `grep`, so I propose `repl_all` instead.

And I prefer to `match_all` for the MatchData version of `scan` (#5749).



----------------------------------------
Feature #12745: String#(g)sub(!) should pass a MatchData to the block, not a String
https://bugs.ruby-lang.org/issues/12745#change-82169

* Author: herwin (Herwin W)
* Status: Feedback
* Priority: Normal
* Assignee: matz (Yukihiro Matsumoto)
* Target version: 
----------------------------------------
A simplified (and stupid) example: replace some placeholders in a string with function calls

~~~ruby
def placeholder(val)
  raise 'Incorrect value' unless val == 'three'
  '3'
end

str = '1.2.[three].4'
str.gsub!(/\[(\w+)\]/) { |m| placeholder(m) }
~~~

This raises the 'incorrect value' because we don't pass the match 'three', but the full string '[three]'. It looks like we have 3 options to fix that:

1. Match `[three]` instead of `three` in the placeholder replacement method
2. Pass `m[1..-2]` instead of `m` to the method (or strip it in `placeholder`)
3. Use `$1` in the method call, ignore the value that's passed to the block

Options 1 and 2 look kind of code duplication to me (and they're possible in the simplified example, but might get tricky in real situations). I don't like option 3 because you completely ignore the value that's been passed to the block in favor of global variables, you can't use named captures, and writing code this way makes it incompatible with Rubinius.

I think it would be more logical to pass a `MatchData` (like what you'd get with `String#match`) instead of a `String` to the block. The `#to_s` returns the whole string, so in 90% of the use cases the code could remain unaltered, but the remaining 10% makes it a change that shouldn't be backported to 2.3.

Attached is a very naive patch to pass a matchdata to the block called by `String#sub`. The additional change in `rbinstall.rb` was required to run `make install`, which actually shows an incompatiblity (which I hadn't anticipated)

---Files--------------------------------
ruby_string_sub_matchdata.diff (952 Bytes)


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