rspec 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. data/.document +4 -4
  2. data/{History.txt → History.rdoc} +27 -4
  3. data/Manifest.txt +18 -7
  4. data/{README.txt → README.rdoc} +0 -0
  5. data/Rakefile +16 -9
  6. data/{Ruby1.9.markdown → Ruby1.9.rdoc} +3 -3
  7. data/TODO.txt +0 -7
  8. data/Upgrade.rdoc +110 -0
  9. data/features/matchers/create_matcher.feature +40 -0
  10. data/features/matchers/create_matcher_outside_rspec.feature +39 -0
  11. data/features/pending/pending_examples.feature +5 -5
  12. data/features/step_definitions/running_rspec.rb +13 -0
  13. data/features/subject/explicit_subject.feature +31 -0
  14. data/features/subject/implicit_subject.feature +31 -0
  15. data/lib/spec/adapters/mock_frameworks/flexmock.rb +1 -0
  16. data/lib/spec/adapters/mock_frameworks/mocha.rb +1 -0
  17. data/lib/spec/adapters/mock_frameworks/rr.rb +1 -0
  18. data/lib/spec/adapters/mock_frameworks/rspec.rb +12 -10
  19. data/lib/spec/dsl.rb +0 -1
  20. data/lib/spec/dsl/main.rb +3 -3
  21. data/lib/spec/example.rb +4 -3
  22. data/lib/spec/example/example_group_factory.rb +1 -3
  23. data/lib/spec/example/example_group_methods.rb +22 -28
  24. data/lib/spec/example/example_group_proxy.rb +64 -0
  25. data/lib/spec/example/example_methods.rb +8 -11
  26. data/lib/spec/example/example_proxy.rb +42 -0
  27. data/lib/spec/example/shared_example_group.rb +1 -1
  28. data/lib/spec/example/subject.rb +14 -3
  29. data/lib/spec/expectations.rb +1 -1
  30. data/lib/spec/expectations/differs/default.rb +46 -49
  31. data/lib/spec/expectations/differs/load-diff-lcs.rb +12 -0
  32. data/lib/spec/interop/test/unit/testcase.rb +2 -2
  33. data/lib/spec/matchers.rb +49 -9
  34. data/lib/spec/matchers/be.rb +12 -15
  35. data/lib/spec/matchers/change.rb +1 -0
  36. data/lib/spec/matchers/dsl.rb +15 -0
  37. data/lib/spec/matchers/have.rb +9 -8
  38. data/lib/spec/matchers/include.rb +2 -16
  39. data/lib/spec/matchers/match_array.rb +2 -14
  40. data/lib/spec/matchers/matcher.rb +16 -11
  41. data/lib/spec/matchers/pretty.rb +36 -0
  42. data/lib/spec/matchers/raise_error.rb +9 -8
  43. data/lib/spec/matchers/simple_matcher.rb +1 -0
  44. data/lib/spec/matchers/throw_symbol.rb +1 -1
  45. data/lib/spec/mocks/argument_expectation.rb +2 -0
  46. data/lib/spec/mocks/message_expectation.rb +2 -0
  47. data/lib/spec/mocks/proxy.rb +9 -10
  48. data/lib/spec/runner.rb +1 -0
  49. data/lib/spec/runner/extensions/kernel.rb +9 -0
  50. data/lib/spec/runner/formatter/base_formatter.rb +22 -9
  51. data/lib/spec/runner/formatter/html_formatter.rb +2 -1
  52. data/lib/spec/runner/heckle_runner.rb +1 -0
  53. data/lib/spec/runner/option_parser.rb +4 -1
  54. data/lib/spec/runner/options.rb +11 -0
  55. data/lib/spec/runner/spec_parser.rb +15 -22
  56. data/lib/spec/version.rb +4 -6
  57. data/spec/autotest/autotest_helper.rb +6 -1
  58. data/spec/spec/dsl/main_spec.rb +3 -3
  59. data/spec/spec/example/example_group_factory_spec.rb +11 -23
  60. data/spec/spec/example/example_group_methods_spec.rb +45 -20
  61. data/spec/spec/example/example_group_proxy_spec.rb +63 -0
  62. data/spec/spec/example/example_group_spec.rb +15 -0
  63. data/spec/spec/example/example_methods_spec.rb +5 -35
  64. data/spec/spec/example/example_proxy_spec.rb +47 -0
  65. data/spec/spec/example/nested_example_group_spec.rb +3 -3
  66. data/spec/spec/example/shared_example_group_spec.rb +4 -4
  67. data/spec/spec/example/subject_spec.rb +77 -0
  68. data/spec/spec/matchers/be_close_spec.rb +10 -10
  69. data/spec/spec/matchers/be_instance_of_spec.rb +13 -8
  70. data/spec/spec/matchers/be_kind_of_spec.rb +10 -8
  71. data/spec/spec/{dsl/matchers_spec.rb → matchers/dsl_spec.rb} +4 -4
  72. data/spec/spec/matchers/matcher_spec.rb +53 -1
  73. data/spec/spec/matchers/matchers_spec.rb +2 -0
  74. data/spec/spec/package/bin_spec_spec.rb +4 -4
  75. data/spec/spec/runner/command_line_spec.rb +2 -2
  76. data/spec/spec/runner/formatter/failing_example_groups_formatter_spec.rb +4 -4
  77. data/spec/spec/runner/formatter/failing_examples_formatter_spec.rb +2 -2
  78. data/spec/spec/runner/formatter/html_formatted-1.8.4.html +1 -1
  79. data/spec/spec/runner/formatter/html_formatted-1.8.5-jruby.html +1 -1
  80. data/spec/spec/runner/formatter/html_formatted-1.8.5.html +1 -1
  81. data/spec/spec/runner/formatter/html_formatted-1.8.6-jruby.html +1 -1
  82. data/spec/spec/runner/formatter/html_formatted-1.8.6.html +1 -1
  83. data/spec/spec/runner/formatter/html_formatted-1.8.7.html +1 -1
  84. data/spec/spec/runner/formatter/html_formatted-1.9.1.html +1 -1
  85. data/spec/spec/runner/formatter/nested_text_formatter_spec.rb +12 -11
  86. data/spec/spec/runner/formatter/profile_formatter_spec.rb +2 -2
  87. data/spec/spec/runner/formatter/progress_bar_formatter_spec.rb +2 -2
  88. data/spec/spec/runner/formatter/specdoc_formatter_spec.rb +2 -2
  89. data/spec/spec/runner/formatter/text_mate_formatted-1.8.4.html +1 -1
  90. data/spec/spec/runner/formatter/text_mate_formatted-1.8.6.html +1 -1
  91. data/spec/spec/runner/formatter/text_mate_formatted-1.8.7.html +1 -1
  92. data/spec/spec/runner/formatter/text_mate_formatted-1.9.1.html +1 -1
  93. data/spec/spec/runner/option_parser_spec.rb +20 -0
  94. data/spec/spec/runner/options_spec.rb +23 -1
  95. data/spec/spec/runner/reporter_spec.rb +20 -17
  96. data/spec/spec/runner/spec_parser_spec.rb +1 -1
  97. metadata +33 -15
  98. data/Upgrade.markdown +0 -63
  99. data/lib/spec/dsl/matchers.rb +0 -13
  100. data/lib/spec/example/example_description.rb +0 -15
