Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setter method (assignment) with multiple arguments

Tags:

ruby

I have a custom class and want to be able to override the assignment operator. Here is an example:

class MyArray < Array
  attr_accessor :direction
  def initialize
    @direction = :forward
  end
end
class History
  def initialize
    @strategy = MyArray.new
  end
  def strategy=(strategy, direction = :forward)
    @strategy << strategy
    @strategy.direction = direction
  end
end

This currently doesn't work as intended. upon using

h = History.new
h.strategy = :mystrategy, :backward

[:mystrategy, :backward] gets assigned to the strategy variable and the direction variable remains :forward.
The important part is that I want to be able to assign a standard value to the direction parameter.

Any clues to make this work are highly appreciated.

like image 823
FlyingFoX Avatar asked Feb 14 '12 16:02

FlyingFoX


2 Answers

Due to the syntax sugar of methods whose names end in=, the only way that you can actually pass multiple parameters to the method is to bypass the syntax sugar and use send

h.send(:strategy=, :mystrategy, :backward )

…in which case you might as well just use a normal method with better names:

h.set_strategy :mystrategy, :backward

However, you could rewrite your method to automatically un-array the values if you knew that an array is never legal for the parameter:

def strategy=( value )
  if value.is_a?( Array )
    @strategy << value.first
    @strategy.direction = value.last
  else
    @strategy = value
  end
end

This seems like a gross hack to me, however. I would use a non-assigment method name with multiple arguments if you need them.


An alternative suggestion: if the only directions are :forward and :backward what about:

def forward_strategy=( name )
  @strategy << name
  @strategy.direction = :forward
end

def reverse_strategy=( name )
  @strategy << name
  @strategy.direction = :backward
end
like image 62
Phrogz Avatar answered Oct 12 '22 02:10

Phrogz


The problem is

def strategy=(strategy, direction = :forward)
  @strategy = strategy
  @strategy.direction = direction
end

When you set

h.strategy = :mystrategy, :backward

you are actually overriding the original @strategy instance. After that call, @strategy is an instance of Symbol, not MyArray.

What do you want to do? Replace the object or update it?

like image 24
Simone Carletti Avatar answered Oct 12 '22 01:10

Simone Carletti