Ruby 2.0.0 mini-highlights, part two

I posted yesterday about the release of Ruby 2.0.0rc1, and today I have a few more neat little things to highlight.

__dir__. Where once you may have done this:

require File.dirname(__FILE__) + "/../some_other_file"

you can now use __dir__, which returns the value of File.dirname(__FILE__):

require __dir__ + "/../some_other_file"

and, being cleaner, it makes it more pleasant to use File.join:

require File.join(__dir__, "../some_other_file")

If only __dir__ was a Pathname instead of a String, so we could do nice stuff like

require __dir__.join("../some_other_file")

but I suppose since Pathname is in the stdlib, not core, that wouldn’t work. (I wish Pathname was in core.)

Array#bsearch, Range#bsearch. Array#bsearch has pretty clear documentation and I won’t bother to try to duplicate it. Range#bsearch is a little bit more subtle – its documentation is similar, and mostly shows it being used as an alternative to Array#bsearch.

What’s interesting about Range#bsearch is that it allows you to more efficiently search through indefinite or expensive collections or sequences. Unfortunately, the neat (albeit extremely contrived) examples I tried to come up with failed, because it only works with numeric ranges:

>> ((Date.today - 365) .. Date.today).bsearch{|date| puts "grepping through #{date} logs for request number 999,999"; date.to_s >= "2012-11-07" }
 TypeError: can't do binary search for Date

>> ("aaa" ... "zzz").bsearch{|str| str >= "vux" }
 TypeError: can't do binary search for String

This was a little bit disappointing, but I’ll admit I can’t think of a lot of really practical uses for binary searches across date or string ranges. (Would have been fun, though…)

Module#define_method. I am really excited about this. Module#define_method can now directly take UnboundMethods (which is what you get from Module#instance_method), which allows you to include methods from one class or module one-by-one, instead of en masse.

Obviously, this isn’t something you want to do arbitrarily, since one method might not operate in the absence of another. In most cases, Object#extend and Module#include are what you want to use. However, this could be a building block for people who want to implement more structured mixin systems. Starting with something like this:

class Module                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                            
  def include_methods(mod, *names)                                                                                                                                                                                                                                          
    names.flatten.each do |name|                                                                                                                                                                                                                                            
      define_method name, mod.instance_method(name)                                                                                                                                                                                                                         
    end                                                                                                                                                                                                                                                                     
  end                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                            
end                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                            
module GrabBag                                                                                                                                                                                                                                                              
                                                                                                                                                                                                                                                                            
  def orz                                                                                                                                                                                                                                                                   
    "orz"                                                                                                                                                                                                                                                                   
  end                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                            
  def vux                                                                                                                                                                                                                                                                   
    "vux"                                                                                                                                                                                                                                                                   
  end                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                            
  def urquan                                                                                                                                                                                                                                                                
    "urquan"                                                                                                                                                                                                                                                                
  end                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                            
end                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                            
class Choosy                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                            
  include_methods GrabBag, %i[orz vux]                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                            
end                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                            
puts Choosy.new.orz   #  "orz"                                                                                                                                                                                                                                                      
puts Choosy.new.vux   #  "vux"                                                                                                                                                                                                                                                    
puts Choosy.new.respond_to?(:urquan)  # false

I can see this being particularly useful in games and large applications which want to implement a controlled version of include, where user-provided mixins are less likely to stomp on methods they shouldn’t. I once implemented an “adjective and noun” system for a game engine using mixins and a C implementation of ‘unextend’. This would have made that whole project much easier.

net/http improvements. I’m hoping to find more information on these changes, because they sound pretty amazing:

* Proxies are now automatically detected from the http_proxy environment
  variable.  See Net::HTTP::new for details.
* gzip and deflate compression are now requested for all requests by
  default.  See Net::HTTP for details.
* SSL sessions are now reused across connections for a single instance.
  This speeds up connection by using a previously negotiated session.
* Requests may be created from a URI which sets the request_uri and host
  header of the request (but does not change the host connected to).
* Responses contain the URI requested which allows easier implementation of
  redirect following.

I know from experience that net/http can be really slow when making a lot of SSL requests. The session reuse should really help – but only if you’re making multiple requests with a single instance, which a lot of people don’t. Eric Hodel has been working on making net/http suck less recently, and this appears to be mostly his work.

Symbol list literal. This says it all:

>> %i[orz vux spathi urquan]
 => [:orz, :vux, :spathi, :urquan]

If you’ve been wanting it, you’ve really wanted it. If you have no idea why anyone would want that, you probably don’t need it. But I’m extremely happy about it.

There’s other, bigger things I haven’t covered because I expect them to be covered heavily and by clearer writers than myself (keyword arguments, lazy enumerators) or because I don’t understand what the deal is with them yet (Onigmo) or because they make me sad (refinements), but little improvements like the ones above have as much of an impact on daily development work as those big headline features.