@@ -18,18 +18,16 @@ module Spec
18
18
  # description
19
19
  # => "should start with a balance of 0"
20
20
  def description
21
- @_defined_description || ::Spec::Matchers.generated_description || "NO NAME"
21
+ @_proxy.description || ::Spec::Matchers.generated_description || "NO NAME"
22
22
  end
23
23
 
24
24
  def options # :nodoc:
25
- @_options
25
+ @_proxy.options
26
26
  end
27
27
 
28
28
  def execute(run_options, instance_variables) # :nodoc:
29
- # FIXME - there is no reason to have example_started pass a name
30
- # - in fact, it would introduce bugs in cases where no docstring
31
- # is passed to it()
32
- run_options.reporter.example_started("")
29
+ puts caller unless caller(0)[1] =~ /example_group_methods/
30
+ run_options.reporter.example_started(@_proxy)
33
31
  set_instance_variables_from_hash(instance_variables)
34
32
 
35
33
  execution_error = nil
@@ -47,7 +45,7 @@ module Spec
47
45
  end
48
46
  end
49
47
 
50
- run_options.reporter.example_finished(ExampleDescription.new(description, options), execution_error)
48
+ run_options.reporter.example_finished(@_proxy.update(description), execution_error)
51
49
  success = execution_error.nil? || ExamplePendingError === execution_error
