rspec_multi_matchers 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2008-11-18
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,18 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ lib/match_each.rb
6
+ lib/match_enum.rb
7
+ lib/match_in_order.rb
8
+ lib/rspec_multi_matchers.rb
9
+ script/console
10
+ script/destroy
11
+ script/generate
12
+ spec/match_each_spec.rb
13
+ spec/match_enum_spec.rb
14
+ spec/match_in_order_spec.rb
15
+ spec/shared_enum_spec.rb
16
+ spec/spec.opts
17
+ spec/spec_helper.rb
18
+ tasks/rspec.rake
data/README.rdoc ADDED
@@ -0,0 +1,72 @@
1
+ = rspec-multi-matchers
2
+
3
+ * http://github.com/gregwebs/rspec-multi-matchers
4
+
5
+ == DESCRIPTION:
6
+
7
+ * match_each
8
+ * match_enum
9
+ * match_in_order
10
+
11
+ require 'rubygems'
12
+ require 'spec'
13
+ require 'rspec_multi_matchers'
14
+
15
+ describe 'array of ones' do
16
+ it 'should be all ones' do
17
+ [1,2,3].should each { |n|
18
+ n.should == 1
19
+ }
20
+ end
21
+ end
22
+
23
+ =begin output
24
+ 'array of ones should fail on 2' FAILED
25
+ line: 14
26
+ item 1: 2
27
+ expected: 1,
28
+ got: 2 (using ==)
29
+ =end
30
+
31
+ As expected, the output shows expected and got fields
32
+ line is the line number of the expectiation inside the block
33
+ the item line gives the index of the item being yielded to the block, and the item itself
34
+
35
+
36
+ === Warning
37
+
38
+ Note the use of brackets '{ ... }' instead of 'do ... end'
39
+ this is necessary because 'do .. end' does not bind strong enough
40
+
41
+ == RELATED ARTICLES:
42
+
43
+ * http://blog.thoughtfolder.com/2008-11-05-rspec-should-each-matcher.html
44
+
45
+ == INSTALL:
46
+
47
+ * sudo gem install gregwebs-rspec-multi-matchers --source http://gems.github.com
48
+
49
+ == LICENSE:
50
+
51
+ (The MIT License)
52
+
53
+ Copyright (c) 2008 Greg Weber
54
+
55
+ Permission is hereby granted, free of charge, to any person obtaining
56
+ a copy of this software and associated documentation files (the
57
+ 'Software'), to deal in the Software without restriction, including
58
+ without limitation the rights to use, copy, modify, merge, publish,
59
+ distribute, sublicense, and/or sell copies of the Software, and to
60
+ permit persons to whom the Software is furnished to do so, subject to
61
+ the following conditions:
62
+
63
+ The above copyright notice and this permission notice shall be
64
+ included in all copies or substantial portions of the Software.
65
+
66
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
67
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
68
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
69
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
70
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
71
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
72
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/rspec_multi_matchers'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('rspec_multi_matchers', RspecMultiMatchers::VERSION) do |p|
7
+ p.developer('Greg Weber', '')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ # p.extra_deps = [
10
+ # ['activesupport','>= 2.0.2'],
11
+ # ]
12
+ p.extra_dev_deps = [
13
+ ['newgem', ">= #{::Newgem::VERSION}"]
14
+ ]
15
+
16
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
17
+ #path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
18
+ #p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
19
+ #p.rsync_args = '-av --delete --ignore-errors'
20
+ end
21
+
22
+ require 'newgem/tasks' # load /tasks/*.rake
23
+ Dir['tasks/**/*.rake'].each { |t| load t }
24
+
25
+ remove_task :default
26
+ task :default => [:spec]
data/lib/match_each.rb ADDED
@@ -0,0 +1,79 @@
1
+ class MatchEach
2
+
3
+ class MatchEachError < Exception; end
4
+ class NoBlockGivenError < MatchEachError; end
5
+
6
+ class BlankEnumerableError < MatchEachError; end
7
+
8
+ def initialize(options, &block)
9
+ @empty_okay = (options and options[:empty])
10
+ @block = block
11
+ if !@block
12
+ raise NoBlockGivenError, 'no block given, you probably need to use brackets instead of "do...end"'
13
+ end
14
+ end
15
+
16
+ def matches?(target)
17
+ if target.nil?
18
+ raise BlankEnumerableError, "Expected an enumerable object, but got nil"
19
+ end
20
+
21
+ if !@empty_okay && target.empty?
22
+ raise BlankEnumerableError, "No items in the given enumerator.\nTo allow an empty enumerator pass the :empty option with a true value"
23
+ end
24
+
25
+ @counter = 0
26
+ target.each do |obj|
27
+ begin
28
+ @block.call(obj)
29
+ rescue Spec::Expectations::ExpectationNotMetError => e
30
+ @error = e
31
+ @failure_object = obj
32
+ return false
33
+ end
34
+ @counter += 1
35
+ end
36
+ true
37
+ end
38
+
39
+ def object_description
40
+ insp = @failure_object.inspect
41
+ return insp if insp.length < 300
42
+
43
+ if @failure_object.respond_to?(:to_s)
44
+ str = @failure_object.to_s
45
+ return str if str .length < 300
46
+ end
47
+
48
+ insp[0..300] + ' ... '
49
+ end
50
+
51
+ def failure_line
52
+ # find 'matches?' in statck trace
53
+ # then move back to the first line number that is not a function call
54
+ error_line = nil
55
+ @error.backtrace.each do |line|
56
+ if line.match(/:\d+:in\s*[`'"](.*)[`'"]\s*$/)
57
+ return error_line if $1 == 'matches?'
58
+ else
59
+ error_line = line.match(/^[^:]+:(\d+)/)[1]
60
+ end
61
+ end
62
+
63
+ nil # should not reach here
64
+ end
65
+
66
+ def failure_message
67
+ padding = ' ' * if @error.message =~ /expected not/ then 4 else 0 end
68
+
69
+ [" line: #{failure_line}",
70
+ " item #{@counter}: #{object_description}"
71
+ ].map { |line| padding + line }.push(@error.message).join("\n")
72
+ end
73
+
74
+ # no need for should_not, so no negative_failure_messages
75
+ end
76
+
77
+ def each(options=nil, &block)
78
+ MatchEach.new options, &block
79
+ end
data/lib/match_enum.rb ADDED
@@ -0,0 +1,66 @@
1
+ class MatchEnum
2
+ @@enum_methods = [] # avoid re-defining
3
+
4
+ class MatchEnumError < Exception; end
5
+ class BlankEnumerableError < MatchEnumError; end
6
+ class NoBlockGivenError < MatchEnumError; end
7
+
8
+ def initialize(method, options, &block)
9
+ @method = method
10
+ @empty_okay = (options and options[:empty])
11
+ @block = block
12
+ if !@block
13
+ raise NoBlockGivenError, 'no block given, you probably need to use brackets instead of "do...end"'
14
+ end
15
+
16
+ @num_args = @block.arity
17
+ @num_args = 0 if @num_args == -1 # correct ruby error
18
+ return if @@enum_methods[@num_args]
19
+ @@enum_methods[@num_args] = true
20
+
21
+ args = (1..(@num_args)).map {|i| 'arg_' << i.to_s}.join(',')
22
+ eval <<-EOS
23
+ def enum_#{@num_args}(target)
24
+ @counter = 0
25
+ target.send(@method) do |#{args}|
26
+ begin
27
+ @block.call(#{args})
28
+ rescue Spec::Expectations::ExpectationNotMetError => e
29
+ @error_msg = e.to_s
30
+ @failure_object = [#{args}]
31
+ return false
32
+ end
33
+ @counter += 1
34
+ end
35
+ true
36
+ end
37
+ EOS
38
+ end
39
+
40
+ def enum(target)
41
+ eval("enum_#{@num_args}(target)")
42
+ end
43
+
44
+ def matches?(target)
45
+ if target.nil?
46
+ raise BlankEnumerableError, "Expected an enumerable object, but got nil"
47
+ end
48
+
49
+ if !@empty_okay && target.empty?
50
+ raise BlankEnumerableError, "No items in the given enumerator.\nTo allow an empty enumerator pass the :empty option with a true value"
51
+ end
52
+
53
+ return enum(target)
54
+ end
55
+
56
+ def failure_message
57
+ if @error_msg =~ /expected not/ then ' ' else '' end <<
58
+ " item #{@counter}: #{@failure_object.inspect}\n#{@error_msg}"
59
+ end
60
+
61
+ # no need for should_not, so no negative_failure_messages
62
+ end
63
+
64
+ def enum(method, options=nil, &block)
65
+ MatchEnum.new method, options, &block
66
+ end
@@ -0,0 +1,31 @@
1
+ class MatchInOrder
2
+ def initialize(regexps)
3
+ @regexps = regexps
4
+ end
5
+
6
+ def matches?(target)
7
+ @target = target
8
+ @regexps.inject(target) do |str, regexp|
9
+ m = str.match(regexp)
10
+ if m.nil?
11
+ @failure_string = str
12
+ @failure_regex = regexp
13
+ return false
14
+ end
15
+ m.post_match
16
+ end
17
+ true
18
+ end
19
+
20
+ def failure_message
21
+ "expected #{@failure_string.inspect} to match #{@failure_regex.inspect}\nwithin string: #{@target.inspect}"
22
+ end
23
+
24
+ def negative_failure_message
25
+ "expected #{@target.inspect} to not match in order against: #{@regexps.inspect}"
26
+ end
27
+ end
28
+
29
+ def match_in_order(*regexps)
30
+ MatchInOrder.new(regexps)
31
+ end
@@ -0,0 +1,10 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module RspecMultiMatchers
5
+ VERSION = '1.0.0'
6
+ end
7
+
8
+ require "match_each"
9
+ require "match_enum"
10
+ require "match_in_order"
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/rspec_multi_matchers.rb'}"
9
+ puts "Loading rspec_multi_matchers gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe MatchEach do
4
+ it_should_behave_like "each matcher"
5
+
6
+ before do
7
+ @class = MatchEach
8
+ @iterator = [:each]
9
+ end
10
+
11
+ it 'should add to the inner error message' do
12
+ begin
13
+ 2.should == 1
14
+ rescue Spec::Expectations::ExpectationNotMetError => e
15
+ @line = __LINE__ + 2
16
+ lambda{ [1,2,3].should each { |n|
17
+ n.should == 1
18
+ } }.should raise_error(
19
+ Spec::Expectations::ExpectationNotMetError, /^\s*line: #{@line}\s*item 1: 2\s*#{Regexp.escape(e.message)}/m)
20
+ else fail
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe MatchEnum do
4
+ it_should_behave_like "each matcher"
5
+
6
+ before do
7
+ @class = MatchEnum
8
+ @iterator = [:enum, :each]
9
+ end
10
+
11
+ it 'should enum with each_with_index' do
12
+ [1,2,3].should enum(:each_with_index) { |n,i| n.should == i + 1 }
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe MatchInOrder do
4
+
5
+ it "should match a single regular expression" do
6
+ "a".should match_in_order(//)
7
+ "a".should match_in_order(/a/)
8
+ "a".should_not match_in_order(/b/)
9
+ "z".should_not match_in_order(/a/)
10
+ end
11
+
12
+ it "should not match the same regular expressions twice" do
13
+ "a".should_not match_in_order(/a/,/a/)
14
+ lambda{ "a".should match_in_order(/a/,/a/) }.should raise_error(Spec::Expectations::ExpectationNotMetError, 'expected "" to match /a/' << "\n" << 'within string: "a"')
15
+
16
+ "abc".should_not match_in_order(/a/,/b/,/c/,/a/)
17
+ lambda{ "abc".should match_in_order(/a/,/b/,/c/,/a/) }.should raise_error(Spec::Expectations::ExpectationNotMetError, 'expected "" to match /a/' << "\n" << 'within string: "abc"')
18
+ end
19
+
20
+ it "should match multiple regular expressions in order" do
21
+ "abc".should match_in_order(/a/,/b/,/c/)
22
+ lambda{ "abc".should_not match_in_order(/a/,/b/,/c/) }.should raise_error(Spec::Expectations::ExpectationNotMetError,'expected "abc" to not match in order against: [/a/, /b/, /c/]')
23
+
24
+ "abc".should_not match_in_order(/a/,/c/,/b/)
25
+ lambda{ "abc".should match_in_order(/a/,/c/,/b/) }.should raise_error(Spec::Expectations::ExpectationNotMetError,'expected "" to match /b/' << "\n" << 'within string: "abc"')
26
+
27
+ "abc".should_not match_in_order(/b/,/a/,/c/)
28
+ lambda{ "abc".should match_in_order(/b/,/a/,/c/) }.should raise_error(Spec::Expectations::ExpectationNotMetError,'expected "c" to match /a/' << "\n" << 'within string: "abc"')
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ shared_examples_for "each matcher" do
2
+ it 'should raise an error when a block is not given' do
3
+ # do...end does not bind strongly enough, must use brackets
4
+ lambda do
5
+ [1,2,3].should send(*@iterator) do |n| n.should == n end
6
+ end.should raise_error(@class::NoBlockGivenError)
7
+ end
8
+
9
+ it 'should not raise an error for met expectations' do
10
+ [1,2,3].should send(*@iterator) {|n| n.should == n}
11
+ end
12
+
13
+ it 'should raise an error if there are no items in the enumerable object' do
14
+ lambda{ [].should send(*@iterator){} }.should raise_error(@class::BlankEnumerableError)
15
+ [false, nil].each do |f|
16
+ @iterator.push(:empty => f)
17
+ lambda{ [].should send(*@iterator){}}.should raise_error(@class::BlankEnumerableError)
18
+ @iterator.pop
19
+ end
20
+ end
21
+
22
+ it 'should not raise an error if there are no items in the enumerable object and the empty flag is passed' do
23
+ ['okay', true].each do |t|
24
+ @iterator.push(:empty => t)
25
+ lambda{ [].should send(*@iterator){} }.should_not raise_error
26
+ @iterator.pop
27
+ end
28
+ end
29
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,12 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ $:.unshift(File.dirname(__FILE__))
11
+ require 'rspec_multi_matchers'
12
+ require 'shared_enum_spec'
data/tasks/rspec.rake ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec_multi_matchers
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Greg Weber
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-09 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: newgem
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.0
34
+ version:
35
+ description: "* match_each * match_enum * match_in_order require 'rubygems' require 'spec' require 'gregwebs-rspec_multi_matchers' describe 'array of ones' do it 'should be all ones' do [1,2,3].should each { |n| n.should == 1 } end end =begin output 'array of ones should fail on 2' FAILED line: 14 item 1: 2 expected: 1, got: 2 (using ==) =end As expected, the output shows expected and got fields line is the line number of the expectiation inside the block the item line gives the index of the item being yielded to the block, and the item itself"
36
+ email:
37
+ - ""
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - README.rdoc
46
+ files:
47
+ - History.txt
48
+ - Manifest.txt
49
+ - README.rdoc
50
+ - Rakefile
51
+ - lib/match_each.rb
52
+ - lib/match_enum.rb
53
+ - lib/match_in_order.rb
54
+ - lib/rspec_multi_matchers.rb
55
+ - script/console
56
+ - script/destroy
57
+ - script/generate
58
+ - spec/match_each_spec.rb
59
+ - spec/match_enum_spec.rb
60
+ - spec/match_in_order_spec.rb
61
+ - spec/shared_enum_spec.rb
62
+ - spec/spec.opts
63
+ - spec/spec_helper.rb
64
+ - tasks/rspec.rake
65
+ has_rdoc: true
66
+ homepage: http://github.com/gregwebs/rspec-multi-matchers
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options:
71
+ - --main
72
+ - README.rdoc
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ version:
87
+ requirements: []
88
+
89
+ rubyforge_project: rspec_multi_matchers
90
+ rubygems_version: 1.3.5
91
+ signing_key:
92
+ specification_version: 2
93
+ summary: "* match_each * match_enum * match_in_order require 'rubygems' require 'spec' require 'gregwebs-rspec_multi_matchers' describe 'array of ones' do it 'should be all ones' do [1,2,3].should each { |n| n.should == 1 } end end =begin output 'array of ones should fail on 2' FAILED line: 14 item 1: 2 expected: 1, got: 2 (using ==) =end As expected, the output shows expected and got fields line is the line number of the expectiation inside the block the item line gives the index of the item being yielded to the block, and the item itself"
94
+ test_files: []
95
+