mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Add Class#attached_object
Implements [Feature #12084] Returns the object for which the receiver is the singleton class, or raises TypeError if the receiver is not a singleton class.
This commit is contained in:
parent
192bc72529
commit
0378e2f4a8
Notes:
git
2022-10-20 15:30:37 +00:00
6 changed files with 112 additions and 0 deletions
16
NEWS.md
16
NEWS.md
|
@ -115,6 +115,21 @@ Note: We're only listing outstanding class updates.
|
|||
STDIN.read # => Blocking operation timed out! (IO::TimeoutError)
|
||||
```
|
||||
|
||||
* Class
|
||||
* `Class#attached_object`, which returns the object for which
|
||||
the receiver is the singleton class. Raises `TypeError` if the
|
||||
receiver is not a singleton class.
|
||||
[[Feature #12084]]
|
||||
|
||||
```ruby
|
||||
class Foo; end
|
||||
|
||||
Foo.singleton_class.attached_object #=> Foo
|
||||
Foo.new.singleton_class.attached_object #=> #<Foo:0x000000010491a370>
|
||||
Foo.attached_object #=> TypeError: `Foo' is not a singleton class
|
||||
nil.singleton_class.attached_object #=> TypeError: `NilClass' is not a singleton class
|
||||
```
|
||||
|
||||
* Data
|
||||
* New core class to represent simple immutable value object. The class is
|
||||
similar to `Struct` and partially shares an implementation, but has more
|
||||
|
@ -323,6 +338,7 @@ The following deprecated APIs are removed.
|
|||
## Miscellaneous changes
|
||||
|
||||
[Feature #12005]: https://bugs.ruby-lang.org/issues/12005
|
||||
[Feature #12084]: https://bugs.ruby-lang.org/issues/12084
|
||||
[Feature #12655]: https://bugs.ruby-lang.org/issues/12655
|
||||
[Feature #12737]: https://bugs.ruby-lang.org/issues/12737
|
||||
[Feature #13110]: https://bugs.ruby-lang.org/issues/13110
|
||||
|
|
27
class.c
27
class.c
|
@ -1589,6 +1589,33 @@ rb_class_subclasses(VALUE klass)
|
|||
return class_descendants(klass, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* attached_object -> object
|
||||
*
|
||||
* Returns the object for which the receiver is the singleton class.
|
||||
*
|
||||
* Raises an TypeError if the class is not a singleton class.
|
||||
*
|
||||
* class Foo; end
|
||||
*
|
||||
* Foo.singleton_class.attached_object #=> Foo
|
||||
* Foo.attached_object #=> TypeError: `Foo' is not a singleton class
|
||||
* Foo.new.singleton_class.attached_object #=> #<Foo:0x000000010491a370>
|
||||
* TrueClass.attached_object #=> TypeError: `TrueClass' is not a singleton class
|
||||
* NilClass.attached_object #=> TypeError: `NilClass' is not a singleton class
|
||||
*/
|
||||
|
||||
VALUE
|
||||
rb_class_attached_object(VALUE klass)
|
||||
{
|
||||
if (!FL_TEST(klass, FL_SINGLETON)) {
|
||||
rb_raise(rb_eTypeError, "`%"PRIsVALUE"' is not a singleton class", klass);
|
||||
}
|
||||
|
||||
return rb_attr_get(klass, id_attached);
|
||||
}
|
||||
|
||||
static void
|
||||
ins_methods_push(st_data_t name, st_data_t ary)
|
||||
{
|
||||
|
|
|
@ -200,6 +200,18 @@ VALUE rb_class_descendants(VALUE klass);
|
|||
*/
|
||||
VALUE rb_class_subclasses(VALUE klass);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the attached object for a singleton class.
|
||||
* If the given class is not a singleton class, raises a TypeError.
|
||||
*
|
||||
* @param[in] klass A class.
|
||||
* @return The object which has the singleton class `klass`.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
VALUE rb_class_attached_object(VALUE klass);
|
||||
|
||||
/**
|
||||
* Generates an array of symbols, which are the list of method names defined in
|
||||
* the passed class.
|
||||
|
|
1
object.c
1
object.c
|
@ -4464,6 +4464,7 @@ InitVM_Object(void)
|
|||
rb_define_method(rb_cClass, "initialize", rb_class_initialize, -1);
|
||||
rb_define_method(rb_cClass, "superclass", rb_class_superclass, 0);
|
||||
rb_define_method(rb_cClass, "subclasses", rb_class_subclasses, 0); /* in class.c */
|
||||
rb_define_method(rb_cClass, "attached_object", rb_class_attached_object, 0); /* in class.c */
|
||||
rb_define_alloc_func(rb_cClass, rb_class_s_alloc);
|
||||
rb_undef_method(rb_cClass, "extend_object");
|
||||
rb_undef_method(rb_cClass, "append_features");
|
||||
|
|
31
spec/ruby/core/class/attached_object_spec.rb
Normal file
31
spec/ruby/core/class/attached_object_spec.rb
Normal file
|
@ -0,0 +1,31 @@
|
|||
require_relative '../../spec_helper'
|
||||
|
||||
ruby_version_is '3.2' do
|
||||
describe "Class#attached_object" do
|
||||
it "returns the object that is attached to a singleton class" do
|
||||
a = Class.new
|
||||
|
||||
a_obj = a.new
|
||||
a_obj.singleton_class.attached_object.should == a_obj
|
||||
end
|
||||
|
||||
it "returns the class object that is attached to a class's singleton class" do
|
||||
a = Class.new
|
||||
singleton_class = (class << a; self; end)
|
||||
|
||||
singleton_class.attached_object.should == a
|
||||
end
|
||||
|
||||
it "raises TypeError if the class is not a singleton class" do
|
||||
a = Class.new
|
||||
|
||||
-> { a.attached_object }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises TypeError for special singleton classes" do
|
||||
-> { nil.singleton_class.attached_object }.should raise_error(TypeError)
|
||||
-> { true.singleton_class.attached_object }.should raise_error(TypeError)
|
||||
-> { false.singleton_class.attached_object }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -759,6 +759,31 @@ class TestClass < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_attached_object
|
||||
c = Class.new
|
||||
sc = c.singleton_class
|
||||
obj = c.new
|
||||
|
||||
assert_equal(obj, obj.singleton_class.attached_object)
|
||||
assert_equal(c, sc.attached_object)
|
||||
|
||||
assert_raise_with_message(TypeError, /is not a singleton class/) do
|
||||
c.attached_object
|
||||
end
|
||||
|
||||
assert_raise_with_message(TypeError, /`NilClass' is not a singleton class/) do
|
||||
nil.singleton_class.attached_object
|
||||
end
|
||||
|
||||
assert_raise_with_message(TypeError, /`FalseClass' is not a singleton class/) do
|
||||
false.singleton_class.attached_object
|
||||
end
|
||||
|
||||
assert_raise_with_message(TypeError, /`TrueClass' is not a singleton class/) do
|
||||
true.singleton_class.attached_object
|
||||
end
|
||||
end
|
||||
|
||||
def test_subclass_gc
|
||||
c = Class.new
|
||||
10_000.times do
|
||||
|
|
Loading…
Reference in a new issue