52
50
  end
53
51
 
@@ -77,7 +75,7 @@ module Spec
77
75
  def set_instance_variables_from_hash(ivars) # :nodoc:
78
76
  ivars.each do |variable_name, value|
79
77
  # Ruby 1.9 requires variable.to_s on the next line
80
- unless ['@_defined_description', '@_options', '@_implementation', '@method_name'].include?(variable_name.to_s)
78
+ unless ['@_proxy', '@_implementation', '@method_name'].include?(variable_name.to_s)
81
79
  instance_variable_set variable_name, value
82
80
  end
83
81
  end
@@ -107,9 +105,8 @@ WARNING
107
105
  example_group_hierarchy.run_after_each(self)
108
106
  end
109
107
 
110
- def initialize(description, options={}, &implementation)
111
- @_options = options
112
- @_defined_description = description
108
+ def initialize(example_proxy, &implementation)
109
+ @_proxy = example_proxy
113
110
  @_implementation = implementation
114
111
  @_backtrace = caller
115
112
  end
@@ -0,0 +1,42 @@
1
+ module Spec
2
+ module Example
3
+ # Lightweight representation of an example. This is the object
4
+ # that is passed to example-related methods in
5
+ # Spec::Runner::Formatter::BaseFormatter
6
+ class ExampleProxy
7
+
8
+ def initialize(description=nil, options={}, location=nil) # :nodoc:
9
+ @description, @options, @location = description, options, location
10
+ end
11
+
12
+ # This is the docstring passed to the <tt>it()</tt> method or any
13
+ # of its aliases
14
+ attr_reader :description
15
+
16
+ # Internal use only - used to store options to pass to example
17
+ # when it is initialized
18
+ attr_reader :options # :nodoc:
19
+
20
+ # The file and line number at which the represented example
21
+ # was declared. This is extracted from <tt>caller</tt>, and is therefore
22
+ # formatted as an individual line in a backtrace.
23
+ attr_reader :location
24
+
25
+ # Deprecated - use location()
26
+ def backtrace
27
+ location
28
+ end
29
+
30
+ # Convenience method for example group - updates the value of
31
+ # <tt>description</tt> and returns self.
32
+ def update(description) # :nodoc:
33
+ @description = description
34
+ self
35
+ end
36
+
37
+ def ==(other) # :nodoc:
38
+ (other.description == description) & (other.backtrace == backtrace)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -39,7 +39,7 @@ module Spec
39
39
  end
40
40
 
41
41
  def expanded_path(example_group)
42
- File.expand_path(example_group.spec_path)
42
+ File.expand_path(example_group.location)
43
43
  end
44
44
  end
45
45
 
@@ -15,12 +15,23 @@ module Spec
15
15
  #
16
16
  # See +ExampleMethods#should+ for more information about this approach.
17
17
  def subject(&block)
18
- if block.nil?
19
- @_subject_block || (described_class ? lambda {described_class.new} : lambda {description_args.first})
18
+ block.nil? ?
19
+ explicit_subject || implicit_subject : @_explicit_subject_block = block
20
+ end
21
+
22
+ def explicit_subject
23
+ if defined?(@_explicit_subject_block)
24
+ @_explicit_subject_block
25
+ elsif super_subject = superclass.instance_variable_get('@_explicit_subject_block')
26
+ super_subject
20
27
  else
21
- @_subject_block = block
28
+ nil
22
29
  end
23
30
  end
