Is there a replacement for sub?

The primary problem is that sub! returns nil when no substitutions are made.

I have similar problem with Array#flatten!, Array#uniq! since it causes problem when chaining!
My solution has been to override these bang! methods to return self even when the bang! method did not have to change the receiver.

for sub! I would override the sub! method as follow

class String
  alias old_sub! sub!
  def sub!(pattern, replacement)
      self.old_sub!(pattern, replacement)
      self
  end
end

As a user of a method, I really do not care if the method did not have to do anything so long as the object is in the desired state.

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]

···

ruby-talk-admin@ruby-lang.org wrote:

------------------------------------------------------------------------

Subject:
Re: Is there a replacement for sub?
From:
"Robert Dober" <robert.dober@gmail.com>
Date:
Fri, 20 Jul 2007 20:49:07 +0900
To:
ruby-talk@ruby-lang.org (ruby-talk ML)

To:
ruby-talk@ruby-lang.org (ruby-talk ML)

On 7/20/07, Martin DeMello <martindemello@gmail.com> wrote:

On 7/20/07, Robert Dober <robert.dober@gmail.com> wrote:
>
> I was reading this whole thread and I kind of think to be dreaming, I
> must have missed something obvious!!!
> Anyway maybe this is was OP wants, well I think it is :wink:
>
> 529/29 > irb
> irb(main):001:0> a='a b c d e f'
> => "a b c d e f"
> irb(main):002:0> a.gsub!(" ","")

Nope, he wants a method that only replaces the first n occurrences of
the pattern. gsub will not do this - you need to run sub in a loop.
(This is where perl's "continue matching where you left off" would
have been a nice optimisation)

Bernard Kenik wrote:

------------------------------------------------------------------------

Subject:
Re: Is there a replacement for sub?
From:
"Robert Dober" <robert.dober@gmail.com>
Date:
Fri, 20 Jul 2007 20:49:07 +0900
To:
ruby-talk@ruby-lang.org (ruby-talk ML)

To:
ruby-talk@ruby-lang.org (ruby-talk ML)

>
> I was reading this whole thread and I kind of think to be dreaming, I
> must have missed something obvious!!!
> Anyway maybe this is was OP wants, well I think it is :wink:
>
> 529/29 > irb
> irb(main):001:0> a='a b c d e f'
> => "a b c d e f"
> irb(main):002:0> a.gsub!(" ","")

Nope, he wants a method that only replaces the first n occurrences of
the pattern. gsub will not do this - you need to run sub in a loop.
(This is where perl's "continue matching where you left off" would
have been a nice optimisation)

The primary problem is that sub! returns nil when no substitutions are made.

I have similar problem with Array#flatten!, Array#uniq! since it causes problem when chaining!
My solution has been to override these bang! methods to return self even when the bang! method did not have to change the receiver.

for sub! I would override the sub! method as follow

class String
alias old_sub! sub!
def sub!(pattern, replacement)
     self.old_sub!(pattern, replacement)
     self
end
end

And this can easily be expanded to do what I was trying to do in the first place! Adding the following method with your replacement method:

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

With this I can specify a.subn!(' ', '', 10) and it will return 'abcdef' just like I was looking for. It will work with zero or negative values returning 'a b c d e f', again like I would expect. Of course if you enter a non-integer value it will error out in its current state but the error is from the times method.

As a user of a method, I really do not care if the method did not have to do anything so long as the object is in the desired state.

I too hate surprises.

···

ruby-talk-admin@ruby-lang.org wrote:

On 7/20/07, Martin DeMello <martindemello@gmail.com> wrote:

On 7/20/07, Robert Dober <robert.dober@gmail.com> wrote:

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]

Hi --

------------------------------------------------------------------------

Subject:
Re: Is there a replacement for sub?
From:
"Robert Dober" <robert.dober@gmail.com>
Date:
Fri, 20 Jul 2007 20:49:07 +0900
To:
ruby-talk@ruby-lang.org (ruby-talk ML)

To:
ruby-talk@ruby-lang.org (ruby-talk ML)

>
> I was reading this whole thread and I kind of think to be dreaming, I
> must have missed something obvious!!!
> Anyway maybe this is was OP wants, well I think it is :wink:
>
> 529/29 > irb
> irb(main):001:0> a='a b c d e f'
> => "a b c d e f"
> irb(main):002:0> a.gsub!(" ","")

