Skip to content

Commit 5c2ce79

Browse files
committed
ActiveRecordRelations support for generic definitions in AR models
1 parent 21a9a6d commit 5c2ce79

File tree

4 files changed

+811
-16
lines changed

4 files changed

+811
-16
lines changed

lib/tapioca/dsl/compilers/active_record_relations.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,16 @@ def common_relation_methods_module
278278

279279
sig { returns(String) }
280280
def constant_name
281-
@constant_name ||= T.let(T.must(qualified_name_of(constant)), T.nilable(String))
281+
@constant_name ||= T.let(constant_name_of(constant), T.nilable(String))
282+
end
283+
284+
sig { params(constant: ConstantType).returns(String) }
285+
def constant_name_of(constant)
286+
if T::Generic === constant
287+
generic_name_of(constant)
288+
else
289+
T.must(qualified_name_of(constant))
290+
end
282291
end
283292

284293
sig { params(method_name: Symbol).returns(T::Boolean) }

lib/tapioca/gem/pipeline.rb

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -475,21 +475,6 @@ def generic_name_of(constant)
475475

476476
"#{type_name}[#{type_variable_names}]"
477477
end
478-
479-
sig { params(constant: Module, class_name: T.nilable(String)).returns(T.nilable(String)) }
480-
def name_of_proxy_target(constant, class_name)
481-
return unless class_name == "ActiveSupport::Deprecation::DeprecatedConstantProxy"
482-
483-
# We are dealing with a ActiveSupport::Deprecation::DeprecatedConstantProxy
484-
# so try to get the name of the target class
485-
begin
486-
target = constant.__send__(:target)
487-
rescue NoMethodError
488-
return
489-
end
490-
491-
name_of(target)
492-
end
493478
end
494479
end
495480
end

lib/tapioca/helpers/rbi_helper.rb

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module RBIHelper
66
extend T::Sig
77
include SorbetHelper
88
extend SorbetHelper
9+
include Runtime::Reflection
910
extend self
1011

1112
class << self
@@ -138,5 +139,61 @@ def valid_parameter_name?(name)
138139
rescue SyntaxError
139140
false
140141
end
142+
143+
sig { params(constant: T.all(Module, T::Generic)).returns(String) }
144+
def generic_name_of(constant)
145+
type_name = T.must(qualified_name_of(constant))
146+
return type_name if type_name =~ /\[.*\]$/
147+
148+
type_variables = Runtime::GenericTypeRegistry.lookup_type_variables(constant)
149+
return type_name unless type_variables
150+
151+
type_variables = type_variables.reject(&:fixed?)
152+
return type_name if type_variables.empty?
153+
154+
type_variable_names = type_variables.map { "T.untyped" }.join(", ")
155+
156+
"#{type_name}[#{type_variable_names}]"
157+
end
158+
159+
sig { params(constant: Module).returns(T.nilable(String)) }
160+
def qualified_name_of(constant)
161+
name = name_of(constant)
162+
return if name.nil?
163+
164+
if name.start_with?("::")
165+
name
166+
else
167+
"::#{name}"
168+
end
169+
end
170+
171+
sig { params(constant: Module).returns(T.nilable(String)) }
172+
def name_of(constant)
173+
name = name_of_proxy_target(constant, super(class_of(constant)))
174+
return name if name
175+
176+
name = super(constant)
177+
return if name.nil?
178+
return unless are_equal?(constant, constantize(name, inherit: true))
179+
180+
name = "Struct" if name =~ /^(::)?Struct::[^:]+$/
181+
name
182+
end
183+
184+
sig { params(constant: Module, class_name: T.nilable(String)).returns(T.nilable(String)) }
185+
def name_of_proxy_target(constant, class_name)
186+
return unless class_name == "ActiveSupport::Deprecation::DeprecatedConstantProxy"
187+
188+
# We are dealing with a ActiveSupport::Deprecation::DeprecatedConstantProxy
189+
# so try to get the name of the target class
190+
begin
191+
target = constant.__send__(:target)
192+
rescue NoMethodError
193+
return
194+
end
195+
196+
name_of(target)
197+
end
141198
end
142199
end

0 commit comments

Comments
 (0)