31
+
32
+ def implicit_subject
33
+ (described_class ? lambda {described_class.new} : lambda {description_args.first})
34
+ end
24
35
  end
25
36
 
26
37
  module ExampleMethods
@@ -31,7 +31,7 @@ module Spec
31
31
  # matchers is quite simple. See Spec::Matchers for details.
32
32
  module Expectations
33
33
  def self.differ
34
- @differ
34
+ defined?(@differ) ? @differ : nil
35
35
  end
36
36
 
37
37
  def self.differ=(differ)
@@ -1,64 +1,61 @@
1
- begin
2
- require 'diff/lcs' #necessary due to loading bug on some machines - not sure why - DaC
3
- require 'diff/lcs/hunk'
4
- rescue LoadError ; raise "You must gem install diff-lcs to use diffing" ; end
5
-
1
+ require File.join(File.dirname(__FILE__), "/load-diff-lcs")
6
2
  require 'pp'
7
3
 
8
4
  module Spec
9
5
  module Expectations
10
6
  module Differs
7
+ unless defined?(Default)
8
+ class Default
9
+ def initialize(options)
10
+ @options = options
11
+ end
11
12
 
12
- # TODO add some rdoc
13
- class Default
14
- def initialize(options)
15
- @options = options
16
- end
17
-
18
- # This is snagged from diff/lcs/ldiff.rb (which is a commandline tool)
19
- def diff_as_string(data_new, data_old)
20
- data_old = data_old.split(/\n/).map! { |e| e.chomp }
21
- data_new = data_new.split(/\n/).map! { |e| e.chomp }
22
- output = ""
23
- diffs = Diff::LCS.diff(data_old, data_new)
24
- return output if diffs.empty?
25
- oldhunk = hunk = nil
26
- file_length_difference = 0
27
- diffs.each do |piece|
28
- begin
29
- hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, context_lines,
30
- file_length_difference)
31
- file_length_difference = hunk.file_length_difference
32
- next unless oldhunk
33
- # Hunks may overlap, which is why we need to be careful when our
34
- # diff includes lines of context. Otherwise, we might print
35
- # redundant lines.
36
- if (context_lines > 0) and hunk.overlaps?(oldhunk)
37
- hunk.unshift(oldhunk)
38
- else
39
- output << oldhunk.diff(format)
13
+ # This is snagged from diff/lcs/ldiff.rb (which is a commandline tool)
14
+ def diff_as_string(data_new, data_old)
15
+ data_old = data_old.split(/\n/).map! { |e| e.chomp }
16
+ data_new = data_new.split(/\n/).map! { |e| e.chomp }
17
+ output = ""
18
+ diffs = Diff::LCS.diff(data_old, data_new)
19
+ return output if diffs.empty?
20
+ oldhunk = hunk = nil
21
+ file_length_difference = 0
22
+ diffs.each do |piece|
23
+ begin
24
+ hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, context_lines,
25
+ file_length_difference)
26
+ file_length_difference = hunk.file_length_difference
27
+ next unless oldhunk
28
+ # Hunks may overlap, which is why we need to be careful when our
29
+ # diff includes lines of context. Otherwise, we might print
30
+ # redundant lines.
31
+ if (context_lines > 0) and hunk.overlaps?(oldhunk)
32
+ hunk.unshift(oldhunk)
33
+ else
34
+ output << oldhunk.diff(format)
35
+ end
36
+ ensure
37
+ oldhunk = hunk
38
+ output << "\n"
40
39
  end
41
- ensure
42
- oldhunk = hunk
43
- output << "\n"
44
- end
40
+ end
41
+ #Handle the last remaining hunk
42
+ output << oldhunk.diff(format) << "\n"
45
43
  end
46
- #Handle the last remaining hunk
47
- output << oldhunk.diff(format) << "\n"
48
- end
49
44
 
50
- def diff_as_object(target,expected)
51
- diff_as_string(PP.pp(target,""), PP.pp(expected,""))
52
- end
45
+ def diff_as_object(target,expected)
46
+ diff_as_string(PP.pp(target,""), PP.pp(expected,""))
47
+ end
53
48
 