Nope, he wants a method that only replaces the first n occurrences of
the pattern. gsub will not do this - you need to run sub in a loop.
(This is where perl's "continue matching where you left off" would
have been a nice optimisation)

The primary problem is that sub! returns nil when no substitutions are made.

I have similar problem with Array#flatten!, Array#uniq! since it causes problem when chaining!
My solution has been to override these bang! methods to return self even when the bang! method did not have to change the receiver.

for sub! I would override the sub! method as follow

class String
alias old_sub! sub!
def sub!(pattern, replacement)
    self.old_sub!(pattern, replacement)
    self
end

As a user of a method, I really do not care if the method did not have to do anything so long as the object is in the desired state.

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]

I would very, very strongly advise you, and everyone else, not to do
this. You will break any code (inside the standard library and/or any
other code you load, or any code that uses your code) that depends on
the documented behavior of these methods. You may not like how sub!
and friends work, but it's a very bad idea to make the decision to
change them on behalf of everyone else, over and above the language
documentation.

David

···

On Sun, 22 Jul 2007, Bernard Kenik wrote:

ruby-talk-admin@ruby-lang.org wrote:

On 7/20/07, Martin DeMello <martindemello@gmail.com> wrote:

On 7/20/07, Robert Dober <robert.dober@gmail.com> wrote:

--
* Books:
   RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242\)
   RUBY FOR RAILS (http://www.manning.com/black\)
* Ruby/Rails training
     & consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

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"

···

On Jul 21, 11:40 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> wrote:

Bernard Kenik wrote:
> ruby-talk-ad...@ruby-lang.org wrote:

>> ------------------------------------------------------------------------

>> Subject:
>> Re: Is there a replacement for sub?
>> From:
>> "Robert Dober" <robert.do...@gmail.com>
>> Date:
>> Fri, 20 Jul 2007 20:49:07 +0900
>> To:
>> ruby-t...@ruby-lang.org (ruby-talk ML)

>> To:
>> ruby-t...@ruby-lang.org (ruby-talk ML)

>> On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:
>>> On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:

>>> > I was reading this whole thread and I kind of think to be dreaming, I
>>> > must have missed something obvious!!!
>>> > Anyway maybe this is was OP wants, well I think it is :wink:

>>> > 529/29 > irb
>>> > irb(main):001:0> a='a b c d e f'
>>> > => "a b c d e f"
>>> > irb(main):002:0> a.gsub!(" ","")

>>> Nope, he wants a method that only replaces the first n occurrences of
>>> the pattern. gsub will not do this - you need to run sub in a loop.
>>> (This is where perl's "continue matching where you left off" would
>>> have been a nice optimisation)

> The primary problem is that sub! returns nil when no substitutions are
> made.

> I have similar problem with Array#flatten!, Array#uniq! since it causes
> problem when chaining!
> My solution has been to override these bang! methods to return self even
> when the bang! method did not have to change the receiver.

> for sub! I would override the sub! method as follow

> class String
> alias old_sub! sub!
> def sub!(pattern, replacement)
> self.old_sub!(pattern, replacement)
> self
> end
> end

And this can easily be expanded to do what I was trying to do in the
first place! Adding the following method with your replacement method:

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

With this I can specify a.subn!(' ', '', 10) and it will return 'abcdef'
just like I was looking for. It will work with zero or negative values
returning 'a b c d e f', again like I would expect. Of course if you
enter a non-integer value it will error out in its current state but the
error is from the times method.

> As a user of a method, I really do not care if the method did not have
> to do anything so long as the object is in the desired state.

I too hate surprises.

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

dblack@wobblini.net wrote:

Hi --

------------------------------------------------------------------------

Subject:
Re: Is there a replacement for sub?
From:
"Robert Dober" <robert.dober@gmail.com>
Date:
Fri, 20 Jul 2007 20:49:07 +0900
To:
ruby-talk@ruby-lang.org (ruby-talk ML)

To:
ruby-talk@ruby-lang.org (ruby-talk ML)

>
> I was reading this whole thread and I kind of think to be dreaming, I
> must have missed something obvious!!!
> Anyway maybe this is was OP wants, well I think it is :wink:
>
> 529/29 > irb
> irb(main):001:0> a='a b c d e f'
> => "a b c d e f"
> irb(main):002:0> a.gsub!(" ","")

Nope, he wants a method that only replaces the first n occurrences of
the pattern. gsub will not do this - you need to run sub in a loop.
(This is where perl's "continue matching where you left off" would
have been a nice optimisation)

The primary problem is that sub! returns nil when no substitutions are made.

I have similar problem with Array#flatten!, Array#uniq! since it causes problem when chaining!
My solution has been to override these bang! methods to return self even when the bang! method did not have to change the receiver.

for sub! I would override the sub! method as follow

class String
alias old_sub! sub!
def sub!(pattern, replacement)
    self.old_sub!(pattern, replacement)
    self
end

As a user of a method, I really do not care if the method did not have to do anything so long as the object is in the desired state.

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]

