Objetos Method no Ligados (Unbound Method Objects)

Ruby soporta métodos unbound. Métodos que no están asociados con un objeto particular. Cuando se usa instance_method se obtiene un método unbound. Los métodos unbound sólo pueden ser llamados después que son ligados a algún objeto.

Los objetos de la clase UnboundMethod representan métodos pero sin el objeto Binding que define su entorno de ejecución.

ruby-1.9.2-head :001 > unbound_plus = Fixnum.instance_method("+")
 => #<UnboundMethod: Fixnum#+> 
ruby-1.9.2-head :002 > plus_5 = unbound_plus.bind(5)
 => #<Method: Fixnum#+> 
ruby-1.9.2-head :003 > plus_5[4]
 => 9 
ruby-1.9.2-head :004 > plus_5.class
 => Method

También es posible construir objetos UnboundMethod usando el método unbind:

ruby-1.9.2-head :014 > x = 4.method('+')
 => #<Method: Fixnum#+> 
ruby-1.9.2-head :015 > u = x.unbind
 => #<UnboundMethod: Fixnum#+> 
ruby-1.9.2-head :016 > w = u.bind(3)
 => #<Method: Fixnum#+> 
ruby-1.9.2-head :017 > w[5]
 => 8

~/rubytesting$ cat -n instance_method.rb 
     1  class Interpreter
     2    def do_a() print "there, "; end
     3    def do_d() print "Hello ";  end
     4    def do_e() print "!\n";     end
     5    def do_v() print "Dave";    end
     6    Dispatcher = {
     7     ?a => instance_method(:do_a),
     8     ?d => instance_method(:do_d),
     9     ?e => instance_method(:do_e),
    10     ?v => instance_method(:do_v)
    11    }
    12    def interpret(string)
    13      string.each_byte {|b| Dispatcher[b].bind(self).call }
    14    end
    15  end
    16  
    17  interpreter = Interpreter.new
    18  interpreter.interpret('dave')
Al ejecutar, se obtiene:

~/rubytesting$ ruby instance_method.rb 
Hello there, Dave!

El operador de interrogación nos dá el código de un carácter:

>> ?a
=> 97
>> 'a'[0]
=> 97
>> 97.chr
=> "a"

Veamos otro ejemplo:

MacBook-Air-de-casiano:rubytesting casiano$ ruby -r debug unbound_method.rb 
unbound_method.rb:1:class Square
(rdb:1) l 1,100
[1, 100] in unbound_method.rb
=> 1  class Square
   2    def area
   3      @side * @side
   4    end
   5    def initialize(side)
   6      @side = side
   7    end
   8  end
   9  
   10  area_un = Square.instance_method(:area)
   11  
   12  s = Square.new(12)
   13  area = area_un.bind(s)
   14  area.call   #=> 144

(rdb:1) b 14
Set breakpoint 1 at unbound_method.rb:14
(rdb:1) c
Breakpoint 1, toplevel at unbound_method.rb:14
unbound_method.rb:14:area.call   #=> 144
(rdb:1) area.call
144

Casiano Rodriguez León 2015-06-18