 window.Spec ||= {}
 
+# Replaces a method on an object with a stub method, a fake method which can
+# be configured to return predetermined responses, as well as set
+# expectations on how it is called.
+#
+# These are created using window#stub, window#shouldReceive and
+# window#shouldNotReceive. You shouldn't need to create one manually.
 class window.Spec.MethodStub
   constructor: (@test, @object, @method) ->
     @possibleCalls = []
     @_replaceMethodOnObject()
 
+  # Makes a new PossibleCall and adds it to the list
   possibleCall: ->
     call = new Spec.MethodStub.PossibleCall(@test, @original)
     @possibleCalls.unshift call
     call
 
+  # Generates a new stub method to inject into the object, and sets the
+  # _stub property on it to point back to this MethodStub.
+  #
+  # _stub is used by window#stub to find an existing MethodStub for a method
+  # and add more possible calls to it, instead of writing over it with
+  # a new MethodStub.
+  #
+  # The code inside the stub method is the same for each MethodStub, but
+  # we create a fresh copy of it so we can assign a unique _stub property.
   _stubMethod: ->
     method = @method
     stubMethod = (args...) ->

    @original = @object[@method]
    @object[@method] = @_stubMethod()

class window.Spec.MethodStub.PossibleCall
  constructor: (@test, @original) ->

  with: (args...) ->
    @arguments = args
    this

  andReturn: (returnValue) ->
    @return = -> returnValue
    this

  andPassthrough: ->
    @return = @original

  expect: ->
    # TODO: Make this description better, possibly with name of
    # the method that should have been called
    @expectation ||= expectation 'get called'
    this

  twice: ->
    @expectation.twice()
    this

  exactly: (times) ->
    @expectation.exactly times
    {times: this}

  matchesArguments: (args) ->
    if !@arguments
      true

    else
      @_arraysMatch @arguments, args

  # Causes this PossibleCall to fulfil a call on the stubbed method. Fails
  # the test if the called arguments don't match expected arguments.
  call: (object, method, args) ->
    if @matchesArguments(args)
      @expectation.meet() if @expectation