54
- protected
55
- def format
56
- @options.diff_format
57
- end
49
+ protected
50
+ def format
51
+ @options.diff_format
52
+ end
58
53
 
59
- def context_lines
60
- @options.context_lines
54
+ def context_lines
55
+ @options.context_lines
56
+ end
61
57
  end
58
+
62
59
  end
63
60
  end
64
61
  end
@@ -0,0 +1,12 @@
1
+ begin
2
+ require 'diff/lcs'
3
+ rescue LoadError
4
+ begin
5
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
6
+ require 'diff/lcs'
7
+ rescue LoadError
8
+ raise "You must gem install diff-lcs to use diffing"
9
+ end
10
+ end
11
+
12
+ require 'diff/lcs/hunk'
@@ -40,10 +40,10 @@ module Test
40
40
  before(:each) {setup}
41
41
  after(:each) {teardown}
42
42
 
43
- def initialize(description, options={}, &implementation)
43
+ def initialize(description, &implementation)
44
44
  super
45
45
  # Some Test::Unit extensions depend on @method_name being present.
46
- @method_name = description
46
+ @method_name = description.description
47
47
  @_result = ::Test::Unit::TestResult.new
48
48
  end
49
49
 
@@ -1,4 +1,5 @@
1
1
  require 'spec/matchers/extensions/instance_exec'
2
+ require 'spec/matchers/pretty'
2
3
  require 'spec/matchers/matcher'
3
4
  require 'spec/matchers/operator_matcher'
4
5
  require 'spec/matchers/be'
@@ -24,6 +25,7 @@ require 'spec/matchers/simple_matcher'
24
25
  require 'spec/matchers/throw_symbol'
25
26
  require 'spec/matchers/wrap_expectation'
26
27
  require 'spec/matchers/compatibility'
28
+ require 'spec/matchers/dsl'
27
29
 
28
30
  module Spec
29
31
 
@@ -82,14 +84,17 @@ module Spec
82
84
  # You can use this feature to invoke any predicate that begins with "has_", whether it is
83
85
  # part of the Ruby libraries (like +Hash#has_key?+) or a method you wrote on your own class.
84
86
  #
85
- # == Custom Expectation Matchers
87
+ # == Custom Matchers
86
88
  #
87
89
  # When you find that none of the stock Expectation Matchers provide a natural
88
- # feeling expectation, you can very easily write your own.
90
+ # feeling expectation, you can very easily write your own using RSpec's matcher
91
+ # DSL or writing one from scratch.
89
92
  #
90
- # For example, imagine that you are writing a game in which players can
91
- # be in various zones on a virtual board. To specify that bob should
92
- # be in zone 4, you could say:
93
+ # === Matcher DSL
94
+ #
95
+ # Imagine that you are writing a game in which players can be in various
96
+ # zones on a virtual board. To specify that bob should be in zone 4, you
97
+ # could say:
93
98
  #
94
99
  # bob.current_zone.should eql(Zone.new("4"))
95
100
  #
@@ -101,7 +106,42 @@ module Spec
101
106
  #
102
107
  # bob.should_not be_in_zone("3")
103
108
  #
104
- # To do this, you would need to write a class like this:
109
+ # You can create such a matcher like so:
110
+ #
111
+ # Spec::Matchers.create :be_in_zone do |zone|
112
+ # match do |player|
113
+ # player.in_zone?(zone)
114
+ # end
115
+ # end
116
+ #
117
+ # This will generate a <tt>be_in_zone</tt> method that returns a matcher
118
+ # with logical default messages for failures. You can override the failure
119
+ # messages and the generated description as follows:
120
+ #
121
+ # Spec::Matchers.create :be_in_zone do |zone|
122
+ # match do |player|
123
+ # player.in_zone?(zone)
124
+ # end
125
+ # failure_message_for_should do |player|
126
+ # # generate and return the appropriate string.
127
+ # end
128
+ # failure_message_for_should_not do |player|
129
+ # # generate and return the appropriate string.
130
+ # end
131
+ # description do
132
+ # # generate and return the appropriate string.
133
+ # end
134
+ # end
135
+ #
136
+ # Each of the message-generation methods has access to the block arguments
137
+ # passed to the <tt>create</tt> method (in this case, <tt>zone</tt>). The
138
+ # failure message methods (<tt>failure_message_for_should</tt> and
139
+ # <tt>failure_message_for_should_not</tt>) are passed the actual value (the
140
+ # receiver of <tt>should</tt> or <tt>should_not</tt>).
141
+ #
142
+ # === Custom Matcher from scratch
143
+ #
144
+ # You could also write a custom matcher from scratch, as follows:
105
145
  #
