1

I have a test class and a box class, in the test class i have a var called boxHolder, which is an array, i want to override the << method for this array. Inside the singleton how can i access moski_call ?

class Test
  attr_accessor :boxHolder

  def initialize()
   super
   self.boxHolder = Array.new

   class << @boxHolder
     def <<(box)
       box.setPositionWithinColumn(moski_call)
       super(box)
     end
   end
  end   

  def moski_call
    "YAAAAAAAAAAAAAAAAAAAA"
  end
end

class Box
  def initialize
  end

  def setPositionWithinColumn(str)
    puts "got a string #{str}"
  end
end

# test
box = Box.new
test = Test.new
test.boxHolder 
1
  • By convention, rubyists don't use camelCase; it's box_holder, not boxHolder, etc... Commented Jul 22, 2010 at 16:02

3 Answers 3

0

like this:

# need this or else `moski_call` method is looked up in context of @boxholder
moski_call_output = moski_call

class << @boxholder; self; end.send(:define_method, :<<) { |box| 
     box.setPositionWithinColumn(moski_call_output)
     super(box)
}
Sign up to request clarification or add additional context in comments.

4 Comments

i am getting the following error: "<<': undefined local variable or method moski_call' for []:Array (NameError)"
Ah, this works, many thanks ... can you please explain why this works, defining moski_call_output solved the problem, but whats the difference between moski_call and moski_call_output ?
@moski, moski_call is a method and moski_call_output is a local variable. In a define_method block methods are looked up in the object the method is defined on - in this case @boxholder. However @boxholder does not have such a method and so it will error. local variables on the other hand are captured by the define_method block (closure) and will be accessible.
moski_call_output won't get updated if moski_call changes... I posted a solution I prefer.
0

What about:

def self.boxHolder.<< (box)
   box.setPositionWithinColumn(moski_call)
   super(box)
end     

This would declare a method for your instance boxHolder. But boxHolder does not have access to the method moski_call

1 Comment

it seems the syntax is not correct, i am getting "syntax error, unexpected '.', expecting '\n' or ';'"
0

You need to maintain access to the "parent" Test object. This can be done using the fact that blocks are closures:

parent = self # to be accessible in the closure

@boxHolder.define_singleton_method(:<<) do |box|
  box.setPositionWithinColumn(parent.moski_call)
  super(box)
end

Note: define_singleton_method is new in Ruby 1.9, so either upgrade, require 'backports/1.9.1/kernel/define_singleton_method' or do class << @boxHolder; define_method(:<<){ "..." } end if using an older Ruby.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.