Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mocha is incompatible with SimpleDelegator #30

Closed
jamesarosen opened this issue Jul 25, 2011 · 15 comments
Closed

mocha is incompatible with SimpleDelegator #30

jamesarosen opened this issue Jul 25, 2011 · 15 comments

Comments

@jamesarosen
Copy link

I can't call stubs or expects on an instance of SimpleDelegator because that object will just pass the stubs or expects call on to the delegated object (confusingly called a "stub"). For example:

require 'mocha'
require 'delegate'

class Foo
  def foo; 'foo'; end
end

class Bar < SimpleDelegator
  def bar; 'bar'; end
  def foobar; foo + bar; end
end

foo = Foo.new
bar = Bar.new(foo)

# this actually ends up as "foo.stubs(:bar).returns('baz')"
bar.stubs(:bar).returns('baz')

# since foo.bar is never called, the stub is meaningless:
bar.foobar # => 'foobar'
@floehopper
Copy link
Member

Hi James,

I've had a look into this and I can't see a simple/elegant solution. The Delegator (and hence SimpleDelegator) don't seem to have any flexibility built into them e.g. you can't tell them not to delegate particular methods. I think what I'd do in this case is to use Forwardable instead along the following lines :-

require 'mocha'
require 'forwardable'

class Foo
  def foo; 'foo'; end
end

class Bar
  extend Forwardable
  def initialize(delegate)
    @delegate = delegate
  end
  def_delegators :@delegate, :foo
  def bar; 'bar'; end
  def foobar; foo + bar; end
end

foo = Foo.new
bar = Bar.new(foo)

bar.stubs(:bar).returns('baz')
bar.foobar # => 'foobaz'

I hope that helps.

Regards, James.

@jamesarosen
Copy link
Author

One idea I had, but didn't dig into: if there were a single module that I mixed in for :stubs and :expects, then I could mix that directly into Bar in BarTest. That doesn't seem like too burdensome a thing to do since I know that Bar < SimpleDelegate.

@floehopper
Copy link
Member

Yeah. I explored that a bit. There is a module (Mocha::ObjectMethods), but including that doesn't work. I think the reason it doesn't work is that Delegate only preserves methods defined in the derived class itself, and not those defined in included modules. It also seems to preserve most methods defined in (but not included into the Kernel module). However, Mocha keeps all its methods in its own modules in order not to unnecessarily pollute other classes/modules and that is something I'd want to continue. That's why I said I couldn't see a simple/elegant solution.

@floehopper
Copy link
Member

Hi James. I can't see a good way forward on this and I'm happy that my suggested work-around is a good enough solution for now. So unless you can suggest a better approach, I don't think I'm going to make any changes to Mocha to address this issue. Are you happy to close the issue?

@floehopper floehopper reopened this Aug 2, 2011
@floehopper
Copy link
Member

Sorry - I didn't mean to close the issue - clicked the wrong button.

@jamesarosen
Copy link
Author

My use case relies on forwarding unexpected method calls, so Forwardable won't work :(

I'll just have to use def @bar.bar; return 'baz'; end;

@floehopper
Copy link
Member

I take your point. I thought I'd mentioned this already, but it would appear not - an alternative would be to implement your own delegator. I've written a very naive one here which I think solves your problem. In this case, since BetterDelegator inherits (implicityly) from Object, Mocha::ObjectMethods are automatically included and it does what I think you want it to.

@floehopper
Copy link
Member

Did my last comment help at all?

@jamesarosen
Copy link
Author

I haven't given it a shot, but it looks quite promising. Thanks!

@dnesteryuk
Copy link

I have the same issue with Mocha :(

@floehopper
Copy link
Member

Have you tried the idea I suggested here i.e. in this Gist?

@dnesteryuk
Copy link

Sorry, at first I was thinking about your approach with Forwardable, another one with BetterDelegator works, thank you!!

@floehopper
Copy link
Member

Cool. Maybe I should release it as a gem ;-)

@jamesarosen
Copy link
Author

I'd love to see the bike-shedding on that gem :)

@floehopper
Copy link
Member

See also #622.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants