Redefining String's gsub
I am new to ruby and I just come across my first tricky problem. I am trying to redefine some methods of String in order to attach some functionality around them. The problematic method appears to be gsub. (EDIT) Let me paste my main.rb that showcases this error.
require 'rubygems' if RUBY_VERSION < "1.9"
require 'sinatra'
class String
alias_method :old_gsub, :gsub
def gsub (*params, &block )
old_gsub *params, &block
end
end
get '/' do
s="Hello world! "
end
This is my starting point and I expect this to work just as the original String does. Unfotunately, with this redefinition in place, some existing code breaks.
As you can see in this script, I try to load Sinatra and serve a page. When I do this and request the index, the web server fails with the following output in the console.
127.0.0.1 - - [25/Feb/2011 17:56:26] "GET / HTTP/1.1" 200 13 0.0012 [2011-02-25 17:56:26] ERROR NoMethodError: undefined method `upcase' for nil:NilClass /usr/local/ruby/lib/ruby/1.9.1/webrick/httpresponse.rb:172:in `block (2 levels) in send_header' /data/Dropbox/Ruby/RubyTrack/lib/main.rb:227:in `gsub' /data/Dropbox/Ruby/RubyTrack/lib/main.rb:227:in `gsub' /usr/local/ruby/lib/ruby/1.9.1/webrick/httpresponse.rb:172:in `block in send_header' +plus more stuff in the trace
[2011-02-25 17:56:26] ERROR NoMethodError: undefined method `[]' for nil:NilClass /usr/local/ruby/lib/ruby/1.9.1/webrick/accesslog.rb:52:in `block in format' /data/Dropbox/Ruby/RubyTrack/lib/main.rb:227:in `gsub' /data/Dropbox/Ruby/RubyTrack/lib/main.rb:227:in `gsub' /usr/local/ruby/lib/ruby/1.9.1/webrick/accesslog.rb:50:in `format' +more stuff in the trace
The first exception (httpresponse.rb:172) is on the line
tmp = key.gsub(/\bwww|^te$|\b\w/){ $&.upcase }
and the second error is caused by the result of (accesslog.rb:50)
format_string.gsub(/\%(?:\{(.*?)\})?开发者_Python百科>?([a-zA-Z%])/)
From the above, it appers that I am using Ruby 1.9.1 (even though ruby -v gives me 1.9.2p0). I'm on Ubuntu 10.04. It is true that there may be something wrong in my configuration of Ruby, installing it in Ubuntu was a bit messy.
So, to sum up, why does my redefinition of gsub behave differenlty than the original gsub?
MRI Ruby's internal C code implementation of gsub
does some magic to set up $&
, $1
, and so on in the calling method. When you redefine gsub
, they end up getting set in your redefinition, rather than the caller of your redefinition.
I don't know a way around this in MRI. In Rubinius, enough of the internals are implemented in Ruby and made accessible to user-level code that it is possible. This is something Yehuda Katz touches on in this post.
精彩评论