rspec-core 2.0.1 → 2.1.0

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 (63) hide show
  1. data/Gemfile +8 -3
  2. data/Guardfile +5 -0
  3. data/History.markdown +32 -2
  4. data/README.markdown +10 -3
  5. data/Rakefile +12 -13
  6. data/Upgrade.markdown +175 -121
  7. data/bin/autospec +13 -0
  8. data/bin/rspec +24 -1
  9. data/features/command_line/line_number_appended_to_path.feature +3 -1
  10. data/features/command_line/line_number_option.feature +3 -1
  11. data/features/command_line/tag.feature +74 -0
  12. data/features/filtering/exclusion_filters.feature +1 -1
  13. data/features/filtering/implicit_filters.feature +166 -0
  14. data/features/hooks/around_hooks.feature +51 -44
  15. data/features/metadata/described_class.feature +3 -0
  16. data/features/pending/pending_examples.feature +76 -0
  17. data/features/step_definitions/additional_cli_steps.rb +11 -0
  18. data/features/subject/attribute_of_subject.feature +8 -0
  19. data/features/subject/explicit_subject.feature +8 -13
  20. data/features/subject/implicit_receiver.feature +29 -0
  21. data/features/subject/implicit_subject.feature +6 -7
  22. data/lib/rspec/core.rb +3 -21
  23. data/lib/rspec/core/backward_compatibility.rb +22 -3
  24. data/lib/rspec/core/command_line.rb +1 -0
  25. data/lib/rspec/core/configuration.rb +34 -6
  26. data/lib/rspec/core/configuration_options.rb +1 -3
  27. data/lib/rspec/core/example.rb +0 -5
  28. data/lib/rspec/core/example_group.rb +9 -8
  29. data/lib/rspec/core/expecting/with_rspec.rb +11 -0
  30. data/lib/rspec/core/extensions/object.rb +1 -1
  31. data/lib/rspec/core/formatters/base_formatter.rb +1 -6
  32. data/lib/rspec/core/hooks.rb +1 -1
  33. data/lib/rspec/core/metadata.rb +15 -5
  34. data/lib/rspec/core/option_parser.rb +17 -0
  35. data/lib/rspec/core/pending.rb +10 -1
  36. data/lib/rspec/core/rake_task.rb +32 -10
  37. data/lib/rspec/core/reporter.rb +1 -0
  38. data/lib/rspec/core/subject.rb +58 -59
  39. data/lib/rspec/core/version.rb +1 -1
  40. data/lib/rspec/core/world.rb +9 -4
  41. data/rspec-core.gemspec +4 -11
  42. data/spec/rspec/core/command_line_spec.rb +16 -5
  43. data/spec/rspec/core/configuration_options_spec.rb +6 -0
  44. data/spec/rspec/core/configuration_spec.rb +89 -6
  45. data/spec/rspec/core/deprecations_spec.rb +17 -1
  46. data/spec/rspec/core/example_group_spec.rb +29 -14
  47. data/spec/rspec/core/example_spec.rb +0 -7
  48. data/spec/rspec/core/formatters/html_formatted-1.8.6.html +49 -33
  49. data/spec/rspec/core/formatters/html_formatted-1.8.7.html +5 -5
  50. data/spec/rspec/core/formatters/html_formatted-1.9.1.html +46 -26
  51. data/spec/rspec/core/formatters/html_formatted-1.9.2.html +5 -5
  52. data/spec/rspec/core/formatters/text_mate_formatted-1.8.6.html +49 -33
  53. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7.html +19 -19
  54. data/spec/rspec/core/formatters/text_mate_formatted-1.9.1.html +56 -33
  55. data/spec/rspec/core/formatters/text_mate_formatted-1.9.2.html +26 -38
  56. data/spec/rspec/core/metadata_spec.rb +153 -132
  57. data/spec/rspec/core/pending_example_spec.rb +133 -25
  58. data/spec/rspec/core/rake_task_spec.rb +25 -32
  59. data/spec/rspec/core/subject_spec.rb +15 -0
  60. data/spec/rspec/core/world_spec.rb +72 -61
  61. data/spec/spec_helper.rb +0 -14
  62. metadata +25 -135
  63. data/features/hooks/halt.feature +0 -26
