rspec-core 2.8.0.rc1 → 2.8.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/License.txt +24 -0
  2. data/README.md +197 -37
  3. data/features/command_line/format_option.feature +3 -3
  4. data/features/command_line/init.feature +18 -0
  5. data/features/example_groups/shared_examples.feature +1 -1
  6. data/features/hooks/around_hooks.feature +4 -4
  7. data/features/pending/pending_examples.feature +5 -5
  8. data/features/support/env.rb +8 -1
  9. data/lib/autotest/rspec2.rb +2 -6
  10. data/lib/rspec/core.rb +48 -158
  11. data/lib/rspec/core/backward_compatibility.rb +2 -0
  12. data/lib/rspec/core/command_line.rb +4 -0
  13. data/lib/rspec/core/configuration.rb +201 -106
  14. data/lib/rspec/core/configuration_options.rb +2 -1
  15. data/lib/rspec/core/deprecation.rb +2 -3
  16. data/lib/rspec/core/drb_options.rb +69 -58
  17. data/lib/rspec/core/dsl.rb +12 -0
  18. data/lib/rspec/core/example.rb +53 -18
  19. data/lib/rspec/core/example_group.rb +144 -54
  20. data/lib/rspec/core/extensions.rb +4 -4
  21. data/lib/rspec/core/extensions/instance_eval_with_args.rb +5 -0
  22. data/lib/rspec/core/extensions/kernel.rb +1 -1
  23. data/lib/rspec/core/extensions/module_eval_with_args.rb +4 -0
  24. data/lib/rspec/core/extensions/ordered.rb +7 -2
  25. data/lib/rspec/core/filter_manager.rb +69 -36
  26. data/lib/rspec/core/formatters/base_text_formatter.rb +1 -1
  27. data/lib/rspec/core/formatters/html_formatter.rb +10 -4
  28. data/lib/rspec/core/hooks.rb +93 -34
  29. data/lib/rspec/core/let.rb +62 -61
  30. data/lib/rspec/core/metadata.rb +103 -80
  31. data/lib/rspec/core/metadata_hash_builder.rb +4 -0
  32. data/lib/rspec/core/option_parser.rb +42 -44
  33. data/lib/rspec/core/pending.rb +25 -3
  34. data/lib/rspec/core/project_initializer.rb +62 -0
  35. data/lib/rspec/core/rake_task.rb +7 -13
  36. data/lib/rspec/core/runner.rb +2 -2
  37. data/lib/rspec/core/shared_context.rb +1 -1
  38. data/lib/rspec/core/shared_example_group.rb +11 -5
  39. data/lib/rspec/core/subject.rb +3 -3
  40. data/lib/rspec/core/version.rb +1 -1
  41. data/lib/rspec/monkey.rb +1 -1
  42. data/lib/rspec/monkey/spork/test_framework/rspec.rb +2 -0
  43. data/spec/command_line/order_spec.rb +19 -13
  44. data/spec/rspec/core/command_line_spec.rb +1 -5
  45. data/spec/rspec/core/configuration_options_spec.rb +22 -27
  46. data/spec/rspec/core/configuration_spec.rb +32 -14
  47. data/spec/rspec/core/drb_command_line_spec.rb +20 -37
  48. data/spec/rspec/core/drb_options_spec.rb +51 -3
  49. data/spec/rspec/core/example_group_spec.rb +101 -84
  50. data/spec/rspec/core/example_spec.rb +14 -0
  51. data/spec/rspec/core/filter_manager_spec.rb +114 -33
  52. data/spec/rspec/core/formatters/html_formatted-1.8.7-jruby.html +17 -69
  53. data/spec/rspec/core/formatters/html_formatted-1.8.7.html +14 -4
  54. data/spec/rspec/core/formatters/html_formatted-1.9.2.html +14 -4
  55. data/spec/rspec/core/formatters/html_formatted-1.9.3.html +14 -4
  56. data/spec/rspec/core/formatters/html_formatter_spec.rb +1 -1
  57. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-jruby.html +20 -72
  58. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7.html +24 -14
  59. data/spec/rspec/core/formatters/text_mate_formatted-1.9.2.html +29 -19
  60. data/spec/rspec/core/formatters/text_mate_formatted-1.9.3.html +29 -19
  61. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +1 -2
  62. data/spec/rspec/core/metadata_spec.rb +77 -45
  63. data/spec/rspec/core/option_parser_spec.rb +5 -0
  64. data/spec/rspec/core/pending_example_spec.rb +44 -12
  65. data/spec/rspec/core/project_initializer_spec.rb +130 -0
  66. data/spec/rspec/core/rake_task_spec.rb +1 -1
  67. data/spec/spec_helper.rb +2 -0
  68. data/spec/support/matchers.rb +2 -12
  69. metadata +18 -16
  70. data/features/command_line/configure.feature +0 -22
  71. data/lib/rspec/core/command_line_configuration.rb +0 -62
  72. data/lib/rspec/core/errors.rb +0 -13
  73. data/spec/rspec/core/command_line_configuration_spec.rb +0 -26
