| 
									
										
										
										
											2024-01-12 09:53:53 -08:00
										 |  |  | # typed: strict | 
					
						
							| 
									
										
										
										
											2023-11-29 15:18:14 +00:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #-- | 
					
						
							|  |  |  | # Most objects are cloneable, but not all. For example you can't dup methods: | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #   method(:puts).dup # => TypeError: allocator undefined for Method | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Classes may signal their instances are not duplicable removing +dup+/+clone+ | 
					
						
							|  |  |  | # or raising exceptions from them. So, to dup an arbitrary object you normally | 
					
						
							|  |  |  | # use an optimistic approach and are ready to catch an exception, say: | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #   arbitrary_object.dup rescue object | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Rails dups objects in a few critical spots where they are not that arbitrary. | 
					
						
							|  |  |  | # That rescue is very expensive (like 40 times slower than a predicate), and it | 
					
						
							|  |  |  | # is often triggered. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # That's why we hardcode the following cases and check duplicable? instead of | 
					
						
							|  |  |  | # using that rescue idiom. | 
					
						
							|  |  |  | #++ | 
					
						
							|  |  |  | class Object | 
					
						
							|  |  |  |   # Can you safely dup this object? | 
					
						
							|  |  |  |   # | 
					
						
							|  |  |  |   # False for method objects; | 
					
						
							|  |  |  |   # true otherwise. | 
					
						
							| 
									
										
										
										
											2024-01-12 09:53:53 -08:00
										 |  |  |   sig { returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2024-01-12 11:45:19 -08:00
										 |  |  |   def duplicable? = true | 
					
						
							| 
									
										
										
										
											2023-11-29 15:18:14 +00:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Method | 
					
						
							|  |  |  |   # Methods are not duplicable: | 
					
						
							|  |  |  |   # | 
					
						
							| 
									
										
										
										
											2024-01-12 09:53:53 -08:00
										 |  |  |   #   method(:puts).duplicable? # => false | 
					
						
							|  |  |  |   #   method(:puts).dup         # => TypeError: allocator undefined for Method | 
					
						
							|  |  |  |   sig { returns(FalseClass) } | 
					
						
							| 
									
										
										
										
											2024-01-12 11:45:19 -08:00
										 |  |  |   def duplicable? = false | 
					
						
							| 
									
										
										
										
											2023-11-29 15:18:14 +00:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class UnboundMethod | 
					
						
							|  |  |  |   # Unbound methods are not duplicable: | 
					
						
							|  |  |  |   # | 
					
						
							| 
									
										
										
										
											2024-01-12 09:53:53 -08:00
										 |  |  |   #   method(:puts).unbind.duplicable? # => false | 
					
						
							|  |  |  |   #   method(:puts).unbind.dup         # => TypeError: allocator undefined for UnboundMethod | 
					
						
							|  |  |  |   sig { returns(FalseClass) } | 
					
						
							| 
									
										
										
										
											2024-01-12 11:45:19 -08:00
										 |  |  |   def duplicable? = false | 
					
						
							| 
									
										
										
										
											2024-01-12 09:53:53 -08:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require "singleton" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Singleton | 
					
						
							|  |  |  |   # Singleton instances are not duplicable: | 
					
						
							|  |  |  |   # | 
					
						
							|  |  |  |   #   Class.new.include(Singleton).instance.dup # TypeError (can't dup instance of singleton | 
					
						
							|  |  |  |   sig { returns(FalseClass) } | 
					
						
							| 
									
										
										
										
											2024-01-12 11:45:19 -08:00
										 |  |  |   def duplicable? = false | 
					
						
							| 
									
										
										
										
											2023-11-29 15:18:14 +00:00
										 |  |  | end |