@@ -23,11 +23,6 @@ module RSpec
23
23
  @example_group_class
24
24
  end
25
25
 
26
- def behaviour
27
- RSpec.deprecate("behaviour", "example_group")
28
- example_group
29
- end
30
-
31
26
  def pending?
32
27
  !!pending
33
28
  end
@@ -4,14 +4,15 @@ module RSpec
4
4
  extend Extensions::ModuleEvalWithArgs
5
5
  include Extensions::InstanceEvalWithArgs
6
6
  extend Hooks
7
- include Subject
7
+ extend Subject::ClassMethods
8
+ include Subject::InstanceMethods
8
9
  include Let
9
10
  include Pending
10
11
 
11
12
  attr_accessor :example
12
13
 
13
14
  def running_example
14
- RSpec.deprecate('running_example', 'example')
15
+ RSpec.deprecate("running_example", "example")
15
16
  example
16
17
  end
17
18
 
@@ -19,9 +20,9 @@ module RSpec
19
20
  RSpec.world
20
21
  end
21
22
 
22
- def self.inherited(klass)
23
+ def self.register
23
24
  RSpec::Core::Runner.autorun
24
- world.example_groups << klass if klass.top_level?
25
+ world.register(self)
25
26
  end
26
27
 
27
28
  class << self
@@ -68,8 +69,8 @@ module RSpec
68
69
  raise "Could not find shared example group named \#{name.inspect}" unless shared_block
69
70
 
70
71
  group = describe("#{report_label || "it should behave like"} \#{name}") do
71
- module_eval_with_args *args, &shared_block
72
- module_eval &customization_block if customization_block
72
+ module_eval_with_args(*args, &shared_block)
73
+ module_eval(&customization_block) if customization_block
73
74
  end
74
75
  group.metadata[:shared_group_name] = name
75
76
  group
@@ -267,8 +268,8 @@ An error occurred in an after(:all) hook.
267
268
  end.all?
268
269
  end
269
270
 
270
- def self.all_apply?(filters)
271
- metadata.all_apply?(filters)
271
+ def self.apply?(predicate, filters)
272
+ metadata.apply?(predicate, filters)
272
273
  end
273
274
 
274
275
  def self.declaration_line_numbers
@@ -0,0 +1,11 @@
1
+ require 'rspec/expectations'
2
+
3
+ module RSpec
4
+ module Core
5
+ module ExpectationFrameworkAdapter
6
+
7
+ include RSpec::Matchers
8
+
9
+ end
10
+ end
11
+ end
@@ -3,7 +3,7 @@ module RSpec
3
3
  module ObjectExtensions
4
4
  def describe(*args, &example_group_block)
5
5
  args << {} unless args.last.is_a?(Hash)
6
- RSpec::Core::ExampleGroup.describe(*args, &example_group_block)
6
+ RSpec::Core::ExampleGroup.describe(*args, &example_group_block).register
7
7
  end
8
8
  end
9
9
  end
@@ -12,7 +12,7 @@ module RSpec
12
12
  attr_reader :failed_examples, :pending_examples
13
13
 
14
14
  def initialize(output)
15
- @output = output
15
+ @output = output || StringIO.new
16
16
  @example_count = @pending_count = @failure_count = 0
17
17
  @examples = []
18
18
  @failed_examples = []
@@ -45,11 +45,6 @@ module RSpec
45
45
  def example_group_finished(example_group)
46
46
  end
47
47
 
48
- def add_example_group(example_group)
49
- RSpec.deprecate("add_example_group", "example_group_started")
50
- example_group_started(example_group)
51
- end
52
-
53
48
  def example_started(example)
54
49
  examples << example
55
50
  end
@@ -11,7 +11,7 @@ module RSpec
11
11
  end
12
12
 
13
13
  def options_apply?(group)
14
- !group || group.all_apply?(options)
14
+ !group || group.apply?(:all?, options)
15
15
  end
16
16
 
17
17
  def to_proc
@@ -32,7 +32,7 @@ module RSpec
32
32
  self[:example_group][:full_description] = full_description_from(*args)
33
33
 
34
34
  self[:example_group][:block] = user_metadata.delete(:example_group_block)
