require 'rubygems'
require 'spec'

module SpyMatchers
class MethodRecorder
def method_missing(sym, *args)
MethodVerifier.new({sym => args})
end
end

def have_received
MethodRecorder.new
end

class MethodVerifier
def initialize(expected)
@expected = expected
end

def matches?(target)
@target = target
@target.was_method_called?(@expected)
end

def failure_message
"expected #{@target.__subject__.inspect} to have received #{@expected.keys[0]}(#{@expected.values[0]})"
end

def negative_failure_message
"expected #{@target.__subject__.inspect} not to have received #{@expected.keys[0]}(#{@expected.values[0]})"
end
end
end

class Spy
def self.on(subject)
Spy.new(subject)
end

def initialize(subject)
@subject = subject
@method_calls = []
end

def was_method_called?(method_with_args)
return @method_calls.include?(method_with_args)
end

def __subject__
@subject
end

def method_missing(sym, *args)
@method_calls << {sym => args}
@subject.send(sym, *args)
end
end

describe "ubiquitous assertion syntax" do
include SpyMatchers

it "should test state" do
2.should == 1+1
end

it "should test an error" do
lambda { [].not_a_method }.should raise_error(NoMethodError)
end

it "should test behavior" do
array = Spy.on []
[1, 2].each do |number|
array << number
end
array.should have_received << 1
array.should have_received << 2
end
end