@@ -2,23 +2,23 @@ module RSpec
2
2
  module Core
3
3
  module Let
4
4
 
5
- module ClassMethods
5
+ module ExampleGroupMethods
6
6
  # Generates a method whose return value is memoized
7
7
  # after the first call.
8
8
  #
9
9
  # @example
10
10
  #
11
- # describe Thing do
12
- # let(:thing) { Thing.new }
11
+ # describe Thing do
12
+ # let(:thing) { Thing.new }
13
13
  #
14
- # it "does something" do
15
- # # first invocation, executes block, memoizes and returns result
16
- # thing.do_something
14
+ # it "does something" do
15
+ # # first invocation, executes block, memoizes and returns result
16
+ # thing.do_something
17
17
  #
18
- # # second invocation, returns the memoized value
19
- # thing.should be_something
20
- # end
21
- # end
18
+ # # second invocation, returns the memoized value
19
+ # thing.should be_something
20
+ # end
21
+ # end
22
22
  def let(name, &block)
23
23
  define_method(name) do
24
24
  __memoized.fetch(name) {|k| __memoized[k] = instance_eval(&block) }
@@ -32,69 +32,70 @@ module RSpec
32
32
  #
33
33
  # @example
34
34
  #
35
- # class Thing
36
- # def self.count
37
- # @count ||= 0
38
- # end
39
- #
40
- # def self.count=(val)
41
- # @count += val
42
- # end
43
- #
44
- # def self.reset_count
45
- # @count = 0
46
- # end
47
- #
48
- # def initialize
49
- # self.class.count += 1
50
- # end
51
- # end
52
- #
53
- # describe Thing do
54
- # after(:each) { Thing.reset_count }
55
- #
56
- # context "using let" do
57
- # let(:thing) { Thing.new }
58
- #
59
- # it "is not invoked implicitly" do
60
- # Thing.count.should eq(0)
61
- # end
62
- #
63
- # it "can be invoked explicitly" do
64
- # thing
65
- # Thing.count.should eq(1)
66
- # end
67
- # end
68
- #
69
- # context "using let!" do
70
- # let!(:thing) { Thing.new }
71
- #
72
- # it "is invoked implicitly" do
73
- # Thing.count.should eq(1)
74
- # end
75
- #
76
- # it "returns memoized version on first invocation" do
77
- # thing
78
- # Thing.count.should eq(1)
79
- # end
80
- # end
81
- # end
35
+ # class Thing
36
+ # def self.count
37
+ # @count ||= 0
38
+ # end
39
+ #
40
+ # def self.count=(val)
41
+ # @count += val
42
+ # end
43
+ #
44
+ # def self.reset_count
45
+ # @count = 0
46
+ # end
47
+ #
48
+ # def initialize
49
+ # self.class.count += 1
50
+ # end
51
+ # end
52
+ #
53
+ # describe Thing do
54
+ # after(:each) { Thing.reset_count }
55
+ #
56
+ # context "using let" do
57
+ # let(:thing) { Thing.new }
58
+ #
59
+ # it "is not invoked implicitly" do
60
+ # Thing.count.should eq(0)
61
+ # end
62
+ #
63
+ # it "can be invoked explicitly" do
64
+ # thing
65
+ # Thing.count.should eq(1)
66
+ # end
67
+ # end
68
+ #
69
+ # context "using let!" do
70
+ # let!(:thing) { Thing.new }
71
+ #
72
+ # it "is invoked implicitly" do
73
+ # Thing.count.should eq(1)
74
+ # end
75
+ #
76
+ # it "returns memoized version on first invocation" do
77
+ # thing
78
+ # Thing.count.should eq(1)
79
+ # end
80
+ # end
81
+ # end
82
82
  def let!(name, &block)
