Home > Back-end >  How do I define a class that passes method calls through a different class's methods?
How do I define a class that passes method calls through a different class's methods?

Time:08-31

ie

class B
  def method_1
  end
  def method_2
  end
  #Additional methods
end

class A
  def initialize instance_of_b
    @b = instance_of_b
  end
  def method_1
    #custom behavior
  end
  #For all other methods, call b.method
end

I know you can accomplish this by having B be a parent of A, but in my particular case that wouldn't make sense; is there a way to do this without using inheritance?

CodePudding user response:

This is what SimpleDelegator is for:

class B
  def method_1
    'foo'
  end
  def method_2
    'bar'
  end
end

require 'delegate'

class A < SimpleDelegator
  def method_1
    super.upcase
  end
end

It automatically creates a constructor that takes the object you want to delegate to:

b = B.new
a = A.new(b)

a.method_1 #=> "FOO"
a.method_2 #=> "bar"

CodePudding user response:

You tagged question with Rails, ActiveSupport has Module#delegate_missing_to method

class B
  def method1
    'foo'
  end

  def method2
    'bar'
  end
end

class A
  delegate_missing_to :@b

  def initialize(b)
    @b = b
  end

  # custom behavior
  def method1
    super.upcase
  end
end
b = B.new
a = A.new(b)

a.method1 #=> "FOO"
a.method2 #=> "bar

CodePudding user response:

You could define Object#method_missing on A:

class B
  def method_1
    :B_method_1
  end

  def method_2
    :B_method_2
  end
end

class A
  def initialize instance_of_b
    @b = instance_of_b
  end

  def method_1
    :A_method_1
  end

  private

  attr_reader :b

  def method_missing(method_name, *args)
    b.send(method_name, *args)
  end
end

b = B.new
a = A.new(b)

p b.method_1 # :B_method_1
p b.method_2 # :B_method_2

p a.method_1 # :A_method_1
p a.method_2 # :B_method_2
p a.method_3 # file.rb:27:in `method_missing': undefined method `method_3' for #<B:0x00007fc2f43b9ae8> (NoMethodError)

CodePudding user response:

One alternative perhaps worth mentioning:

require 'forwardable'

class A

  extend Forwardable

  def_instance_delegators :@b, :method1, :method2, :method3

end

With this, a a = A.new; a.method2 would aktually do a @b.method2 in the A-instance a.

While this requires you to type the list of the methods you want to forward, this has the advantage that A really gets new methods of this name, which of course does not happen with an automatism based on, say, method_missing.

  • Related