35
- self[:example_group][:file_path], self[:example_group][:line_number] = file_and_line_number_from(caller)
35
+ self[:example_group][:file_path], self[:example_group][:line_number] = file_and_line_number_from(user_metadata.delete(:caller) || caller)
36
36
  self[:example_group][:location] = location_from(self[:example_group])
37
37
 
38
38
  update(user_metadata)
@@ -68,13 +68,13 @@ EOM
68
68
  store(:description, description.to_s)
69
69
  store(:full_description, "#{self[:example_group][:full_description]} #{self[:description]}")
70
70
  store(:execution_result, {})
71
- self[:file_path], self[:line_number] = file_and_line_number_from(caller)
71
+ self[:file_path], self[:line_number] = file_and_line_number_from(options.delete(:caller) || caller)
72
72
  self[:location] = location_from(self)
73
73
  update(options)
74
74
  end
75
75
 
76
- def all_apply?(filters)
77
- filters.all? do |key, value|
76
+ def apply?(predicate, filters)
77
+ filters.send(predicate) do |key, value|
78
78
  apply_condition(key, value)
79
79
  end
80
80
  end
@@ -96,7 +96,17 @@ EOM
96
96
  when Regexp
97
97
  metadata[key] =~ value
98
98
  when Proc
99
- value.call(metadata[key]) rescue false
99
+ if value.arity == 2
100
+ # Pass the metadata hash to allow the proc to check if it even has the key.
101
+ # This is necessary for the implicit :if exclusion filter:
102
+ # { } # => run the example
103
+ # { :if => nil } # => exclude the example
104
+ # The value of metadata[:if] is the same in these two cases but
105
+ # they need to be treated differently.
106
+ value.call(metadata[key], metadata) rescue false
107
+ else
108
+ value.call(metadata[key]) rescue false
109
+ end
100
110
  when Fixnum
101
111
  if key == :line_number
102
112
  relevant_line_numbers(metadata).include?(world.preceding_declaration_line(value))
@@ -99,6 +99,23 @@ module RSpec::Core
99
99
  parser.on('--autotest') do |o|
100
100
  options[:autotest] = true
101
101
  end
102
+
103
+ parser.on('--fail-fast', 'Use the fail_fast option to tell RSpec to abort the run on first failure.') do |o|
104
+ options[:fail_fast] = true
105
+ end
106
+
107
+ parser.on('-t', '--tag TAG[:VALUE]', 'Run examples with the specified tag',
108
+ 'To exclude examples, add ~ before the tag (e.g. ~slow)',
109
+ '(TAG is always converted to a symbol)') do |tag|
110
+ filter_type = tag =~ /^~/ ? :exclusion_filter : :filter
111
+
112
+ name,value = tag.gsub(/^(~@|~|@)/, '').split(':')
113
+ name = name.to_sym
114
+ value = true if value.nil?
115
+
116
+ options[filter_type] ||= {}
117
+ options[filter_type][name] = value
118
+ end
102
119
  end
103
120
  end
104
121
  end
@@ -1,7 +1,16 @@
1
1
  module RSpec
2
2
  module Core
3
3
  module Pending
4
- def pending(message = 'No reason given')
4
+ DEFAULT_MESSAGE = 'No reason given'
5
+
6
+ def pending(*args)
7
+ options = args.last.is_a?(Hash) ? args.pop : {}
8
+ message = args.first || DEFAULT_MESSAGE
9
+
10
+ if options[:unless] || (options.has_key?(:if) && !options[:if])
11
+ return block_given? ? yield : nil
12
+ end
13
+
5
14
  example.metadata[:pending] = true
6
15
  example.metadata[:execution_result][:pending_message] = message
7
16
  if block_given?
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'rspec/core'
3
4
  require 'rspec/core/deprecation'
4
5
  require 'rake'
5
6
  require 'rake/tasklib'
@@ -20,7 +21,22 @@ module RSpec
20
21
  # 'spec/**/*_spec.rb'
21
22
  attr_accessor :pattern
22
23
 
24
+ # By default, if there is a Gemfile, the generated command will include
25
+ # 'bundle exec'. Set this to true to ignore the presence of a Gemfile, and
26
+ # not add 'bundle exec' to the command.
27
+ #
28
+ # default:
29
+ # false
30
+ attr_accessor :skip_bundler
31
+
32
+ # Name of Gemfile to use
33
+ #
34
+ # default:
35
+ # Gemfile
36
+ attr_accessor :gemfile
37
+
23
38
  # Deprecated. Use ruby_opts="-w" instead.
