module Tapioca::GenericTypeRegistry
This class is responsible for storing and looking up information related to generic types.
The class stores 2 different kinds of data, in two separate lookup tables:
1. a lookup of generic type instances by name: `@generic_instances` 2. a lookup of type variable serializer by constant and type variable instance: `@type_variables`
By storing the above data, we can cheaply query each constant against this registry to see if it declares any generic type variables. This becomes a simple lookup in the `@type_variables` hash table with the given constant.
If there is no entry, then we can cheaply know that we can skip generic type information generation for this type.
On the other hand, if we get a result, then the result will be a hash of type variable to type variable serializers. This allows us to associate type variables to the constant names that represent them, easily.
Constants
- TypeVariable
Public Class Methods
lookup_type_variables(constant)
click to toggle source
# File lib/tapioca/generic_type_registry.rb, line 64 def lookup_type_variables(constant) @type_variables[constant] end
register_type(constant, types)
click to toggle source
# File lib/tapioca/generic_type_registry.rb, line 49 def register_type(constant, types) # Build the name of the instantiated generic type, # something like `"Foo[X, Y, Z]"` type_list = types.map { |type| T::Utils.coerce(type).name }.join(", ") name = "#{Reflection.name_of(constant)}[#{type_list}]" # Create a generic type with an overridden `name` # method that returns the name we constructed above. # # Also, we try to memoize the generic type based on the name, so that # we don't have to keep recreating them all the time. @generic_instances[name] ||= create_generic_type(constant, name) end
register_type_variable(constant, type_variable)
click to toggle source
# File lib/tapioca/generic_type_registry.rb, line 83 def register_type_variable(constant, type_variable) type_variables = lookup_or_initialize_type_variables(constant) type_variables[type_variable] = type_variable.serialize end
Private Class Methods
create_generic_type(constant, name)
click to toggle source
# File lib/tapioca/generic_type_registry.rb, line 92 def create_generic_type(constant, name) generic_type = case constant when Class # For classes, we want to create a subclass, so that an instance of # the generic class `Foo[Bar]` is still a `Foo`. That is: # `Foo[Bar].new.is_a?(Foo)` should be true, which isn't the case # if we just clone the class. But subclassing works just fine. create_safe_subclass(constant) else # This can only be a module and it is fine to just clone modules # since they can't have instances and will not have `is_a?` relationships. # Moreover, we never `include`/`extend` any generic modules into the # ancestor tree, so this doesn't become a problem with checking the # instance of a class being `is_a?` of a module type. constant.clone end # Let's set the `name` method to return the proper generic name generic_type.define_singleton_method(:name) { name } # Return the generic type we created generic_type end
create_safe_subclass(constant)
click to toggle source
# File lib/tapioca/generic_type_registry.rb, line 117 def create_safe_subclass(constant) # Lookup the "inherited" class method inherited_method = constant.method(:inherited) # and the module that defines it owner = inherited_method.owner # If no one has overriden the inherited method yet, just subclass return Class.new(constant) if Class == owner begin # Otherwise, some inherited method could be preventing us # from creating subclasses, so let's override it and rescue owner.send(:define_method, :inherited) do |s| inherited_method.call(s) rescue # Ignoring errors end # return a subclass Class.new(constant) ensure # Reinstate the original inherited method back. owner.send(:define_method, :inherited, inherited_method) end end
lookup_or_initialize_type_variables(constant)
click to toggle source
# File lib/tapioca/generic_type_registry.rb, line 144 def lookup_or_initialize_type_variables(constant) @type_variables[constant] ||= {}.compare_by_identity end