I would very, very strongly advise you, and everyone else, not to do
this. You will break any code (inside the standard library and/or any
other code you load, or any code that uses your code) that depends on
the documented behavior of these methods. You may not like how sub!
and friends work, but it's a very bad idea to make the decision to
change them on behalf of everyone else, over and above the language
documentation.

What I planned to do was get rid of the alias and change the name of the 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.

···

On Sun, 22 Jul 2007, Bernard Kenik wrote:

ruby-talk-admin@ruby-lang.org wrote:

On 7/20/07, Martin DeMello <martindemello@gmail.com> wrote:

On 7/20/07, Robert Dober <robert.dober@gmail.com> wrote:

David

bbiker wrote:

···

On Jul 21, 11:40 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> > wrote:

Bernard Kenik wrote:

ruby-talk-ad...@ruby-lang.org wrote:

------------------------------------------------------------------------
Subject:
Re: Is there a replacement for sub?
From:
"Robert Dober" <robert.do...@gmail.com>
Date:
Fri, 20 Jul 2007 20:49:07 +0900
To:
ruby-t...@ruby-lang.org (ruby-talk ML)
To:
ruby-t...@ruby-lang.org (ruby-talk ML)
On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:

On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:

I was reading this whole thread and I kind of think to be dreaming, I
must have missed something obvious!!!
Anyway maybe this is was OP wants, well I think it is :wink:
529/29 > irb
irb(main):001:0> a='a b c d e f'
=> "a b c d e f"
irb(main):002:0> a.gsub!(" ","")

Nope, he wants a method that only replaces the first n occurrences of
the pattern. gsub will not do this - you need to run sub in a loop.
(This is where perl's "continue matching where you left off" would
have been a nice optimisation)

The primary problem is that sub! returns nil when no substitutions are
made.
I have similar problem with Array#flatten!, Array#uniq! since it causes
problem when chaining!
My solution has been to override these bang! methods to return self even
when the bang! method did not have to change the receiver.
for sub! I would override the sub! method as follow
class String
alias old_sub! sub!
def sub!(pattern, replacement)
     self.old_sub!(pattern, replacement)
     self
end
end

And this can easily be expanded to do what I was trying to do in the
first place! Adding the following method with your replacement method:

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

With this I can specify a.subn!(' ', '', 10) and it will return 'abcdef'
just like I was looking for. It will work with zero or negative values
returning 'a b c d e f', again like I would expect. Of course if you
enter a non-integer value it will error out in its current state but the
error is from the times method.

As a user of a method, I really do not care if the method did not have
to do anything so long as the object is in the desired state.

I too hate surprises.

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"

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.

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

···

On Jul 22, 10:39 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> wrote:

dbl...@wobblini.net wrote:
> Hi --

> On Sun, 22 Jul 2007, Bernard Kenik wrote:

>> ruby-talk-ad...@ruby-lang.org wrote:

>>> ------------------------------------------------------------------------

>>> Subject:
>>> Re: Is there a replacement for sub?
>>> From:
>>> "Robert Dober" <robert.do...@gmail.com>
>>> Date:
>>> Fri, 20 Jul 2007 20:49:07 +0900
>>> To:
>>> ruby-t...@ruby-lang.org (ruby-talk ML)

