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)
 | 
					    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…
	
	Add table
		Add a link
		
	
		Reference in a new issue