4 class MatcherConstraint
5 def initialize(matcher)
10 @matcher.matches?(value)
14 class LiteralArgConstraint
15 def initialize(literal)
16 @literal_value = literal
20 @literal_value == value
24 class RegexpArgConstraint
25 def initialize(regexp)
30 return value =~ @regexp unless value.is_a?(Regexp)
35 class AnyArgConstraint
36 def initialize(ignore)
49 class AnyArgsConstraint
55 class NoArgsConstraint
65 class NumericArgConstraint
66 def initialize(ignore)
74 class BooleanArgConstraint
75 def initialize(ignore)
83 return true if value.is_a?(TrueClass)
84 return true if value.is_a?(FalseClass)
89 class StringArgConstraint
90 def initialize(ignore)
98 class DuckTypeArgConstraint
99 def initialize(*methods_to_respond_to)
100 @methods_to_respond_to = methods_to_respond_to
104 @methods_to_respond_to.all? { |sym| value.respond_to?(sym) }
112 class ArgumentExpectation
114 @@constraint_classes = Hash.new { |hash, key| LiteralArgConstraint}
115 @@constraint_classes[:anything] = AnyArgConstraint
116 @@constraint_classes[:numeric] = NumericArgConstraint
117 @@constraint_classes[:boolean] = BooleanArgConstraint
118 @@constraint_classes[:string] = StringArgConstraint
122 if [:any_args] == args
123 @expected_params = nil
124 warn_deprecated(:any_args.inspect, "any_args()")
125 elsif args.length == 1 && args[0].is_a?(AnyArgsConstraint) then @expected_params = nil
126 elsif [:no_args] == args
127 @expected_params = []
128 warn_deprecated(:no_args.inspect, "no_args()")
129 elsif args.length == 1 && args[0].is_a?(NoArgsConstraint) then @expected_params = []
130 else @expected_params = process_arg_constraints(args)
134 def process_arg_constraints(constraints)
135 constraints.collect do |constraint|
136 convert_constraint(constraint)
140 def warn_deprecated(deprecated_method, instead)
141 Kernel.warn "The #{deprecated_method} constraint is deprecated. Use #{instead} instead."
144 def convert_constraint(constraint)
145 if [:anything, :numeric, :boolean, :string].include?(constraint)
148 instead = "anything()"
150 instead = "boolean()"
152 instead = "an_instance_of(Numeric)"
154 instead = "an_instance_of(String)"
156 warn_deprecated(constraint.inspect, instead)
157 return @@constraint_classes[constraint].new(constraint)
159 return MatcherConstraint.new(constraint) if is_matcher?(constraint)
160 return RegexpArgConstraint.new(constraint) if constraint.is_a?(Regexp)
161 return LiteralArgConstraint.new(constraint)
165 return obj.respond_to?(:matches?) && obj.respond_to?(:description)
169 return true if @expected_params.nil?
170 return true if @expected_params == args
171 return constraints_match?(args)
174 def constraints_match?(args)
175 return false if args.length != @expected_params.length
176 @expected_params.each_index { |i| return false unless @expected_params[i].matches?(args[i]) }