rspec-core 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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