>>> To:
>>> ruby-t...@ruby-lang.org (ruby-talk ML)

>>> On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:
>>>> On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:

>>>> > I was reading this whole thread and I kind of think to be dreaming, I
>>>> > must have missed something obvious!!!
>>>> > Anyway maybe this is was OP wants, well I think it is :wink:

>>>> > 529/29 > irb
>>>> > irb(main):001:0> a='a b c d e f'
>>>> > => "a b c d e f"
>>>> > irb(main):002:0> a.gsub!(" ","")

>>>> Nope, he wants a method that only replaces the first n occurrences of
>>>> the pattern. gsub will not do this - you need to run sub in a loop.
>>>> (This is where perl's "continue matching where you left off" would
>>>> have been a nice optimisation)

>> The primary problem is that sub! returns nil when no substitutions are
>> made.

>> I have similar problem with Array#flatten!, Array#uniq! since it
>> causes problem when chaining!
>> My solution has been to override these bang! methods to return self
>> even when the bang! method did not have to change the receiver.

>> for sub! I would override the sub! method as follow

>> class String
>> alias old_sub! sub!
>> def sub!(pattern, replacement)
>> self.old_sub!(pattern, replacement)
>> self
>> end
>> end

>> As a user of a method, I really do not care if the method did not have
>> to do anything so long as the object is in the desired state.

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

> I would very, very strongly advise you, and everyone else, not to do
> this. You will break any code (inside the standard library and/or any
> other code you load, or any code that uses your code) that depends on
> the documented behavior of these methods. You may not like how sub!
> and friends work, but it's a very bad idea to make the decision to
> change them on behalf of everyone else, over and above the language
> documentation.

What I planned to do was get rid of the alias and change the name of the
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 -

Hi --

···

On Mon, 23 Jul 2007, Michael W. Ryder wrote:

What I planned to do was get rid of the alias and change the name of the 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.

I suspect you're not giving yourself enough credit :slight_smile: Anyway, soon
it won't be overnight anymore :slight_smile: Meanwhile, I think doing it in an
additive way is definitely better, though not entirely clash-proof.

David