39
+ #
24
40
  # When true, requests that the specs be run with the warning flag set.
25
41
  # e.g. "ruby -w"
26
42
  #
@@ -29,7 +45,7 @@ module RSpec
29
45
  attr_reader :warning
30
46
 
31
47
  def warning=(true_or_false)
32
- RSpec.deprecate("warning", 'ruby_opts="-w"')
48
+ RSpec.deprecate("RSpec::Core::RakeTask#warning=", 'ruby_opts="-w"')
33
49
  @warning = true_or_false
34
50
  end
35
51
 
@@ -57,7 +73,7 @@ module RSpec
57
73
 
58
74
  # Path to rcov.
59
75
  #
60
- # defaults:
76
+ # default:
61
77
  # 'rcov'
62
78
  attr_accessor :rcov_path
63
79
 
@@ -86,16 +102,22 @@ module RSpec
86
102
  attr_accessor :rspec_opts
87
103
 
88
104
  # Deprecated. Use rspec_opts instead.
105
+ #
106
+ # Command line options to pass to rspec.
107
+ #
108
+ # default:
109
+ # nil
89
110
  def spec_opts=(opts)
90
- RSpec.deprecate("spec_opts","rspec_opts")
111
+ RSpec.deprecate('RSpec::Core::RakeTask#spec_opts=', 'rspec_opts=')
91
112
  @rspec_opts = opts
92
113
  end
93
114
 
94
115
  def initialize(*args)
95
116
  @name = args.shift || :spec
96
117
  @pattern, @rcov_path, @rcov_opts, @ruby_opts, @rspec_opts = nil, nil, nil, nil, nil
97
- @warning, @rcov = false, false
118
+ @warning, @rcov, @skip_bundler = false, false, false
98
119
  @verbose, @fail_on_error = true, true
120
+ @gemfile = 'Gemfile'
99
121
 
100
122
  yield self if block_given?
101
123
 
@@ -136,10 +158,10 @@ module RSpec
136
158
  cmd_parts = [ruby_opts]
137
159
  cmd_parts << "-w" if warning?
138
160
  cmd_parts << "-S"
139
- cmd_parts << "bundle exec" if bundler?
161
+ cmd_parts << "bundle exec" if gemfile? unless skip_bundler
140
162
  cmd_parts << runner
141
163
  if rcov
142
- cmd_parts << ["-Ispec", rcov_opts]
164
+ cmd_parts << ["-Ispec", "-Ilib", rcov_opts]
143
165
  else
144
166
  cmd_parts << rspec_opts
145
167
  end
@@ -157,10 +179,6 @@ module RSpec
157
179
  rcov ? rcov_path : rspec_path
158
180
  end
159
181
 
160
- def bundler?
161
- File.exist?("./Gemfile")
162
- end
163
-
164
182
  def warning?
165
183
  warning
166
184
  end
@@ -169,6 +187,10 @@ module RSpec
169
187
  lambda {|s| s == ""}
170
188
  end
171
189
 
190
+ def gemfile?
191
+ File.exist?(gemfile)
192
+ end
193
+
172
194
  end
173
195
  end
174
196
  end
@@ -3,6 +3,7 @@ module RSpec::Core
3
3
  def initialize(*formatters)
4
4
  @formatters = formatters
5
5
  @example_count = @failure_count = @pending_count = 0
6
+ @duration = @start = nil
6
7
  end
7
8
 
8
9
  def report(count)
@@ -1,69 +1,68 @@
1
- require 'ostruct'
2
-
3
1
  module RSpec
4
2
  module Core
5
3
  module Subject
4
+ module InstanceMethods
6
5
 
