20

I'm trying to write a method that acts as a setter and takes some extra arguments besides the assigned value. Silly example:

class WordGenerator
  def []=(letter, position, allowed)
    puts "#{letter}#{allowed ? ' now' : ' no longer'} allowed at #{position}"
  end

  def allow=(letter, position, allowed)
    # ...
  end
end

Writing it as an indexer works and I can call it like this:

gen = WordGenerator.new

gen['a', 1] = true
# or explicitly:
gen.[]=('a', 1, true)

But when I try any of the following, the interpreter complains:

gen.allow('a', 1) = false # syntax error
gen.allow=('a', 1, false) # syntax error

Why won't this work, am I missing the obvious?

Valentin Milea
  • 3,186
  • 3
  • 28
  • 29
  • related / duplicate: http://stackoverflow.com/questions/9280623/setter-method-assignment-with-multiple-arguments – kotique Jun 15 '12 at 13:29

2 Answers2

21

It doesn't work because the parser doesn't allow it. An equals sign is allowed in expressions of the form identifier = expression, expression.identifier = expression (where identifier is \w+), expression[arguments] = expression and expression.[]= arguments and as part of a string or symbol or character literal (?=). That's it.

gen.send(:allow=, 'a', 1, false) would work, but at that point you could as well just give the method a name that doesn't include a =.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
  • Thanks. Funny thing is it allows stuff like 'def seed=(value) end; gen.seed=(1)'. I would have expected 'seed=' to be the identifier, but (if I understood your rules correctly) it goes like: [gen/expr].[seed/identifier]=[(1)/expr]. This would explain why it fails with more than one argument -- (a) is an expression, however (a, b) is not! Assuming this holds, how does 'gen.[]=('a', 1, true)' work? – Valentin Milea Mar 04 '10 at 18:26
  • `.[]=` is another special case which I forgot in my list above (along with `expression[comma_seperated_expressions] = expression`, which of course also works). – sepp2k Mar 04 '10 at 19:53
8

I have come across this and decided to pass my arguments as an array or hash.

E.g.:

def allow=(arguments)
  puts arguments[:letter]
  puts arguments[:position]
  puts arguments[:allowed]
end

object.allow={:letter=>'A',:position=>3,:allowed=>true}
Andro Selva
  • 53,910
  • 52
  • 193
  • 240
Ross F
  • 81
  • 1
  • 1