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

Commit 11928e0

Browse files
authored
Merge pull request #2862 from rspec/remove-deprecated-results-hash-compatibility
Remove deprecated Hash-like behavior from example execution result
2 parents 0ea90bb + 6b64925 commit 11928e0

File tree

6 files changed

+17
-254
lines changed

6 files changed

+17
-254
lines changed

Changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Breaking Changes:
1515
an unsupported value. (Phil Pirozhkov, #2849)
1616
* Remove deprecated access to an example group's metadata through the example.
1717
(Phil Pirozhkov, #2851)
18+
* Remove deprecated Hash-like behavior from example
19+
execution result. (Phil Pirozhkov, #2862)
1820

1921
Enhancements:
2022

lib/rspec/core/example.rb

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -551,10 +551,7 @@ def location_description
551551
end
552552

553553
# Represents the result of executing an example.
554-
# Behaves like a hash for backwards compatibility.
555554
class ExecutionResult
556-
include HashImitatable
557-
558555
# @return [Symbol] `:passed`, `:failed` or `:pending`.
559556
attr_accessor :status
560557

@@ -616,32 +613,6 @@ def calculate_run_time(finished_at)
616613
self.finished_at = finished_at
617614
self.run_time = (finished_at - started_at).to_f
618615
end
619-
620-
# For backwards compatibility we present `status` as a string
621-
# when presenting the legacy hash interface.
622-
def hash_for_delegation
623-
super.tap do |hash|
624-
hash[:status] &&= status.to_s
625-
end
626-
end
627-
628-
def set_value(name, value)
629-
value &&= value.to_sym if name == :status
630-
super(name, value)
631-
end
632-
633-
def get_value(name)
634-
if name == :status
635-
status.to_s if status
636-
else
637-
super
638-
end
639-
end
640-
641-
def issue_deprecation(_method_name, *_args)
642-
RSpec.deprecate("Treating `metadata[:execution_result]` as a hash",
643-
:replacement => "the attributes methods to access the data")
644-
end
645616
end
646617
end
647618

lib/rspec/core/metadata.rb

Lines changed: 0 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -290,107 +290,5 @@ def full_description
290290
:shared_group_inclusion_backtrace
291291
]
292292
end
293-
294-
# Mixin that makes the including class imitate a hash for backwards
295-
# compatibility. The including class should use `attr_accessor` to
296-
# declare attributes.
297-
# @private
298-
module HashImitatable
299-
def self.included(klass)
300-
klass.extend ClassMethods
301-
end
302-
303-
def to_h
304-
hash = extra_hash_attributes.dup
305-
306-
self.class.hash_attribute_names.each do |name|
307-
hash[name] = __send__(name)
308-
end
309-
310-
hash
311-
end
312-
313-
(Hash.public_instance_methods - Object.public_instance_methods).each do |method_name|
314-
next if [:[], :[]=, :to_h].include?(method_name.to_sym)
315-
316-
define_method(method_name) do |*args, &block|
317-
issue_deprecation(method_name, *args)
318-
319-
hash = hash_for_delegation
320-
self.class.hash_attribute_names.each do |name|
321-
hash.delete(name) unless instance_variable_defined?(:"@#{name}")
322-
end
323-
324-
hash.__send__(method_name, *args, &block).tap do
325-
# apply mutations back to the object
326-
hash.each do |name, value|
327-
if directly_supports_attribute?(name)
328-
set_value(name, value)
329-
else
330-
extra_hash_attributes[name] = value
331-
end
332-
end
333-
end
334-
end
335-
end
336-
337-
def [](key)
338-
issue_deprecation(:[], key)
339-
340-
if directly_supports_attribute?(key)
341-
get_value(key)
342-
else
343-
extra_hash_attributes[key]
344-
end
345-
end
346-
347-
def []=(key, value)
348-
issue_deprecation(:[]=, key, value)
349-
350-
if directly_supports_attribute?(key)
351-
set_value(key, value)
352-
else
353-
extra_hash_attributes[key] = value
354-
end
355-
end
356-
357-
private
358-
359-
def extra_hash_attributes
360-
@extra_hash_attributes ||= {}
361-
end
362-
363-
def directly_supports_attribute?(name)
364-
self.class.hash_attribute_names.include?(name)
365-
end
366-
367-
def get_value(name)
368-
__send__(name)
369-
end
370-
371-
def set_value(name, value)
372-
__send__(:"#{name}=", value)
373-
end
374-
375-
def hash_for_delegation
376-
to_h
377-
end
378-
379-
def issue_deprecation(_method_name, *_args)
380-
# no-op by default: subclasses can override
381-
end
382-
383-
# @private
384-
module ClassMethods
385-
def hash_attribute_names
386-
@hash_attribute_names ||= []
387-
end
388-
389-
def attr_accessor(*names)
390-
hash_attribute_names.concat(names)
391-
super
392-
end
393-
end
394-
end
395293
end
396294
end

spec/rspec/core/example_execution_result_spec.rb

Lines changed: 7 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,8 @@ module RSpec
22
module Core
33
class Example
44
RSpec.describe ExecutionResult do
5-
it "supports ruby 2.1's `to_h` protocol" do
6-
er = ExecutionResult.new
7-
er.run_time = 17
8-
er.pending_message = "just because"
9-
10-
expect(er.to_h).to include(
11-
:run_time => 17,
12-
:pending_message => "just because"
13-
)
14-
end
15-
16-
it 'includes all defined attributes in the `to_h` hash even if not set' do
17-
expect(ExecutionResult.new.to_h).to include(
5+
it 'has `status` and `pending_message` attributes' do
6+
expect(ExecutionResult.new).to have_attributes(
187
:status => nil,
198
:pending_message => nil
209
)
@@ -25,111 +14,12 @@ class Example
2514
expect { er.pending_fixed = true }.to change(er, :pending_fixed?).from(false).to(true)
2615
end
2716

28-
describe "backwards compatibility" do
29-
it 'supports indexed access like a hash' do
30-
er = ExecutionResult.new
31-
er.started_at = (started_at = ::Time.utc(2014, 3, 1, 12, 30))
32-
expect_deprecation_with_call_site(__FILE__, __LINE__ + 1, /execution_result/)
33-
expect(er[:started_at]).to eq(started_at)
34-
end
35-
36-
it 'supports indexed updates like a hash' do
37-
er = ExecutionResult.new
38-
expect_deprecation_with_call_site(__FILE__, __LINE__ + 1, /execution_result/)
39-
er[:started_at] = (started_at = ::Time.utc(2014, 3, 1, 12, 30))
40-
expect(er.started_at).to eq(started_at)
41-
end
42-
43-
it 'can get and set user defined attributes like with a hash' do
44-
er = ExecutionResult.new
45-
allow_deprecation
46-
expect { er[:foo] = 3 }.to change { er[:foo] }.from(nil).to(3)
47-
expect(er.to_h).to include(:foo => 3)
48-
end
49-
50-
it 'supports `update` like a hash' do
51-
er = ExecutionResult.new
52-
expect_deprecation_with_call_site(__FILE__, __LINE__ + 1, /execution_result/)
53-
er.update(:pending_message => "some message", :exception => ArgumentError.new)
54-
expect(er.pending_message).to eq("some message")
55-
expect(er.exception).to be_a(ArgumentError)
56-
end
57-
58-
it 'can set undefined attribute keys through any hash mutation method' do
59-
allow_deprecation
60-
er = ExecutionResult.new
61-
er.update(:pending_message => "msg", :foo => 3)
62-
expect(er.to_h).to include(:pending_message => "msg", :foo => 3)
63-
end
64-
65-
it 'supports `merge` like a hash' do
66-
er = ExecutionResult.new
67-
er.exception = ArgumentError.new
68-
er.pending_message = "just because"
69-
70-
expect_deprecation_with_call_site(__FILE__, __LINE__ + 1, /execution_result/)
71-
merged = er.merge(:exception => NotImplementedError.new, :foo => 3)
72-
73-
expect(merged).to include(
74-
:exception => an_instance_of(NotImplementedError),
75-
:pending_message => "just because",
76-
:foo => 3
77-
)
78-
79-
expect(er.exception).to be_an(ArgumentError)
80-
end
81-
82-
it 'supports blocks for hash methods that support one' do
83-
er = ExecutionResult.new
84-
expect_deprecation_with_call_site(__FILE__, __LINE__ + 1, /execution_result/)
85-
expect(er.fetch(:foo) { 3 }).to eq(3)
86-
end
87-
88-
specify '#fetch treats unset properties the same as a hash does' do
89-
allow_deprecation
90-
er = ExecutionResult.new
91-
expect { er.fetch(:pending_message) }.to raise_error(KeyError)
92-
er.pending_message = "some msg"
93-
expect(er.fetch(:pending_message)).to eq("some msg")
94-
end
95-
96-
describe "status" do
97-
it 'returns a string when accessed like a hash' do
98-
er = ExecutionResult.new
99-
expect(er[:status]).to eq(nil)
100-
er.status = :failed
101-
expect(er[:status]).to eq("failed")
102-
end
103-
104-
it "sets the status to a symbol when assigned as a string via the hash interface" do
105-
er = ExecutionResult.new
106-
er[:status] = "failed"
107-
expect(er.status).to eq(:failed)
108-
er[:status] = nil
109-
expect(er.status).to eq(nil)
110-
end
111-
112-
it "is presented as a string when included in returned hashes" do
113-
er = ExecutionResult.new
114-
er.status = :failed
115-
expect(er.merge(:foo => 3)).to include(:status => "failed", :foo => 3)
116-
117-
er.status = nil
118-
expect(er.merge(:foo => 3)).to include(:status => nil, :foo => 3)
119-
end
120-
121-
it "is updated to a symbol when updated as a string via `update`" do
122-
er = ExecutionResult.new
123-
er.update(:status => "passed")
124-
expect(er.status).to eq(:passed)
125-
end
17+
it 'does not support `to_h`' do
18+
expect(ExecutionResult.new.respond_to?(:to_h)).to be false
19+
end
12620

127-
it 'is presented as a symbol in `to_h`' do
128-
er = ExecutionResult.new
129-
er.status = :failed
130-
expect(er.to_h).to include(:status => :failed)
131-
end
132-
end
21+
it 'does not behave like a hash' do
22+
expect(ExecutionResult.new.respond_to?(:[])).to be false
13323
end
13424
end
13525
end

spec/rspec/core/example_group_spec.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,8 @@ def extract_execution_results(group)
11381138
end
11391139
group.run
11401140

1141-
expect(extract_execution_results(group).map(&:to_h)).to match([
1142-
a_hash_including(
1141+
expect(extract_execution_results(group)).to match([
1142+
have_attributes(
11431143
:status => :pending,
11441144
:pending_message => "Temporarily skipped with #{method_name}"
11451145
)
@@ -1190,12 +1190,12 @@ def extract_execution_results(group)
11901190
end
11911191
group.run
11921192

1193-
expect(extract_execution_results(group).map(&:to_h)).to match([
1194-
a_hash_including(
1193+
expect(extract_execution_results(group)).to match([
1194+
have_attributes(
11951195
:status => :failed,
11961196
:pending_message => "No reason given"
11971197
),
1198-
a_hash_including(
1198+
have_attributes(
11991199
:status => :pending,
12001200
:pending_message => "unimplemented"
12011201
)

spec/rspec/core/metadata_spec.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ def metadata_for(*args)
102102
end
103103

104104
it "creates an empty execution result" do
105-
expect(example_metadata[:execution_result].to_h.reject { |_, v| v.nil? } ).to eq({})
105+
expect(example_metadata[:execution_result])
106+
.to be_an(Example::ExecutionResult)
107+
.and have_attributes(:status => nil)
106108
end
107109

108110
it "extracts file path from caller" do

0 commit comments

Comments
 (0)