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

Commit 46fceb6

Browse files
committed
Add Support.class_of for extracting class of any object
1 parent 601bc13 commit 46fceb6

File tree

5 files changed

+82
-4
lines changed

5 files changed

+82
-4
lines changed

Changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ Enhancements:
55

66
* Improve compatibility with `--enable-frozen-string-literal` option
77
on Ruby 2.3+. (Pat Allan, #320)
8+
* Add `Support.class_of` for extracting class of any object.
9+
(Yuji Nakayama, #325)
810

911
Bug Fixes:
1012

lib/rspec/support.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ def self.method_handle_for(object, method_name)
7373
end
7474
end
7575

76+
# @api private
77+
#
78+
# Used internally to get a class of a given object, even if it does not respond to #class.
79+
def self.class_of(object)
80+
object.class
81+
rescue NoMethodError
82+
singleton_class = class << object; self; end
83+
singleton_class.ancestors.find { |ancestor| !ancestor.equal?(singleton_class) }
84+
end
85+
7686
# A single thread local variable so we don't excessively pollute that namespace.
7787
def self.thread_local_data
7888
Thread.current[:__rspec] ||= {}

lib/rspec/support/object_formatter.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,7 @@ def inspect
199199
end
200200

201201
def klass
202-
singleton_class = class << object; self; end
203-
singleton_class.ancestors.find { |ancestor| !ancestor.equal?(singleton_class) }
202+
Support.class_of(object)
204203
end
205204

206205
# http://stackoverflow.com/a/2818916

spec/rspec/support/object_formatter_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def with_delegate_loaded
178178
end
179179
end
180180

181-
context 'with an object that does not respond to #inspect such as BasicObject' do
181+
context 'with an object that does not respond to #class and #inspect such as BasicObject' do
182182
subject(:output) do
183183
ObjectFormatter.format(input)
184184
end
@@ -197,7 +197,7 @@ def self.to_s
197197
'BasicObject'
198198
end
199199

200-
undef inspect, respond_to?
200+
undef class, inspect, respond_to?
201201
end
202202
end
203203

spec/rspec/support_spec.rb

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,73 @@ def method_missing(name, *args, &block)
118118
end
119119
end
120120

121+
describe '.class_of' do
122+
subject(:klass) do
123+
Support.class_of(object)
124+
end
125+
126+
context 'with a String instance' do
127+
let(:object) do
128+
'foo'
129+
end
130+
131+
it { should equal(String) }
132+
end
133+
134+
context 'with a BasicObject instance' do
135+
let(:object) do
136+
basic_object_class.new
137+
end
138+
139+
let(:basic_object_class) do
140+
defined?(BasicObject) ? BasicObject : fake_basic_object_class
141+
end
142+
143+
let(:fake_basic_object_class) do
144+
Class.new do
145+
def self.to_s
146+
'BasicObject'
147+
end
148+
149+
undef class, inspect, respond_to?
150+
end
151+
end
152+
153+
it { should equal(basic_object_class) }
154+
end
155+
156+
context 'with nil' do
157+
let(:object) do
158+
nil
159+
end
160+
161+
it { should equal(NilClass) }
162+
end
163+
164+
context 'with an object having a singleton class' do
165+
let(:object) do
166+
object = 'foo'
167+
168+
def object.some_method
169+
end
170+
171+
object
172+
end
173+
174+
it 'returns its non-singleton ancestor class' do
175+
expect(klass).to equal(String)
176+
end
177+
end
178+
179+
context 'with a Class instance' do
180+
let(:object) do
181+
String
182+
end
183+
184+
it { should equal(Class) }
185+
end
186+
end
187+
121188
describe "failure notification" do
122189
before { @failure_notifier = RSpec::Support.failure_notifier }
123190
after { RSpec::Support.failure_notifier = @failure_notifier }

0 commit comments

Comments
 (0)