Ruby 2.0.0 mini-highlights

Ruby 2.0.0-rc1 is out, and the big stuff has already been pretty well-covered – lazy enumerators, keyword arguments, Module#prepend (although I hope to cover that a little later, to show an example of why I’m so excited about it). Refinements are in there but experimental, and I wouldn’t bet on them staying for too long.

There’s more fun stuff in the NEWS file, though.

Kernel#caller_locations. This isn’t very well-documented (something in Ruby poorly documented? no way!) It’s a close parallel to Kernel#caller, which you may have used before:

>> pp caller
["/home/mboeh/.rvm/rubies/ruby-2.0.0-rc1/lib/ruby/2.0.0/irb/workspace.rb:86:in `eval'",
 "/home/mboeh/.rvm/rubies/ruby-2.0.0-rc1/lib/ruby/2.0.0/irb/workspace.rb:86:in `evaluate'",
 "/home/mboeh/.rvm/rubies/ruby-2.0.0-rc1/lib/ruby/2.0.0/irb/context.rb:366:in `evaluate'",
 ...]

On first blush, caller_locations seems to do the same thing:

>> pp caller_locations
["/home/mboeh/.rvm/rubies/ruby-2.0.0-rc1/lib/ruby/2.0.0/irb/workspace.rb:86:in `eval'",
 "/home/mboeh/.rvm/rubies/ruby-2.0.0-rc1/lib/ruby/2.0.0/irb/workspace.rb:86:in `evaluate'",
 "/home/mboeh/.rvm/rubies/ruby-2.0.0-rc1/lib/ruby/2.0.0/irb/context.rb:366:in `evaluate'",
 ...]

But in the second example, those aren’t actually Strings!

>> caller.first.class
 => String
>> caller_locations.first.class
 => Thread::Backtrace::Location

Thread::Backtrace::Location is also minimally documented, but it essentially provides structured access to the data that makes up each line of the backtrace.

>> caller_locations.first.absolute_path
 => "/home/mboeh/.rvm/rubies/ruby-2.0.0-rc1/lib/ruby/2.0.0/irb/workspace.rb"
>> caller_locations.first.label
 => "eval"
>> caller_locations.first.lineno
 => 86

This should make any code that has to print, rewrite, or otherwise reflect on and manipulate the backtrace cleaner and more obvious. Thread#backtrace_locations provides the same functionality versus Thread#backtrace.

Thread-local variables. In Ruby 1.9, thread-local variables (as accessed with Thread# and friends) are actually Fiber-local variables. Ruby 2.0 keeps this behavior but also includes Thread#thread_variable_get and Thread#thread_variable_set, which appear to be scoped to the current Thread. The Fiber-local behavior had been causing problems with concurrency libraries like Celluloid (which uses Fibers heavily) and ActiveRecord, which used thread-local variables to store a checked-out connection from the connection pool. Fiber-heavy code ended up checking out many more connections than was warranted.

Module#const_get. Have you ever found yourself writing non-Rails code and really wanting String#constantize? I’ve copied around a minimal implementation of that method more often than I’d care to say. Well, now const_get does it for you.

>> Kernel.const_get "Thread::Backtrace::Location"
 => Thread::Backtrace::Location

Lots more in there, too.