7
- def self.included(kls)
8
- kls.class_eval do
9
- extend ClassMethods
10
- alias_method :__should_for_example_group__, :should
11
- alias_method :__should_not_for_example_group__, :should_not
6
+ # Returns the subject defined by the example group. The subject block is
7
+ # only executed once per example, the result of which is cached and
8
+ # returned by any subsequent calls to +subject+.
9
+ #
10
+ # If a class is passed to +describe+ and no subject is explicitly
11
+ # declared in the example group, then +subject+ will return a new
12
+ # instance of that class.
13
+ #
14
+ # == Examples
15
+ #
16
+ # # explicit subject defined by the subject method
17
+ # describe Person do
18
+ # subject { Person.new(:birthdate => 19.years.ago) }
19
+ # it "should be eligible to vote" do
20
+ # subject.should be_eligible_to_vote
21
+ # end
22
+ # end
23
+ #
24
+ # # implicit subject => { Person.new }
25
+ # describe Person do
26
+ # it "should be eligible to vote" do
27
+ # subject.should be_eligible_to_vote
28
+ # end
29
+ # end
30
+ def subject
31
+ @original_subject ||= instance_eval(&self.class.subject)
12
32
  end
13
- end
14
33
 
15
- # Returns the subject defined by the example group. The subject block is
16
- # only executed once per example, the result of which is cached and
17
- # returned by any subsequent calls to +subject+.
18
- #
19
- # If a class is passed to +describe+ and no subject is explicitly
20
- # declared in the example group, then +subject+ will return a new
21
- # instance of that class.
22
- #
23
- # == Examples
24
- #
25
- # # explicit subject defined by the subject method
26
- # describe Person do
27
- # subject { Person.new(:birthdate => 19.years.ago) }
28
- # it "should be eligible to vote" do
29
- # subject.should be_eligible_to_vote
30
- # end
31
- # end
32
- #
33
- # # implicit subject => { Person.new }
34
- # describe Person do
35
- # it "should be eligible to vote" do
36
- # subject.should be_eligible_to_vote
37
- # end
38
- # end
39
- def subject
40
- @original_subject ||= instance_eval(&self.class.subject)
41
- end
34
+ begin
35
+ require 'rspec/expectations/extensions/kernel'
36
+ alias_method :__should_for_example_group__, :should
37
+ alias_method :__should_not_for_example_group__, :should_not
42
38
 
43
- # When +should+ is called with no explicit receiver, the call is
44
- # delegated to the object returned by +subject+. Combined with
45
- # an implicit subject (see +subject+), this supports very concise
46
- # expressions.
47
- #
48
- # == Examples
49
- #
50
- # describe Person do
51
- # it { should be_eligible_to_vote }
52
- # end
53
- def should(matcher=nil, message=nil)
54
- self == subject ? self.__should_for_example_group__(matcher) : subject.should(matcher,message)
55
- end
39
+ # When +should+ is called with no explicit receiver, the call is
40
+ # delegated to the object returned by +subject+. Combined with
41
+ # an implicit subject (see +subject+), this supports very concise
42
+ # expressions.
43
+ #
44
+ # == Examples
45
+ #
46
+ # describe Person do
47
+ # it { should be_eligible_to_vote }
48
+ # end
49
+ def should(matcher=nil, message=nil)
50
+ self == subject ? self.__should_for_example_group__(matcher) : subject.should(matcher,message)
51
+ end
56
52
 
57
- # Just like +should+, +should_not+ delegates to the subject (implicit or
58
- # explicit) of the example group.
59
- #
60
- # == Examples
61
- #
62
- # describe Person do
63
- # it { should_not be_eligible_to_vote }
64
- # end
65
- def should_not(matcher=nil, message=nil)
66
- self == subject ? self.__should_not_for_example_group__(matcher) : subject.should_not(matcher,message)
53
+ # Just like +should+, +should_not+ delegates to the subject (implicit or
54
+ # explicit) of the example group.
55
+ #
56
+ # == Examples
57
+ #
58
+ # describe Person do
59
+ # it { should_not be_eligible_to_vote }
60
+ # end
61
+ def should_not(matcher=nil, message=nil)
62
+ self == subject ? self.__should_not_for_example_group__(matcher) : subject.should_not(matcher,message)
63
+ end
64
+ rescue LoadError
65
+ end
67
66
  end
68
67
 
69
68
  module ClassMethods
@@ -150,7 +149,7 @@ module RSpec
150
149
 
151
150
  attr_reader :explicit_subject_block # :nodoc:
152
151
 
153
- private
152
+ private
154
153
 
155
154
  def explicit_subject
156
155
  group = self