diff options
author | Francis Irving <francis@mysociety.org> | 2009-12-02 17:51:30 +0000 |
---|---|---|
committer | Francis Irving <francis@mysociety.org> | 2009-12-02 17:51:30 +0000 |
commit | 5f3139b538d1ff58b719a72d7c7cf05a5b6136b5 (patch) | |
tree | 13597cf6751df3122bfb1f1e5b1699e5c7ec5f93 /vendor/plugins/rspec/lib/spec/matchers | |
parent | dcf788cab6268a5c9830178d1bdff606f84132ce (diff) |
Part of upgrade to rails 2.3.2
Diffstat (limited to 'vendor/plugins/rspec/lib/spec/matchers')
12 files changed, 417 insertions, 0 deletions
diff --git a/vendor/plugins/rspec/lib/spec/matchers/be_instance_of.rb b/vendor/plugins/rspec/lib/spec/matchers/be_instance_of.rb new file mode 100644 index 000000000..ffc238405 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/be_instance_of.rb @@ -0,0 +1,26 @@ +module Spec + module Matchers + # :call-seq: + # should be_instance_of(expected) + # should be_an_instance_of(expected) + # should_not be_instance_of(expected) + # should_not be_an_instance_of(expected) + # + # Passes if actual.instance_of?(expected) + # + # == Examples + # + # 5.should be_instance_of(Fixnum) + # 5.should_not be_instance_of(Numeric) + # 5.should_not be_instance_of(Float) + def be_an_instance_of(expected) + Matcher.new :be_an_instance_of, expected do |_expected_| + match do |actual| + actual.instance_of?(_expected_) + end + end + end + + alias_method :be_instance_of, :be_an_instance_of + end +end diff --git a/vendor/plugins/rspec/lib/spec/matchers/be_kind_of.rb b/vendor/plugins/rspec/lib/spec/matchers/be_kind_of.rb new file mode 100644 index 000000000..6a1fddc13 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/be_kind_of.rb @@ -0,0 +1,26 @@ +module Spec + module Matchers + # :call-seq: + # should be_kind_of(expected) + # should be_a_kind_of(expected) + # should_not be_kind_of(expected) + # should_not be_a_kind_of(expected) + # + # Passes if actual.kind_of?(expected) + # + # == Examples + # + # 5.should be_kind_of(Fixnum) + # 5.should be_kind_of(Numeric) + # 5.should_not be_kind_of(Float) + def be_a_kind_of(expected) + Matcher.new :be_a_kind_of, expected do |_expected_| + match do |actual| + actual.kind_of?(_expected_) + end + end + end + + alias_method :be_kind_of, :be_a_kind_of + end +end diff --git a/vendor/plugins/rspec/lib/spec/matchers/compatibility.rb b/vendor/plugins/rspec/lib/spec/matchers/compatibility.rb new file mode 100644 index 000000000..3b3ddb9b6 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/compatibility.rb @@ -0,0 +1,14 @@ +Spec::Matchers.constants.each do |c| + if Class === (klass = Spec::Matchers.const_get(c)) + if klass.public_instance_methods.any? {|m| ['failure_message_for_should',:failure_message_for_should].include?(m)} + klass.class_eval do + alias_method :failure_message, :failure_message_for_should + end + end + if klass.public_instance_methods.any? {|m| ['failure_message_for_should_not',:failure_message_for_should_not].include?(m)} + klass.class_eval do + alias_method :negative_failure_message, :failure_message_for_should_not + end + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/matchers/dsl.rb b/vendor/plugins/rspec/lib/spec/matchers/dsl.rb new file mode 100644 index 000000000..73f363457 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/dsl.rb @@ -0,0 +1,20 @@ +module Spec + module Matchers + module DSL + # See Spec::Matchers + def define(name, &declarations) + define_method name do |*expected| + Spec::Matchers::Matcher.new name, *expected, &declarations + end + end + + # Deprecated - use define + def create(name, &declarations) + Spec.deprecate("Spec::Matchers.create","Spec::Matchers.define") + define(name, &declarations) + end + end + end +end + +Spec::Matchers.extend Spec::Matchers::DSL diff --git a/vendor/plugins/rspec/lib/spec/matchers/errors.rb b/vendor/plugins/rspec/lib/spec/matchers/errors.rb new file mode 100644 index 000000000..49c267797 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/errors.rb @@ -0,0 +1,5 @@ +module Spec + module Matchers + class MatcherError < StandardError; end + end +end
\ No newline at end of file diff --git a/vendor/plugins/rspec/lib/spec/matchers/extensions/instance_exec.rb b/vendor/plugins/rspec/lib/spec/matchers/extensions/instance_exec.rb new file mode 100644 index 000000000..ca7e14ead --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/extensions/instance_exec.rb @@ -0,0 +1,31 @@ +module Spec + module Matchers + module InstanceExec + unless respond_to?(:instance_exec) + # based on Bounded Spec InstanceExec (Mauricio Fernandez) + # http://eigenclass.org/hiki/bounded+space+instance_exec + # - uses singleton_class of matcher instead of global + # InstanceExecHelper module + # - this keeps it scoped to this class only, which is the + # only place we need it + # - only necessary for ruby 1.8.6 + def instance_exec(*args, &block) + singleton_class = (class << self; self; end) + begin + orig_critical, Thread.critical = Thread.critical, true + n = 0 + n += 1 while respond_to?(method_name="__instance_exec#{n}") + singleton_class.module_eval{ define_method(:__instance_exec, &block) } + ensure + Thread.critical = orig_critical + end + begin + return send(:__instance_exec, *args) + ensure + singleton_class.module_eval{ remove_method(:__instance_exec) } rescue nil + end + end + end + end + end +end
\ No newline at end of file diff --git a/vendor/plugins/rspec/lib/spec/matchers/generated_descriptions.rb b/vendor/plugins/rspec/lib/spec/matchers/generated_descriptions.rb new file mode 100644 index 000000000..2340f57d8 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/generated_descriptions.rb @@ -0,0 +1,36 @@ +module Spec + module Matchers + class << self + attr_accessor :last_matcher, :last_should # :nodoc: + end + + def self.clear_generated_description + self.last_matcher = nil + self.last_should = nil + end + + def self.generated_description + return nil if last_should.nil? + "#{last_should.to_s.gsub('_',' ')} #{last_description}" + end + + private + + def self.last_description + last_matcher.respond_to?(:description) ? last_matcher.description : <<-MESSAGE +When you call a matcher in an example without a String, like this: + +specify { object.should matcher } + +or this: + +it { should matcher } + +RSpec expects the matcher to have a #description method. You should either +add a String to the example this matcher is being used in, or give it a +description method. Then you won't have to suffer this lengthy warning again. +MESSAGE + end + end +end + diff --git a/vendor/plugins/rspec/lib/spec/matchers/match_array.rb b/vendor/plugins/rspec/lib/spec/matchers/match_array.rb new file mode 100644 index 000000000..51b4f3929 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/match_array.rb @@ -0,0 +1,71 @@ +module Spec + module Matchers + + class MatchArray #:nodoc: + include Spec::Matchers::Pretty + + def initialize(expected) + @expected = expected + end + + def matches?(actual) + @actual = actual + @extra_items = difference_between_arrays(@actual, @expected) + @missing_items = difference_between_arrays(@expected, @actual) + @extra_items.empty? & @missing_items.empty? + end + + def failure_message_for_should + message = "expected collection contained: #{safe_sort(@expected).inspect}\n" + message += "actual collection contained: #{safe_sort(@actual).inspect}\n" + message += "the missing elements were: #{safe_sort(@missing_items).inspect}\n" unless @missing_items.empty? + message += "the extra elements were: #{safe_sort(@extra_items).inspect}\n" unless @extra_items.empty? + message + end + + def failure_message_for_should_not + "Matcher does not support should_not" + end + + def description + "contain exactly #{_pretty_print(@expected)}" + end + + private + + def safe_sort(array) + array.all?{|item| item.respond_to?(:<=>)} ? array.sort : array + end + + def difference_between_arrays(array_1, array_2) + difference = array_1.dup + array_2.each do |element| + if index = difference.index(element) + difference.delete_at(index) + end + end + difference + end + + + end + + # :call-seq: + # should =~ expected + # + # Passes if actual contains all of the expected regardless of order. + # This works for collections. Pass in multiple args and it will only + # pass if all args are found in collection. + # + # NOTE: there is no should_not version of array.should =~ other_array + # + # == Examples + # + # [1,2,3].should =~ [1,2,3] # => would pass + # [1,2,3].should =~ [2,3,1] # => would pass + # [1,2,3,4].should =~ [1,2,3] # => would fail + # [1,2,2,3].should =~ [1,2,3] # => would fail + # [1,2,3].should =~ [1,2,3,4] # => would fail + OperatorMatcher.register(Array, '=~', Spec::Matchers::MatchArray) + end +end diff --git a/vendor/plugins/rspec/lib/spec/matchers/matcher.rb b/vendor/plugins/rspec/lib/spec/matchers/matcher.rb new file mode 100644 index 000000000..165ddffb5 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/matcher.rb @@ -0,0 +1,87 @@ +module Spec + module Matchers + class Matcher + include Spec::Matchers::InstanceExec + include Spec::Matchers::Pretty + include Spec::Matchers + + attr_reader :expected, :actual + + def initialize(name, *expected, &declarations) + @name = name + @expected = expected + @actual = nil + @diffable = false + @messages = { + :description => lambda {"#{name_to_sentence}#{expected_to_sentence}"}, + :failure_message_for_should => lambda {|actual| "expected #{actual.inspect} to #{name_to_sentence}#{expected_to_sentence}"}, + :failure_message_for_should_not => lambda {|actual| "expected #{actual.inspect} not to #{name_to_sentence}#{expected_to_sentence}"} + } + making_declared_methods_public do + instance_exec(*@expected, &declarations) + end + end + + def matches?(actual) + instance_exec(@actual = actual, &@match_block) + end + + def description(&block) + cache_or_call_cached(:description, &block) + end + + def failure_message_for_should(&block) + cache_or_call_cached(:failure_message_for_should, actual, &block) + end + + def failure_message_for_should_not(&block) + cache_or_call_cached(:failure_message_for_should_not, actual, &block) + end + + def match(&block) + @match_block = block + end + + def diffable? + @diffable + end + + def diffable + @diffable = true + end + + private + + def making_declared_methods_public # :nodoc: + # Our home-grown instance_exec in ruby 1.8.6 results in any methods + # declared in the block eval'd by instance_exec in the block to which we + # are yielding here are scoped private. This is NOT the case for Ruby + # 1.8.7 or 1.9. + # + # Also, due some crazy scoping that I don't understand, these methods + # are actually available in the specs (something about the matcher being + # defined in the scope of Spec::Matchers or within an example), so not + # doing the following will not cause specs to fail, but they *will* + # cause features to fail and that will make users unhappy. So don't. + orig_private_methods = private_methods + yield + st = (class << self; self; end) + (private_methods - orig_private_methods).each {|m| st.__send__ :public, m} + end + + def cache_or_call_cached(key, actual=nil, &block) + block ? @messages[key] = block : + actual.nil? ? @messages[key].call : @messages[key].call(actual) + end + + def name_to_sentence + split_words(@name) + end + + def expected_to_sentence + to_sentence(@expected) + end + + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/matchers/method_missing.rb b/vendor/plugins/rspec/lib/spec/matchers/method_missing.rb new file mode 100644 index 000000000..ae7f39795 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/method_missing.rb @@ -0,0 +1,9 @@ +module Spec + module Matchers + def method_missing(sym, *args, &block) # :nodoc: + return Matchers::Be.new(sym, *args) if sym.to_s =~ /^be_/ + return Matchers::Has.new(sym, *args) if sym.to_s =~ /^have_/ + super + end + end +end diff --git a/vendor/plugins/rspec/lib/spec/matchers/pretty.rb b/vendor/plugins/rspec/lib/spec/matchers/pretty.rb new file mode 100644 index 000000000..152058373 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/pretty.rb @@ -0,0 +1,37 @@ +module Spec + module Matchers + module Pretty + def split_words(sym) + sym.to_s.gsub(/_/,' ') + end + + def to_sentence(words) + words = words.map{|w| w.inspect} + case words.length + when 0 + "" + when 1 + " #{words[0]}" + when 2 + " #{words[0]} and #{words[1]}" + else + " #{words[0...-1].join(', ')}, and #{words[-1]}" + end + end + + def _pretty_print(array) + result = "" + array.each_with_index do |item, index| + if index < (array.length - 2) + result << "#{item.inspect}, " + elsif index < (array.length - 1) + result << "#{item.inspect} and " + else + result << "#{item.inspect}" + end + end + result + end + end + end +end
\ No newline at end of file diff --git a/vendor/plugins/rspec/lib/spec/matchers/wrap_expectation.rb b/vendor/plugins/rspec/lib/spec/matchers/wrap_expectation.rb new file mode 100644 index 000000000..95162cae1 --- /dev/null +++ b/vendor/plugins/rspec/lib/spec/matchers/wrap_expectation.rb @@ -0,0 +1,55 @@ +module Spec + module Matchers + # wraps an expectation in a block that will return true if the + # expectation passes and false if it fails (without bubbling up + # the failure). + # + # This is intended to be used in the context of a simple matcher, + # and is especially useful for wrapping multiple expectations or + # one or more assertions from test/unit extensions when running + # with test/unit. + # + # == Examples + # + # def eat_cheese(cheese) + # simple_matcher do |mouse, matcher| + # matcher.failure_message = "expected #{mouse} to eat cheese" + # wrap_expectation do |matcher| + # assert_eats_cheese(mouse) + # end + # end + # end + # + # describe Mouse do + # it "eats cheese" do + # Mouse.new.should eat_cheese + # end + # end + # + # You might be wondering "why would I do this if I could just say" + # assert_eats_cheese?", a fair question, indeed. You might prefer + # to replace the word assert with something more aligned with the + # rest of your code examples. You are using rspec, after all. + # + # The other benefit you get is that you can use the negative version + # of the matcher: + # + # describe Cat do + # it "does not eat cheese" do + # Cat.new.should_not eat_cheese + # end + # end + # + # So in the event there is no assert_does_not_eat_cheese available, + # you're all set! + def wrap_expectation(matcher, &block) + begin + block.call(matcher) + return true + rescue Exception => e + matcher.failure_message = e.message + return false + end + end + end +end |