Upgraded Rails and RSpec
[monkeycharger.git] / vendor / plugins / rspec / lib / spec / matchers / have.rb
blob8a7adf4c6e23f175be5589b4b4ddb249d68b64c3
1 module Spec
2   module Matchers
3     
4     class Have #:nodoc:
5       def initialize(expected, relativity=:exactly)
6         @expected = (expected == :no ? 0 : expected)
7         @relativity = relativity
8       end
9     
10       def relativities
11         @relativities ||= {
12           :exactly => "",
13           :at_least => "at least ",
14           :at_most => "at most "
15         }
16       end
17     
18       def method_missing(sym, *args, &block)
19         @collection_name = sym
20         @args = args
21         @block = block
22         self
23       end
24     
25       def matches?(collection_owner)
26         if collection_owner.respond_to?(collection_name)
27           collection = collection_owner.send(collection_name, *@args, &@block)
28         elsif (collection_owner.respond_to?(:length) || collection_owner.respond_to?(:size))
29           collection = collection_owner
30         else
31           collection_owner.send(collection_name, *@args, &@block)
32         end
33         @actual = collection.size if collection.respond_to?(:size)
34         @actual = collection.length if collection.respond_to?(:length)
35         raise not_a_collection if @actual.nil?
36         return @actual >= @expected if @relativity == :at_least
37         return @actual <= @expected if @relativity == :at_most
38         return @actual == @expected
39       end
40       
41       def not_a_collection
42         "expected #{@collection_name} to be a collection but it does not respond to #length or #size"
43       end
44     
45       def failure_message
46         "expected #{relative_expectation} #{collection_name}, got #{@actual}"
47       end
49       def negative_failure_message
50         if @relativity == :exactly
51           return "expected target not to have #{@expected} #{collection_name}, got #{@actual}"
52         elsif @relativity == :at_most
53           return <<-EOF
54 Isn't life confusing enough?
55 Instead of having to figure out the meaning of this:
56   should_not have_at_most(#{@expected}).#{collection_name}
57 We recommend that you use this instead:
58   should have_at_least(#{@expected + 1}).#{collection_name}
59 EOF
60         elsif @relativity == :at_least
61           return <<-EOF
62 Isn't life confusing enough?
63 Instead of having to figure out the meaning of this:
64   should_not have_at_least(#{@expected}).#{collection_name}
65 We recommend that you use this instead:
66   should have_at_most(#{@expected - 1}).#{collection_name}
67 EOF
68         end
69       end
70       
71       def description
72         "have #{relative_expectation} #{collection_name}"
73       end
74       
75       private
76       def collection_name
77         @collection_name
78       end
79       
80       def relative_expectation
81         "#{relativities[@relativity]}#{@expected}"
82       end
83     end
85     # :call-seq:
86     #   should have(number).named_collection__or__sugar
87     #   should_not have(number).named_collection__or__sugar
88     #
89     # Passes if receiver is a collection with the submitted
90     # number of items OR if the receiver OWNS a collection
91     # with the submitted number of items.
92     #
93     # If the receiver OWNS the collection, you must use the name
94     # of the collection. So if a <tt>Team</tt> instance has a
95     # collection named <tt>#players</tt>, you must use that name
96     # to set the expectation.
97     #
98     # If the receiver IS the collection, you can use any name
99     # you like for <tt>named_collection</tt>. We'd recommend using
100     # either "elements", "members", or "items" as these are all
101     # standard ways of describing the things IN a collection.
102     #
103     # This also works for Strings, letting you set an expectation
104     # about its length
105     #
106     # == Examples
107     #
108     #   # Passes if team.players.size == 11
109     #   team.should have(11).players
110     #
111     #   # Passes if [1,2,3].length == 3
112     #   [1,2,3].should have(3).items #"items" is pure sugar
113     #
114     #   # Passes if "this string".length == 11
115     #   "this string".should have(11).characters #"characters" is pure sugar
116     def have(n)
117       Matchers::Have.new(n)
118     end
119     alias :have_exactly :have
121     # :call-seq:
122     #   should have_at_least(number).items
123     #
124     # Exactly like have() with >=.
125     #
126     # == Warning
127     #
128     # +should_not+ +have_at_least+ is not supported
129     def have_at_least(n)
130       Matchers::Have.new(n, :at_least)
131     end
133     # :call-seq:
134     #   should have_at_most(number).items
135     #
136     # Exactly like have() with <=.
137     #
138     # == Warning
139     #
140     # +should_not+ +have_at_most+ is not supported
141     def have_at_most(n)
142       Matchers::Have.new(n, :at_most)
143     end
144   end