]> git.openstreetmap.org Git - rails.git/blob - vendor/gems/rspec-1.1.2/lib/spec/matchers/have.rb
added RSpec and RSpec on Rails
[rails.git] / vendor / gems / rspec-1.1.2 / lib / spec / matchers / have.rb
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         @plural_collection_name = Inflector.pluralize(sym.to_s) if Object.const_defined?(:Inflector)
21         @args = args
22         @block = block
23         self
24       end
25     
26       def matches?(collection_owner)
27         if collection_owner.respond_to?(@collection_name)
28           collection = collection_owner.send(@collection_name, *@args, &@block)
29         elsif (@plural_collection_name && collection_owner.respond_to?(@plural_collection_name))
30           collection = collection_owner.send(@plural_collection_name, *@args, &@block)
31         elsif (collection_owner.respond_to?(:length) || collection_owner.respond_to?(:size))
32           collection = collection_owner
33         else
34           collection_owner.send(@collection_name, *@args, &@block)
35         end
36         @actual = collection.size if collection.respond_to?(:size)
37         @actual = collection.length if collection.respond_to?(:length)
38         raise not_a_collection if @actual.nil?
39         return @actual >= @expected if @relativity == :at_least
40         return @actual <= @expected if @relativity == :at_most
41         return @actual == @expected
42       end
43       
44       def not_a_collection
45         "expected #{@collection_name} to be a collection but it does not respond to #length or #size"
46       end
47     
48       def failure_message
49         "expected #{relative_expectation} #{@collection_name}, got #{@actual}"
50       end
51
52       def negative_failure_message
53         if @relativity == :exactly
54           return "expected target not to have #{@expected} #{@collection_name}, got #{@actual}"
55         elsif @relativity == :at_most
56           return <<-EOF
57 Isn't life confusing enough?
58 Instead of having to figure out the meaning of this:
59   should_not have_at_most(#{@expected}).#{@collection_name}
60 We recommend that you use this instead:
61   should have_at_least(#{@expected + 1}).#{@collection_name}
62 EOF
63         elsif @relativity == :at_least
64           return <<-EOF
65 Isn't life confusing enough?
66 Instead of having to figure out the meaning of this:
67   should_not have_at_least(#{@expected}).#{@collection_name}
68 We recommend that you use this instead:
69   should have_at_most(#{@expected - 1}).#{@collection_name}
70 EOF
71         end
72       end
73       
74       def description
75         "have #{relative_expectation} #{@collection_name}"
76       end
77       
78       private
79       
80       def relative_expectation
81         "#{relativities[@relativity]}#{@expected}"
82       end
83     end
84
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
120
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
132
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
145 end