--
* Books:
   RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242\)
   RUBY FOR RAILS (http://www.manning.com/black\)
* Ruby/Rails training
     & consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

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 23, 11:51 am, bbiker <renard3...@gmail.com> wrote:

On Jul 22, 10:39 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> > wrote:

> dbl...@wobblini.net wrote:
> > Hi --

> > On Sun, 22 Jul 2007, Bernard Kenik wrote:

> >> ruby-talk-ad...@ruby-lang.org wrote:

> >>> ------------------------------------------------------------------------

> >>> Subject:
> >>> Re: Is there a replacement for sub?
> >>> From:
> >>> "Robert Dober" <robert.do...@gmail.com>
> >>> Date:
> >>> Fri, 20 Jul 2007 20:49:07 +0900
> >>> To:
> >>> ruby-t...@ruby-lang.org (ruby-talk ML)

> >>> To:
> >>> ruby-t...@ruby-lang.org (ruby-talk ML)

> >>> On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:
> >>>> On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:

> >>>> > I was reading this whole thread and I kind of think to be dreaming, I
> >>>> > must have missed something obvious!!!
> >>>> > Anyway maybe this is was OP wants, well I think it is :wink:

> >>>> > 529/29 > irb
> >>>> > irb(main):001:0> a='a b c d e f'
> >>>> > => "a b c d e f"
> >>>> > irb(main):002:0> a.gsub!(" ","")

> >>>> Nope, he wants a method that only replaces the first n occurrences of
> >>>> the pattern. gsub will not do this - you need to run sub in a loop.
> >>>> (This is where perl's "continue matching where you left off" would
> >>>> have been a nice optimisation)

> >> The primary problem is that sub! returns nil when no substitutions are
> >> made.

> >> I have similar problem with Array#flatten!, Array#uniq! since it
> >> causes problem when chaining!
> >> My solution has been to override these bang! methods to return self
> >> even when the bang! method did not have to change the receiver.

> >> for sub! I would override the sub! method as follow

> >> class String
> >> alias old_sub! sub!
> >> def sub!(pattern, replacement)
> >> self.old_sub!(pattern, replacement)
> >> self
> >> end
> >> end

> >> As a user of a method, I really do not care if the method did not have
> >> to do anything so long as the object is in the desired state.

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

> > I would very, very strongly advise you, and everyone else, not to do
> > this. You will break any code (inside the standard library and/or any
> > other code you load, or any code that uses your code) that depends on
> > the documented behavior of these methods. You may not like how sub!
> > and friends work, but it's a very bad idea to make the decision to
> > change them on behalf of everyone else, over and above the language
> > documentation.

> What I planned to do was get rid of the alias and change the name of the
> 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- Hide quoted text -

- Show quoted text -

bbiker wrote:

···

On Jul 22, 10:39 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> > wrote:

dbl...@wobblini.net wrote:

Hi --
On Sun, 22 Jul 2007, Bernard Kenik wrote:

ruby-talk-ad...@ruby-lang.org wrote:

------------------------------------------------------------------------
Subject:
Re: Is there a replacement for sub?
From:
"Robert Dober" <robert.do...@gmail.com>
Date:
Fri, 20 Jul 2007 20:49:07 +0900
To:
ruby-t...@ruby-lang.org (ruby-talk ML)
To:
ruby-t...@ruby-lang.org (ruby-talk ML)
On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:

On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:

I was reading this whole thread and I kind of think to be dreaming, I
must have missed something obvious!!!
Anyway maybe this is was OP wants, well I think it is :wink:
529/29 > irb
irb(main):001:0> a='a b c d e f'
=> "a b c d e f"
irb(main):002:0> a.gsub!(" ","")

Nope, he wants a method that only replaces the first n occurrences of
the pattern. gsub will not do this - you need to run sub in a loop.
(This is where perl's "continue matching where you left off" would
have been a nice optimisation)

The primary problem is that sub! returns nil when no substitutions are
made.
I have similar problem with Array#flatten!, Array#uniq! since it
causes problem when chaining!
My solution has been to override these bang! methods to return self
even when the bang! method did not have to change the receiver.
for sub! I would override the sub! method as follow
class String
alias old_sub! sub!
def sub!(pattern, replacement)
    self.old_sub!(pattern, replacement)
    self
end
As a user of a method, I really do not care if the method did not have
to do anything so long as the object is in the desired state.
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]

I would very, very strongly advise you, and everyone else, not to do
this. You will break any code (inside the standard library and/or any
other code you load, or any code that uses your code) that depends on
the documented behavior of these methods. You may not like how sub!
and friends work, but it's a very bad idea to make the decision to
change them on behalf of everyone else, over and above the language
documentation.

What I planned to do was get rid of the alias and change the name of the
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

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.

for single substitution you can use subn!(pattern, replacement) since
n defaults to 1. Ditto for subn.

···

On Jul 23, 2:53 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> wrote:

bbiker wrote:
> On Jul 22, 10:39 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> > > wrote:
>> dbl...@wobblini.net wrote:
>>> Hi --
>>> On Sun, 22 Jul 2007, Bernard Kenik wrote:
>>>> ruby-talk-ad...@ruby-lang.org wrote:
>>>>> ------------------------------------------------------------------------
>>>>> Subject:
>>>>> Re: Is there a replacement for sub?
>>>>> From:
>>>>> "Robert Dober" <robert.do...@gmail.com>
>>>>> Date:
>>>>> Fri, 20 Jul 2007 20:49:07 +0900
>>>>> To:
>>>>> ruby-t...@ruby-lang.org (ruby-talk ML)
>>>>> To:
>>>>> ruby-t...@ruby-lang.org (ruby-talk ML)
>>>>> On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:
>>>>>> On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:
>>>>>>> I was reading this whole thread and I kind of think to be dreaming, I
>>>>>>> must have missed something obvious!!!
>>>>>>> Anyway maybe this is was OP wants, well I think it is :wink:
>>>>>>> 529/29 > irb
>>>>>>> irb(main):001:0> a='a b c d e f'
>>>>>>> => "a b c d e f"
>>>>>>> irb(main):002:0> a.gsub!(" ","")
>>>>>> Nope, he wants a method that only replaces the first n occurrences of
>>>>>> the pattern. gsub will not do this - you need to run sub in a loop.
>>>>>> (This is where perl's "continue matching where you left off" would
>>>>>> have been a nice optimisation)
>>>> The primary problem is that sub! returns nil when no substitutions are
>>>> made.
>>>> I have similar problem with Array#flatten!, Array#uniq! since it
>>>> causes problem when chaining!
>>>> My solution has been to override these bang! methods to return self
>>>> even when the bang! method did not have to change the receiver.
>>>> for sub! I would override the sub! method as follow
>>>> class String
>>>> alias old_sub! sub!
>>>> def sub!(pattern, replacement)
>>>> self.old_sub!(pattern, replacement)
>>>> self
>>>> end
>>>> end
>>>> As a user of a method, I really do not care if the method did not have
>>>> to do anything so long as the object is in the desired state.
>>>> 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]
>>> I would very, very strongly advise you, and everyone else, not to do
>>> this. You will break any code (inside the standard library and/or any
>>> other code you load, or any code that uses your code) that depends on
>>> the documented behavior of these methods. You may not like how sub!
>>> and friends work, but it's a very bad idea to make the decision to
>>> change them on behalf of everyone else, over and above the language
>>> documentation.
>> What I planned to do was get rid of the alias and change the name of the
>> 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

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.- Hide quoted text -