83
83
  let(name, &block)
84
84
  before { __send__(name) }
85
85
  end
86
86
  end
87
87
 
88
- module InstanceMethods
89
- private
88
+ # @private
89
+ module ExampleMethods
90
+ # @private
90
91
  def __memoized
91
92
  @__memoized ||= {}
92
93
  end
93
94
  end
94
95
 
95
96
  def self.included(mod)
96
- mod.extend ClassMethods
97
- mod.__send__ :include, InstanceMethods
97
+ mod.extend ExampleGroupMethods
98
+ mod.__send__ :include, ExampleMethods
98
99
  end
99
100
 
100
101
  end
@@ -1,13 +1,35 @@
1
1
  module RSpec
2
2
  module Core
3
- # Each ExampleGroup class and Example instance ...
3
+ # Each ExampleGroup class and Example instance owns an instance of
4
+ # Metadata, which is Hash extended to support lazy evaluation of values
5
+ # associated with keys that may or may not be used by any example or group.
6
+ #
7
+ # In addition to metadata that is used internally, this also stores
8
+ # user-supplied metadata, e.g.
9
+ #
10
+ # describe Something, :type => :ui do
11
+ # it "does something", :slow => true do
12
+ # # ...
13
+ # end
14
+ # end
15
+ #
16
+ # `:type => :ui` is stored in the Metadata owned by the example group, and
17
+ # `:slow => true` is stored in the Metadata owned by the example. These can
18
+ # then be used to select which examples are run using the `--tag` option on
19
+ # the command line, or several methods on `Configuration` used to filter a
20
+ # run (e.g. `filter_run_including`, `filter_run_excluding`, etc).
4
21
  #
5
22
  # @see Example#metadata
6
23
  # @see ExampleGroup.metadata
24
+ # @see FilterManager
25
+ # @see Configuration#filter_run_including
26
+ # @see Configuration#filter_run_excluding
7
27
  class Metadata < Hash
8
28
 
29
+ # @private
9
30
  module MetadataHash
10
31
 
32
+ # @private
11
33
  # Supports lazy evaluation of some values. Extended by
12
34
  # ExampleMetadataHash and GroupMetadataHash, which get mixed in to
13
35
  # Metadata for ExampleGroups and Examples (respectively).
@@ -23,10 +45,13 @@ module RSpec
23
45
  super
24
46
  when :execution_result
25
47
  store(:execution_result, {})
26
- when :describes
27
- store(:describes, described_class_for(self))
48
+ when :describes, :described_class
49
+ klass = described_class
50
+ store(:described_class, klass)
51
+ # TODO (2011-11-07 DC) deprecate :describes as a key
52
+ store(:describes, klass)
28
53
  when :full_description
29
- store(:full_description, full_description_for(self))
54
+ store(:full_description, full_description)
30
55
  when :description
31
56
  store(:description, build_description_from(*self[:description_args]))
32
57
  else
@@ -34,7 +59,7 @@ module RSpec
34
59
  end
35
60
  end
36
61
 
37
- private
62
+ private
38
63
 
39
64
  def location
40
65
  "#{self[:file_path]}:#{self[:line_number]}"
@@ -49,16 +74,8 @@ module RSpec
49
74
  self[:caller].detect {|l| l !~ /\/lib\/rspec\/core/}
50
75
  end
51
76
 
52
- def described_class_for(m)
53
- m[:example_group][:describes]
54
- end
55
-
56
- def full_description_for(m)
57
- build_description_from(m[:example_group][:full_description], *m[:description_args])
58
- end
59
-
60
77
  def build_description_from(*parts)
