views:

50

answers:

2

How do I implement the '<<' to have the same behavior when used as a chainable method?

class Test
  attr_accessor :internal_array

  def initialize
    @internal_array = []
  end

  def <<(item)
    @internal_array << :a
    @internal_array << item
  end
end

t = Test.new
t << 1
t << 2
t << 3
#t.internal_array => [:a, 1, :a, 2, :a, 3]
puts "#{t.internal_array}" # => a1a2a3

t = Test.new
t << 1 << 2 << 3
#t.internal_array => [:a, 1, 2, 3]
puts "#{t.internal_array}" # => a123 , Why not a1a2a3?

I want both cases giving the same result.

+4  A: 

Add self as the last line in the << method to return it. As is, you're implicitly returning the array, not the instance.

Matthew Flaschen
A: 

Explanation of the answer above:

When a method is chained, the next method is applied to the result of the first method.

For exemplo:

class A
  def method1
    B.new
  end
end

class B
  def method2
    C.new
  end
end

class C
  def method3
    puts "It is working!!!"
  end
end

The code below will work

A.new.method1.method2.method3

but the this will not

A.new.method1.method3.method2

because an instance of class B, which is the result of A.new.method1 doesn't implement method3. This is the same of:

(((A.new).method1).method3).method2

The code used in the question above, was a little bit more trick, because both, Test and Array had the method <<. But I want Test#<< to return self, and not the @internal_array that was being returned.

Portela
Is this supposed to be an answer to your question? I'm confused.
Chuck
It is the explanation of the answer above. The short answer was given by Matthew: add self at the...
Portela