I understand how to implement a (validating) setter (def item=
), but how do I intercept the <<
operation on a field?
class Bla
attr_reader :item
def initialize
@item = []
end
# only called for =, +=, -= operations (not <<)
def item=(value)
puts "Changing value to #{value}"
# pretend that there is a conditional here
@item = value
end
# This is wrong:
#def item<<(value)
# puts "adding value #{value}"
# @item << value
#end
end
b = Bla.new
b.item = ['one'] # works
b.item += ['one'] # works
b.item << 'two' # bypasses my setter
I've tried def item<<(value)
, that doesn't seem to work.
When you call b.item << 'two'
, you are calling the <<
method on item
directly. So you have a few options here:
Implement <<
directly on your Bla
class, then use b << 'two'
:
# in class Bla
def <<(value)
# do validation here
@item << value
end
Use some other, nicer-named wrapper method name like add_item
:
# in class Bla
def add_item(value)
# do validation here
@item << value
end
Use a special array class for @item
which has a custom definition for <<
:
class MyArray < Array
def <<(item)
# run validation here
super
end
end
# in Bla class
def initialize
@item = MyArray.new
end
I would probably go with option 2, it's the most simple and readable.