61
- parts.map {|p| p.to_s}.reduce do |desc, p|
78
+ parts.map {|p| p.to_s}.inject do |desc, p|
62
79
  p =~ /^(#|::|\.)/ ? "#{desc}#{p}" : "#{desc} #{p}"
63
80
  end || ""
64
81
  end
@@ -68,6 +85,14 @@ module RSpec
68
85
  # lazy evaluation of some values.
69
86
  module ExampleMetadataHash
70
87
  include MetadataHash
88
+
89
+ def described_class
90
+ self[:example_group].described_class
91
+ end
92
+
93
+ def full_description
94
+ build_description_from(self[:example_group][:full_description], *self[:description_args])
95
+ end
71
96
  end
72
97
 
73
98
  # Mixed in to Metadata for an ExampleGroup (extends MetadataHash) to
@@ -75,14 +100,13 @@ module RSpec
75
100
  module GroupMetadataHash
76
101
  include MetadataHash
77
102
 
78
- private
79
-
80
- def described_class_for(*)
81
- ancestors.each do |g|
82
- return g[:describes] if g.has_key?(:describes)
103
+ def described_class
104
+ container_stack.each do |g|
105
+ return g[:describes] if g.has_key?(:describes)
106
+ return g[:described_class] if g.has_key?(:described_class)
83
107
  end
84
108
 
85
- ancestors.reverse.each do |g|
109
+ container_stack.reverse.each do |g|
86
110
  candidate = g[:description_args].first
87
111
  return candidate unless String === candidate || Symbol === candidate
88
112
  end
@@ -90,30 +114,26 @@ module RSpec
90
114
  nil
91
115
  end
92
116
 
93
- def full_description_for(*)
94
- build_description_from(*ancestors.reverse.map do |a|
95
- a[:description_args]
96
- end.flatten)
117
+ def full_description
118
+ build_description_from(*container_stack.reverse.map {|a| a[:description_args]}.flatten)
97
119
  end
98
120
 
99
- private
100
-
101
- def ancestors
102
- @ancestors ||= begin
103
- groups = [group = self]
104
- while group.has_key?(:example_group)
105
- groups << group[:example_group]
106
- group = group[:example_group]
107
- end
108
- groups
109
- end
121
+ def container_stack
122
+ @container_stack ||= begin
123
+ groups = [group = self]
124
+ while group.has_key?(:example_group)
125
+ groups << group[:example_group]
126
+ group = group[:example_group]
127
+ end
128
+ groups
129
+ end
110
130
  end
111
131
  end
112
132
 
113
133
  def initialize(parent_group_metadata=nil)
114
134
  if parent_group_metadata
115
135
  update(parent_group_metadata)
116
- store(:example_group, {:example_group => parent_group_metadata[:example_group]}.extend(GroupMetadataHash))
136
+ store(:example_group, {:example_group => parent_group_metadata[:example_group].extend(GroupMetadataHash)}.extend(GroupMetadataHash))
117
137
  else
118
138
  store(:example_group, {}.extend(GroupMetadataHash))
119
139
  end
@@ -121,7 +141,7 @@ module RSpec
121
141
  yield self if block_given?
122
142
  end
123
143
 
124
- # @api private
144
+ # @private
125
145
  def process(*args)
126
146
  user_metadata = args.last.is_a?(Hash) ? args.pop : {}
127
147
  ensure_valid_keys(user_metadata)
@@ -132,36 +152,29 @@ module RSpec
132
152
  update(user_metadata)
133
153
  end
134
154
 
135
- # @api private
155
+ # @private
136
156
  def for_example(description, user_metadata)
137
157
  dup.extend(ExampleMetadataHash).configure_for_example(description, user_metadata)
138
158
  end
139
159
 
140
- # @api private
160
+ # @private
141
161
  def any_apply?(filters)
142
162
  filters.any? {|k,v| filter_applies?(k,v)}
143
163
  end
144
164
 
145
- # @api private
165
+ # @private
146
166
  def all_apply?(filters)
147
167
  filters.all? {|k,v| filter_applies?(k,v)}
148
168
  end
149
169
 
150
- # @api private
170
+ # @private
151
171
  def filter_applies?(key, value, metadata=self)
172
+ return metadata.filter_applies_to_any_value?(key, value) if Array === metadata[key]
173
+ return metadata.line_number_filter_applies?(value) if key == :line_numbers
174
+ return metadata.location_filter_applies?(value) if key == :locations
175
+ return metadata.filters_apply?(key, value) if Hash === value
176
+
152
177
  case value
153
- when Hash
154
- if key == :locations
155
- file_path = (self[:example_group] || {})[:file_path]
156
- expanded_path = file_path && File.expand_path( file_path )
157
- if expanded_path && line_numbers = value[expanded_path]
158
- filter_applies?(:line_numbers, line_numbers)
159
- else
160
- true
161
- end
162
- else
163
- value.all? { |k, v| filter_applies?(k, v, metadata[key]) }
164
- end
165
178
  when Regexp
166
179
  metadata[key] =~ value
167
180
  when Proc
@@ -176,21 +189,35 @@ module RSpec
176
189
  else
177
190
  value.call(metadata[key]) rescue false
178
191
  end
179
- when String
180
- metadata[key].to_s == value.to_s
181
- when Enumerable
182
- if key == :line_numbers
183
- preceding_declaration_lines = value.map{|v| world.preceding_declaration_line(v)}
184
- !(relevant_line_numbers(metadata) & preceding_declaration_lines).empty?
185
- else
186
- metadata[key] == value
187
- end
188
192
  else
189
193
  metadata[key].to_s == value.to_s
190
194
  end
191
195
  end
192
196
 
193
- protected
197
+ # @private
198
+ def filters_apply?(key, value)
199
+ value.all? {|k, v| filter_applies?(k, v, self[key])}
200
+ end
201
+
202
+ # @private
203
+ def filter_applies_to_any_value?(key, value)
204
+ self[key].any? {|v| filter_applies?(key, v, {key => value})}
205
+ end
206
+
207
+ # @private
208
+ def location_filter_applies?(locations)
209
+ # it ignores location filters for other files
210
+ line_number = example_group_declaration_line(locations)
211
+ line_number ? line_number_filter_applies?(line_number) : true
212
+ end
213
+
214
+ # @private
215
+ def line_number_filter_applies?(line_numbers)
216
+ preceding_declaration_lines = line_numbers.map {|n| RSpec.world.preceding_declaration_line(n)}
217
+ !(relevant_line_numbers & preceding_declaration_lines).empty?
218
+ end
219
+
220
+ protected
194
221
 
195
222
  def configure_for_example(description, user_metadata)
196
223
  store(:description_args, [description])
@@ -198,7 +225,7 @@ module RSpec
198
225
  update(user_metadata)
199
226
  end
200
227
 
201
- private
228
+ private
202
229
 
203
230
  RESERVED_KEYS = [
204
231
  :description,
@@ -212,37 +239,33 @@ module RSpec
212
239
 
213
240
  def ensure_valid_keys(user_metadata)
214
241
  RESERVED_KEYS.each do |key|
215
- if user_metadata.keys.include?(key)
242
+ if user_metadata.has_key?(key)
216
243
  raise <<-EOM
217
- #{"*"*50}
244
+ #{"*"*50}
218
245
  :#{key} is not allowed
219
246
 
220
247
  RSpec reserves some hash keys for its own internal use,
221
248
  including :#{key}, which is used on:
222
249
 
223
- #{caller(0)[4]}.
250
+ #{caller(0)[4]}.
224
251
 
225
252
  Here are all of RSpec's reserved hash keys:
226
253
 
227
- #{RESERVED_KEYS.join("\n ")}
228
- #{"*"*50}
229
- EOM
230
- raise ":#{key} is not allowed"
254
+ #{RESERVED_KEYS.join("\n ")}
255
+ #{"*"*50}
256
+ EOM
231
257
  end
232
258
  end
233
259
  end
234
260
 
235
- def world
236
- RSpec.world
261
+ def example_group_declaration_line(locations)
262
+ locations[File.expand_path(self[:example_group][:file_path])] if self[:example_group]
237
263
  end
238
264
 
239
- def relevant_line_numbers(metadata)
240
- line_numbers = [metadata[:line_number]]
241
- if metadata[:example_group]
242
- line_numbers + relevant_line_numbers(metadata[:example_group])
243
- else
244
- line_numbers
245
- end
265
+ # TODO - make this a method on metadata - the problem is
266
+ # metadata[:example_group] is not always a kind of GroupMetadataHash.
267
+ def relevant_line_numbers(metadata=self)
268
+ [metadata[:line_number]] + (metadata[:example_group] ? relevant_line_numbers(metadata[:example_group]) : [])
246
269
  end
247
270
 
248
271
  end