Search code examples
rubyoperator-overloadingmetaprogrammingattr-accessor

Override << for an array instance variable in class


I need to override the operator << for one single attribute in my class.

Basically, what I want is allow to push only unique integers to my array attribute.

Here's what I have:

class Player
  attr_accessor :moves

  def initialize
    @moves = []
  end

  def moves<<(value)
    raise Exception if @moves.include?(value)
    @moves.push(value)
  end
end

Unfortunately, this code doesn't work.

How can I improve that or maybe there are better ways to implement such functionality?


Solution

  • class Player
      attr_accessor :moves
    
      def initialize
        @moves = []
        @moves.define_singleton_method(:<<) do |value|
          raise Exception if include?(value)
          push(value)
        end
      end
    end
    

    You can add methods only specific to a given object using the Object#define_singleton_method. Ruby is really flexible when it comes to meta programming.

    However such tools should be used sparingly. I don't know your specific situation, but you are probably better off not giving direct access to @moves. The best approach might be to define methods in Player that create an indirect and more restrictive interface to the internal representation and give you more control.