How to manually delegate an object in Ruby

1

To better understand meta-programming in Ruby I would like to make an object, when instantiated, delegate all methods of an object passed as a parameter. And your class will delegate the methods that the class contains. However, I would like Object and Class methods, such as: send and object_id, which can cause errors if changed,

I thought of something like:

 def delegate_all
    delegate_instance if !@delegated
    delegate_singleton if !@@delegated
end
def delegate_instance
    ((@model.class.instance_methods-Object.instance_methods)-Class.instance_methods).each do |name|
            name = name.to_sym
            puts name.to_s
            self.class.send(:define_method, name){ |*args|
                method = @model.method name
                #if method.arity > 0
                    method.call args
                #else
                #   method.call
                #end        
            }
    end
    @delegated = true
end 
def delegate_singleton
    ((@model.class.singleton_methods-Class.singleton_methods)-Object.singleton_methods).each do |name|
        name = name.to_sym
        puts name.to_s
        self.class.define_singleton_method(name){|*args|
            name = name.to_sym
            method = @model.singleton_method name
            #if method.arity > 0
                method.call args
            #else
            #   method.call
            #end    
        }
    end
    @@delegated = true  
end

Does anyone have any idea how I can do this ?, but I should also consider methods with parameters.

    
asked by anonymous 24.01.2015 / 01:01

2 answers

1

The simplest way is to work with method_missing , like this:

class SimpleDelegator < BasicObject
  def initialize(obj)
    @obj = obj
  end
  def method_missing(method, *args, &block)
    SimpleDelegator.new(@obj.send(method, *args, &block))
  end
  def inspect
    "SimpleDelegator for #{@obj.inspect}"
  end
  def to_s
    "SimpleDelegator for #{@obj.to_s}"
  end
end

x = SimpleDelegator.new(3)
y = x+2
print y  #=> SimpleDelegator for 5
print y.class #=> SimpleDelegator

The advantage of doing so is that you do not need to know what the object's methods are before you create the delegator, any non-standard method is immediately passed on to the delegate object. Notice that I used the inheritance of BasicObject to have as few methods as possible in the class.

BasicObject.instance_methods
# => [:==, :equal?, :!, :!=, :instance_eval, :instance_exec,
#     :__send__, :__id__, :__binding__]

But note that not even these methods are needed for the class to work. You can quietly define it like this:

class SimpleDelegator < BasicObject
  instance_methods.each {|m| undef_method m } # remove todo e qualquer método
  def initialize(obj)
    @obj = obj
  end
  def method_missing(method, *args, &block)
    SimpleDelegator.new(@obj.send(method, *args, &block))
  end
end

x = SimpleDelegator.new(3)
y = x+2
print y  #=> 5
print y.class #=> Fixnum (note que não deixou de ser um SimpleDelegator)
    
25.01.2015 / 19:53
0

There is a solution to this problem in stdlib called SimpleDelegator:

link

    
07.04.2015 / 21:13