Is there a replacement for sub?

On Jul 22, 10:39 pm, “Michael W. Ryder” [email protected]
wrote:

Re: Is there a replacement for sub?
On 7/20/07, Martin DeMello [email protected] wrote:

My solution has been to override these bang! methods to return self
end
p arr => [1, 2, 3, 4, 5, 6]
new sub! method to something like subf! for just that reason. I still
prefer this version much better than the original version as there are
no surprises. It is very hard to change 30+ years of practice overnight.

David- Hide quoted text -

  • Show quoted text – Hide quoted text -

  • Show quoted text -

Actually you do not have to define subf! as an intermediate step
you can directly define subn and subn! directly

class String
def subn!(pattern, replacement, n = 1)
n.times { self.sub!(pattern, replacement) }
self # or return self
end

def subn(pattern, replacement, n = 1)
return self if n < 1
@str = self.sub(pattern, replacement)
(n-1).times { @str = @str.sub(pattern, replacement) }
@str # or return @str
end
end

Note that sub and sub! are the original definitions

You use subn(pattern, replacement) and subn!(pattern, replacement) as
substitutes for sub(pattern, replacement) and sub!(pattern,
replacement) which eliminate the unpleasant surprises.

In addition, both can be safely chained !!!

Hope this helps

bbiker wrote:

Fri, 20 Jul 2007 20:49:07 +0900

irb(main):001:0> a=‘a b c d e f’
My solution has been to override these bang! methods to return self even
first place! Adding the following method with your replacement method:
just like I was looking for. It will work with zero or negative values
For an array such as arr = [1,2,3,4,5,6], I can safely chain the bang!

instead of => “j i h g f e d cba”

I made your suggested change with one cosmetic change. I added return
in front of the self to remind me what is the result of the method.
Thanks for the improvement.

bbiker wrote:

“Robert D.” [email protected]

Anyway maybe this is was OP wants, well I think it is :wink:
I have similar problem with Array#flatten!, Array#uniq! since it
end
other code you load, or any code that uses your code) that depends on

n.times { self.sub!(pattern, replacement) }

Note that sub and sub! are the original definitions

You use subn(pattern, replacement) and subn!(pattern, replacement) as
substitutes for sub(pattern, replacement) and sub!(pattern,
replacement) which eliminate the unpleasant surprises.

In addition, both can be safely chained !!!

Hope this helps

Thanks for the updated code. I think I will keep the subf and subf!
definitions for when I want to do single replacements that are free of
surprises. Maybe I will someday be able to use the original definitions
with confidence but when I am in the middle of a programming run I hate
to stop and look up language definitions to avoid problems. It just
ruins the flow of thought.

On Jul 23, 11:51 am, bbiker [email protected] wrote:

On Sun, 22 Jul 2007, Bernard K. wrote:

Fri, 20 Jul 2007 20:49:07 +0900

must have missed something obvious!!!
have been a nice optimisation)

other code you load, or any code that uses your code) that depends on
David- Hide quoted text -
n.times { self.sub!(pattern, replacement) }

  • Show quoted text -
    You might consider adding the following, so you have a matching
    replacement set for sub, sub!, gsub, and gsub!

You can think of gsubn and gsubn! as no nil returns :>)

class String
def subn!(pattern, replacement, n = 1)
n.times { self.sub!(pattern, replacement) }
self
end

def subn(pattern, replacement, n = 1)
return self if n < 1
@str = self.sub(pattern, replacement)
(n-1).times { @str = @str.sub(pattern, replacement) }
@str
end

def gsubn!(pattern, replacement)
self.gsub!(pattern, replacement)
self # does not return nil if no
changes were made
end

alias gsubn gsub # you can use either gsubn or gsub
end

My primary objection to have a nil return is that it prevents me from
safely chaining bang! methods.

The nil return is counter-intuitive and violates the Principle of
Least Surprise

As I said before given an array such as arr = [1, 2, 3, 4, 5, 6], I
can do

new_arr = arr.flatten.uniq.sort => [1, 2, 3, 4, 5, 6]

Intuitively I would think that I should be able to do
arr.flatten!.uniq!.sort!; however because of the nil return by
#flatten!, a NoMethodError is raised by #uniq! since the nil object
does not have a uniq! method.

Note that not all bang! methods return nil when nothing was changed in
the receiver. Array#sort! return self if self was already sorted.

Hopefully Matz might be reading this thread and might consider
changing the behavior of bang! methods returns.

On Jul 21, 11:40 pm, “Michael W. Ryder” [email protected]
wrote:

Fri, 20 Jul 2007 20:49:07 +0900

must have missed something obvious!!!
have been a nice optimisation)

returning ‘a b c d e f’, again like I would expect. Of course if you

For an array such as arr = [1,2,3,4,5,6], I can safely chain the bang!
methods without worrying about nil returns from flatten! and uniq!

arr.flatten!.uniq!.sort! # NO ERROR MSG “undefined method `uniq!’ for
nil:NilClass (NoMethodError)” because flatten! would have returned nil
p arr => [1, 2, 3, 4, 5, 6]- Hide quoted text -

  • Show quoted text – Hide quoted text -

  • Show quoted text -

Note that as written, subn! returns n. So if you need to do some
chaining, you should change subn! as follows:

def subn!(pattern, replacement, n=1)
n.times { self.sub!(pattern, replacement) }
self
end

str = “a b c d e f g h i j”
str.subn!(/ /,‘’,2).reverse! # won’t produce an error msg such as

C:/Documents … /rb5C.tmp:30: undefined method `reverse!’ for
1:Fixnum (NoMethodError)

instead of => “j i h g f e d cba”