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
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)
|
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
|
* Data
|
||||||
* New core class to represent simple immutable value object. The class is
|
* New core class to represent simple immutable value object. The class is
|
||||||
similar to `Struct` and partially shares an implementation, but has more
|
similar to `Struct` and partially shares an implementation, but has more
|
||||||
@ -323,6 +338,7 @@ The following deprecated APIs are removed.
|
|||||||
## Miscellaneous changes
|
## Miscellaneous changes
|
||||||
|
|
||||||
[Feature #12005]: https://bugs.ruby-lang.org/issues/12005
|
[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 #12655]: https://bugs.ruby-lang.org/issues/12655
|
||||||
[Feature #12737]: https://bugs.ruby-lang.org/issues/12737
|
[Feature #12737]: https://bugs.ruby-lang.org/issues/12737
|
||||||
[Feature #13110]: https://bugs.ruby-lang.org/issues/13110
|
[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);
|
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
|
static void
|
||||||
ins_methods_push(st_data_t name, st_data_t ary)
|
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);
|
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
|
* Generates an array of symbols, which are the list of method names defined in
|
||||||
* the passed class.
|
* 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, "initialize", rb_class_initialize, -1);
|
||||||
rb_define_method(rb_cClass, "superclass", rb_class_superclass, 0);
|
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, "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_define_alloc_func(rb_cClass, rb_class_s_alloc);
|
||||||
rb_undef_method(rb_cClass, "extend_object");
|
rb_undef_method(rb_cClass, "extend_object");
|
||||||
rb_undef_method(rb_cClass, "append_features");
|
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
|
||||||
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
|
def test_subclass_gc
|
||||||
c = Class.new
|
c = Class.new
|
||||||
10_000.times do
|
10_000.times do
|
||||||
|
Loading…
x
Reference in New Issue
Block a user