Dynamic Dispatch Discrepancy


*Update*
By the way I unsuccessfully tried overriding the methods() method and almost went as far as overriding send on my mock wrapping ObjCMock class. My experience in MOP tells me that overriding send is likely rooted in trouble so I decided against it.

Yesterday’s Ruby drama ended with my finding a hack around the dropped parameters. If I was more familiar with Ruby, had more time to kill, or if it were Groovy instead then my solution would be much cleaner.

The problem:
Ruby Mocks under RSpec (have no idea if the problem persists in other Ruby scripting environments) do not receive parameters correctly from native Cocoa objects.

The hack:
Use a home-grown mock to intercept the parameter and pass along to the Ruby mock.

The code: (bowling_controller_spec.rb)

require File.dirname(__FILE__) + ‘/test_helper’

require “BowlingController.bundle”
OSX::ns_import :BowlingController
OSX::ns_import :BowlingProtocol
require ‘delegate’

include OSX

class ObjCMock
attr_accessor :delegate
def roll(num)
@delegate.roll(num)
end

# def method_missing(m, *args)
# puts “Forwarding message”
# @delegate.send(m, args)
# end

def initialize(theMock)
@delegate = theMock
end
end

describe BowlingController do
before(:each) do
@controller = BowlingController.new
@bowling = mock(‘BowlingProtocol’)
@text_field = mock(‘Pins’)
@text_field.stub!(:intValue).and_return(10)
@controller.pins = @text_field
end

it “should roll a ball” do
@controller.roll
end

it “should roll a ball and get the value from the pins outlet” do
@text_field.should_receive(:intValue).and_return(0)
@controller.roll
end

it “should be an OSX::NSObject” do
@controller.is_a?(OSX::NSObject).should == true
end

it “should have an outlet to a bowling object” do
@controller.bowling = @bowling
end

it “should send the pin value to the bowling object” do
@controller.bowling = ObjCMock.new(@bowling)
# @controller.bowling = @bowling
@bowling.should_receive(:roll).with(NSNumber.numberWithInt(10))

@controller.roll
end
end

I left in the commented out method_missing magic that doesn’t work the way I’d expect it. Ideally I’d like to tuck this wrapping mock to the side without needing to define the specific signature I’m mocking. Ideally method_missing would give me the ability to answer any message. Alas, I get “does not reckognize selector” errors from NSProxy when I enable it. I have a feeling that NSProxy probably looks through the defined methods on it’s delegate and throws this error without 1st trying to invoke the method… effectively killing any dynamic magic ability from objects passed into Cocoa land. I also have a feeling that there are a few other holes in the proxy approach with Ruby/Cocoa. If anybody happens to know the details feel free to chime in.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 250 other followers

%d bloggers like this: