def nsub!(*args)
      if m = query_str.match(args[0])    # m will now hold the FIRST set of backreferenced matches
        # there is at least one match
        @changed_in ||= []
        @changed_in << caller[1][/(\w+)\W*$/, 1]
        if block_given?
          # query_str.gsub!(args[0]) {yield(*m.to_a[1..-1])}    # There is a bug here: If gsub matches more than once,
                                                      # then the first set of referenced matches will be passed to the block
          ret_str = m.pre_match + m[0].sub(args[0]) { yield(*m.to_a[1..-1]) }   # this will take care of the first set of matches
          while (m_old = m.dup) && (m = m.post_match.match(args[0]))
            ret_str << m.pre_match + m[0].sub(args[0]) { yield(*m.to_a[1..-1]) }
          end
          ret_str << m_old.post_match
          query_str.sub!(/.*/, ret_str)
        else
          query_str.gsub!(args[0], args[1])
        end
      end
    end
def nsub!(*args)
      if m = query_str.match(args[0])    # m will now hold the FIRST set of backreferenced matches
        # there is at least one match
        @changed_in ||= []
        @changed_in << caller[1][/(\w+)\W*$/, 1]
        if block_given?
          # query_str.gsub!(args[0]) {yield(*m.to_a[1..-1])}    # There is a bug here: If gsub matches more than once,
                                                      # then the first set of referenced matches will be passed to the block
          ret_str = m.pre_match + m[0].sub(args[0]) { yield(*m.to_a[1..-1]) }   # this will take care of the first set of matches
          while (m_old = m.dup) && (m = m.post_match.match(args[0]))
            ret_str << m.pre_match + m[0].sub(args[0]) { yield(*m.to_a[1..-1]) }
          end
          ret_str << m_old.post_match
          query_str.sub!(/.*/, ret_str)
        else
          query_str.gsub!(args[0], args[1])
        end
      end
    end
Usage:
   self.nsub!(/foo/, 'bar')

 nsub! is like gsub! except it logs the calling method in @changed_in.
 There is another difference: When using blocks, matched strings are
 available as block params, e.g.: # nsub!(/(match1)(match2)/) {|m1,m2|}

 I wrote this because I was having problems overriding gsub and passing
 a block from the new gsub to super.