Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit fac163d

Browse files
committed
Merge pull request #2035 from avantcredit/simple_key_filtering
Add ability to filter hooks via simple keys.
2 parents 561cce6 + f19728c commit fac163d

File tree

3 files changed

+203
-6
lines changed

3 files changed

+203
-6
lines changed

features/hooks/filtering.feature

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,186 @@ Feature: filters
244244
.after context
245245
"""
246246

247+
Scenario: Filtering hooks using symbols
248+
Given a file named "filter_example_hooks_with_symbol_spec.rb" with:
249+
"""ruby
250+
RSpec.configure do |config|
251+
config.before(:example, :foo) do
252+
invoked_hooks << :before_example_foo_bar
253+
end
254+
end
255+
256+
RSpec.describe "a filtered before :example hook" do
257+
let(:invoked_hooks) { [] }
258+
259+
describe "group without a matching metadata key" do
260+
it "does not run the hook" do
261+
expect(invoked_hooks).to be_empty
262+
end
263+
264+
it "does not run the hook for an example with metadata hash containing the key with a falsey value", :foo => nil do
265+
expect(invoked_hooks).to be_empty
266+
end
267+
268+
it "runs the hook for an example with metadata hash containing the key with a truthy value", :foo => :bar do
269+
expect(invoked_hooks).to eq([:before_example_foo_bar])
270+
end
271+
272+
it "runs the hook for an example with only the key defined", :foo do
273+
expect(invoked_hooks).to eq([:before_example_foo_bar])
274+
end
275+
end
276+
277+
describe "group with matching metadata key", :foo do
278+
it "runs the hook" do
279+
expect(invoked_hooks).to eq([:before_example_foo_bar])
280+
end
281+
end
282+
end
283+
"""
284+
When I run `rspec filter_example_hooks_with_symbol_spec.rb`
285+
Then the examples should all pass
286+
287+
Scenario: Filtering hooks using a hash
288+
Given a file named "filter_example_hooks_with_hash_spec.rb" with:
289+
"""ruby
290+
RSpec.configure do |config|
291+
config.before(:example, :foo => { :bar => :baz, :slow => true }) do
292+
invoked_hooks << :before_example_foo_bar
293+
end
294+
end
295+
296+
RSpec.describe "a filtered before :example hook" do
297+
let(:invoked_hooks) { [] }
298+
299+
describe "group without matching metadata" do
300+
it "does not run the hook" do
301+
expect(invoked_hooks).to be_empty
302+
end
303+
304+
it "does not run the hook for an example if only part of the filter matches", :foo => { :bar => :baz } do
305+
expect(invoked_hooks).to be_empty
306+
end
307+
308+
it "runs the hook for an example if the metadata contains all key value pairs from the filter", :foo => { :bar => :baz, :slow => true, :extra => :pair } do
309+
expect(invoked_hooks).to eq([:before_example_foo_bar])
310+
end
311+
end
312+
313+
describe "group with matching metadata", :foo => { :bar => :baz, :slow => true } do
314+
it "runs the hook" do
315+
expect(invoked_hooks).to eq([:before_example_foo_bar])
316+
end
317+
end
318+
end
319+
"""
320+
When I run `rspec filter_example_hooks_with_hash_spec.rb`
321+
Then the examples should all pass
322+
323+
Scenario: Filtering hooks using a Proc
324+
Given a file named "filter_example_hooks_with_proc_spec.rb" with:
325+
"""ruby
326+
RSpec.configure do |config|
327+
config.before(:example, :foo => Proc.new { |value| value.is_a?(String) } ) do
328+
invoked_hooks << :before_example_foo_bar
329+
end
330+
end
331+
332+
RSpec.describe "a filtered before :example hook" do
333+
let(:invoked_hooks) { [] }
334+
335+
describe "group without matching metadata" do
336+
it "does not run the hook" do
337+
expect(invoked_hooks).to be_empty
338+
end
339+
340+
it "does not run the hook if the proc returns false", :foo => :bar do
341+
expect(invoked_hooks).to be_empty
342+
end
343+
344+
it "runs the hook if the proc returns true", :foo => 'bar' do
345+
expect(invoked_hooks).to eq([:before_example_foo_bar])
346+
end
347+
end
348+
349+
describe "group with matching metadata", :foo => 'bar' do
350+
it "runs the hook" do
351+
expect(invoked_hooks).to eq([:before_example_foo_bar])
352+
end
353+
end
354+
end
355+
"""
356+
When I run `rspec filter_example_hooks_with_proc_spec.rb`
357+
Then the examples should all pass
358+
359+
Scenario: Filtering hooks using a regular expression
360+
Given a file named "filter_example_hooks_with_regexp_spec.rb" with:
361+
"""ruby
362+
RSpec.configure do |config|
363+
config.before(:example, :foo => /bar/ ) do
364+
invoked_hooks << :before_example_foo_bar
365+
end
366+
end
367+
368+
RSpec.describe "a filtered before :example hook" do
369+
let(:invoked_hooks) { [] }
370+
371+
describe "group without matching metadata" do
372+
it "does not run the hook" do
373+
expect(invoked_hooks).to be_empty
374+
end
375+
376+
it "does not run the hook if the value does not match", :foo => 'baz' do
377+
expect(invoked_hooks).to be_empty
378+
end
379+
380+
it "runs the hook if the value matches", :foo => 'bar' do
381+
expect(invoked_hooks).to eq([:before_example_foo_bar])
382+
end
383+
end
384+
385+
describe "group with matching metadata", :foo => 'bar' do
386+
it "runs the hook" do
387+
expect(invoked_hooks).to eq([:before_example_foo_bar])
388+
end
389+
end
390+
end
391+
"""
392+
When I run `rspec filter_example_hooks_with_regexp_spec.rb`
393+
Then the examples should all pass
394+
395+
Scenario: Filtering hooks using string comparison
396+
Given a file named "filter_example_hooks_with_strcmp_spec.rb" with:
397+
"""ruby
398+
RSpec.configure do |config|
399+
config.before(:example, :foo => :bar ) do
400+
invoked_hooks << :before_example_foo_bar
401+
end
402+
end
403+
404+
RSpec.describe "a filtered before :example hook" do
405+
let(:invoked_hooks) { [] }
406+
407+
describe "group without matching metadata" do
408+
it "does not run the hook" do
409+
expect(invoked_hooks).to be_empty
410+
end
411+
412+
it "does not run the hook if the coerced values do not match", :foo => 'baz' do
413+
expect(invoked_hooks).to be_empty
414+
end
415+
416+
it "does not run the hook if the coerced values match", :foo => 'bar' do
417+
expect(invoked_hooks).to eq([:before_example_foo_bar])
418+
end
419+
end
420+
421+
describe "group with matching metadata", :foo => 'bar' do
422+
it "runs the hook" do
423+
expect(invoked_hooks).to eq([:before_example_foo_bar])
424+
end
425+
end
426+
end
427+
"""
428+
When I run `rspec filter_example_hooks_with_strcmp_spec.rb`
429+
Then the examples should all pass

lib/rspec/core/metadata_filter.rb

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,19 @@ def apply?(predicate, filters, metadata)
1515
# @private
1616
def filter_applies?(key, value, metadata)
1717
silence_metadata_example_group_deprecations do
18-
return filter_applies_to_any_value?(key, value, metadata) if Array === metadata[key] && !(Proc === value)
1918
return location_filter_applies?(value, metadata) if key == :locations
2019
return id_filter_applies?(value, metadata) if key == :ids
2120
return filters_apply?(key, value, metadata) if Hash === value
2221

2322
return false unless metadata.key?(key)
23+
return true if TrueClass === value && !!metadata[key]
24+
return filter_applies_to_any_value?(key, value, metadata) if Array === metadata[key] && !(Proc === value)
2425

2526
case value
2627
when Regexp
2728
metadata[key] =~ value
2829
when Proc
29-
case value.arity
30-
when 0 then value.call
31-
when 2 then value.call(metadata[key], metadata)
32-
else value.call(metadata[key])
33-
end
30+
proc_filter_applies?(key, value, metadata)
3431
else
3532
metadata[key].to_s == value.to_s
3633
end
@@ -61,6 +58,14 @@ def line_number_filter_applies?(line_numbers, metadata)
6158
!(relevant_line_numbers(metadata) & preceding_declaration_lines).empty?
6259
end
6360

61+
def proc_filter_applies?(key, proc, metadata)
62+
case proc.arity
63+
when 0 then proc.call
64+
when 2 then proc.call(metadata[key], metadata)
65+
else proc.call(metadata[key])
66+
end
67+
end
68+
6469
def relevant_line_numbers(metadata)
6570
Metadata.ascend(metadata).map { |meta| meta[:line_number] }
6671
end

spec/rspec/core/metadata_filter_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ def filter_applies?(key, value, metadata)
157157
metadata = { :foo => "words" }
158158
expect(filter_applies?(:foo, { :bar => /word/ }, metadata)).to be_falsey
159159
end
160+
161+
it 'matches when a metadata key is specified without a value and exists in the metadata hash' do
162+
metadata = { :foo => "words" }
163+
expect(filter_applies?(:foo, true, metadata)).to be_truthy
164+
end
160165
end
161166

162167
context "with an Array" do
@@ -199,6 +204,10 @@ def filter_applies?(key, value, metadata)
199204
it "does not match a proc that evaluates to false" do
200205
expect(filter_applies?(:tag, lambda { |values| values.include? 'nothing' }, metadata_with_array)).to be_falsey
201206
end
207+
208+
it 'matches when a metadata key is specified without a value and exists in the metadata hash' do
209+
expect(filter_applies?(:tag, true, metadata_with_array)).to be_truthy
210+
end
202211
end
203212
end
204213
end

0 commit comments

Comments
 (0)