106
146
  # class BeInZone
107
147
  # def initialize(expected)
@@ -111,10 +151,10 @@ module Spec
111
151
  # @target = target
112
152
  # @target.current_zone.eql?(Zone.new(@expected))
113
153
  # end
114
- # def failure_message
154
+ # def failure_message_for_should
115
155
  # "expected #{@target.inspect} to be in Zone #{@expected}"
116
156
  # end
117
- # def negative_failure_message
157
+ # def failure_message_for_should_not
118
158
  # "expected #{@target.inspect} not to be in Zone #{@expected}"
119
159
  # end
120
160
  # end
@@ -152,4 +192,4 @@ module Spec
152
192
  # end
153
193
  #
154
194
  module Matchers; end
155
- end
195
+ end
@@ -2,9 +2,12 @@ module Spec
2
2
  module Matchers
3
3
 
4
4
  class Be #:nodoc:
5
+ include Spec::Matchers::Pretty
6
+
5
7
  def initialize(*args)
6
8
  @expected = args.empty? ? true : set_expected(args.shift)
7
9
  @args = args
10
+ @comparison_method = nil
8
11
  end
9
12
 
10
13
  def matches?(actual)
@@ -98,6 +101,9 @@ it reads really poorly.
98
101
  end
99
102
 
100
103
  def prefix
104
+ # FIXME - this is a bit goofy - but we get failures
105
+ # if just defining @prefix = nil in initialize
106
+ @prefix = nil unless defined?(@prefix)
101
107
  @prefix
102
108
  end
103
109
 
@@ -107,7 +113,9 @@ it reads really poorly.
107
113
 
108
114
  def handling_predicate?
109
115
  return false if [true, false, nil].include?(expected)
110
- return @handling_predicate
116
+ # FIXME - this is a bit goofy - but we get failures
117
+ # if just defining @handling_predicate = nil or false in initialize
118
+ return defined?(@handling_predicate) ? @handling_predicate : nil
111
119
  end
112
120
 
113
121
  def predicate
@@ -142,19 +150,8 @@ it reads really poorly.
142
150
  split_words(prefix)
143
151
  end
144
152
 
145
- def split_words(sym)
146
- sym.to_s.gsub(/_/,' ')
147
- end
148
-
149
153
  def args_to_sentence
150
- case @args.length
151
- when 0
152
- ""
153
- when 1
154
- " #{@args[0]}"
155
- else
156
- " #{@args[0...-1].join(', ')} and #{@args[-1]}"
157
- end
154
+ to_sentence(@args)
158
155
  end
159
156
 
160
157
  end
@@ -163,9 +160,9 @@ it reads really poorly.
163
160
  # should be_true
164
161
  # should be_false
165
162
  # should be_nil
166
- # should be_arbitrary_predicate(*args)
163
+ # should be_[arbitrary_predicate](*args)
167
164
  # should_not be_nil
168
- # should_not be_arbitrary_predicate(*args)
165
+ # should_not be_[arbitrary_predicate](*args)
169
166
  #
170
167
  # Given true, false, or nil, will pass if actual value is
171
168
  # true, false or nil (respectively). Given no args means
@@ -6,6 +6,7 @@ module Spec
6
6
  def initialize(receiver=nil, message=nil, &block)
7
7
  @message = message || "result"
8
8
  @value_proc = block || lambda {receiver.__send__(message)}
9
+ @to = @from = @minimum = @maximum = @amount = nil
9
10
  end
10
11
 
11
12
  def matches?(event_proc)