- Show quoted text -

<snip>

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

Yours yes, mine not at all

... unless gsub!(..., ...)

is quite useful to me.

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.

That is a different case, I adhere to your POV on this one.

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.

Why should he? He *might* consider it if it were a largely discussed
and backed up RCR, there seems some way to go...

Robert

···

On 7/23/07, bbiker <renard3411@gmail.com> wrote:
--

We're on a mission from God. ~ Elwood,

bbiker wrote:
<snip>

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

Is there any reason you used the above three lines instead of:
       @str = self
       n.times { @str = @str.sub(pattern, replacement) }

As I mentioned in an earlier post times seems to work fine with zero or negative values not changing the string. The replacement code seems "cleaner" but I may be missing some gotcha that your code prevents.
Again, thanks for improving my knowledge of Ruby.

···

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

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

Yours yes, mine not at all

.. unless gsub!(..., ...)

is quite useful to me.

well how about this counter example?

str = "hello"

str.downcase!.capitalize! => NoMethodError: undefined method
`captitalize!' for nil:NilClass

My point is that method chaining is a common ruby idiom and nil
returns get in the way!!!

I believe that there was/is a thread regarding chaining when a method
returns nil.

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

Why should he? He *might* consider it if it were a largely discussed
and backed up RCR, there seems some way to go...

That's for sure. I know that I am whistling in the wind. :<o)

···

On Jul 23, 4:38 pm, "Robert Dober" <robert.do...@gmail.com> wrote:

On 7/23/07, bbiker <renard3...@gmail.com> wrote:

# str = "hello"
# str.downcase!.capitalize! => NoMethodError: undefined method
# `captitalize!' for nil:NilClass

···

From: bbiker [mailto:renard3411@gmail.com]
#
# My point is that method chaining is a common ruby idiom and nil
# returns get in the way!!!

imnsh opinion,

bang methods do _not_ look nice on chains. In fact, they look like they cut chains :slight_smile:

use non-bang methods instead. syntax is very clean.

these are some stupid examples,

irb(main):001:0> "asdf".downcase
=> "asdf"
irb(main):002:0> "asdf".downcase!
=> nil
irb(main):003:0> "asdf".downcase.capitalize.capitalize
=> "Asdf"
irb(main):004:0> "asdf".downcase!
=> nil
irb(main):005:0> "asdf".downcase!.capitalize!
NoMethodError: undefined method `capitalize!' for nil:NilClass
        from (irb):5
        from :0
irb(main):006:0> "asdfX".downcase!.capitalize!
=> "Asdfx"
irb(main):007:0> "asdfX".downcase!.capitalize!.capitalize!
=> nil
irb(main):008:0> "asdfX".downcase!.capitalize!.capitalize!.capitalize!
NoMethodError: undefined method `capitalize!' for nil:NilClass
        from (irb):8
        from :0
irb(main):009:0> "asdfX".downcase.capitalize.capitalize.capitalize
=> "Asdfx"

kind regards -botp