The following script doesn't work...
Do you have any idea of what is wrong?
Is it a ruby bug? (ruby version: ruby 1.9.1p243 (2009-07-16 revision
24175) [i386-darwin9])
require 'time'
Time.parse("1999-10-31 16:46:50") # this works
class String
alias_method :old_sub!, :sub!
def sub!(*args, &block)
old_sub!(*args, &block)
end
end
Time.parse("1999-10-31 16:46:50") # this crashes
# =>
#
# ArgumentError: argument out of range
# from /opt/local/lib/ruby1.9/1.9.1/time.rb:202:in `local'
# from /opt/local/lib/ruby1.9/1.9.1/time.rb:202:in `make_time'
# from /opt/local/lib/ruby1.9/1.9.1/time.rb:261:in `parse'
# from (irb):10
# from /opt/local/bin/irb1.9:12:in `<main>'
on 2009-11-02 12:49
on 2009-11-02 13:08
Thomas Sevestre wrote: > > The following script doesn't work... > Do you have any idea of what is wrong? There are loads of sub! calls in date/format.rb, but I have no idea why delegating sub! in this way would break it. I note that the same error occurs in 1.8.6 too: ArgumentError: argument out of range from /usr/lib/ruby/1.8/time.rb:184:in `local' from /usr/lib/ruby/1.8/time.rb:184:in `make_time' from /usr/lib/ruby/1.8/time.rb:243:in `parse' from (irb):19 I copied time.rb to my local directory and modified it to puts the arguments to local. I see that it is calling Time.local(1999, 10, 31, 16, 46, 50, 0) before the sub! change, but Time.local(2009,0,1,0,0,0,0) after it. Most bizarre.
on 2009-11-02 13:40
Hi -- On Mon, 2 Nov 2009, Brian Candler wrote: > from /usr/lib/ruby/1.8/time.rb:184:in `local' > > Time.local(2009,0,1,0,0,0,0) > > after it. Most bizarre. I believe it's about the $1, $2... variables: "abc".sub!(/(.)/, "z") p $1 # nil "abc".old_sub!(/(.)/, "z") p $1 # "a" When sub! calls old_sub!, the $n variables inside sub! are not set, but the ones in old_sub! are. When the date parser hits _parse_iso (or whichever of that family of methods it hits), there are calls to sub! followed by usage of the $n variables, which are actually not set because they're two methods removed. A more generic example: def y(str) /(.)/.match(str) p $1 end def x(str) y(str) p $1 end x("abc") => "a" nil David -- The Ruby training with D. Black, G. Brown, J.McAnally Compleat Jan 22-23, 2010, Tampa, FL Rubyist http://www.thecompleatrubyist.com David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)
on 2009-11-02 14:23
> A more generic example:
So the $~ variables are both thread-local *and* scoped to the enclosing
method? That's definitely new to me. Thanks for the explanation.
on 2009-11-02 16:31
Interesting! I wasn't aware of that.
Is there any way to make it work?
It is feasible in your generic example:
def y(str, b)
eval "/(.)/.match(str)", b
p $1
end
def x(str)
y(str, binding)
p $1
end
x("abc")
# =>
#
# nil
# "a"
But in my case, I need to find the caller's binding :
class String
alias_method :old_sub!, :sub!
def sub!(*args, &block)
eval "old_sub!(*args, &block)", caller_binding
end
end
But I havn't been able to retrieve it :( Do you have any idea?
Thomas
on 2009-11-02 18:13
On Mon, Nov 2, 2009 at 9:31 AM, Thomas Sevestre <ts@tcare.fr> wrote: > Interesting! I wasn't aware of that. > > Is there any way to make it work? It is not possible to make it work. I have written on this previously, but it's a particular ugly wart of Ruby that the $_ and $~ variables (and related vars like $1, $&, etc) are "special", and only certain core class methods are able to modify them (in the caller's scope) while no Ruby code can. It is for this reason that you can't alias and wrap any of those methods without breaking them. To be honest, Ruby would be *far* better off if $_ and $~ went away, since I believe they're overreaching by modifying the caller's scope without your knowledge. - Charlie
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.