Skip to content

Commit

Permalink
Merge pull request #265 from pocke/absolute_type_name
Browse files Browse the repository at this point in the history
absolute type name
  • Loading branch information
pocke authored Jul 13, 2023
2 parents 81cae00 + 43543f7 commit 4ba3f0f
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 132 deletions.
87 changes: 48 additions & 39 deletions lib/rbs_rails/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ class Generator
def initialize(klass, dependencies:)
@klass = klass
@dependencies = dependencies
@klass_name = Util.module_name(klass)
@klass_name = Util.module_name(klass, abs: false)

namespaces = klass_name.split('::').tap{ |names| names.pop }
namespaces = klass_name(abs: false).split('::').tap{ |names| names.pop }
@dependencies << namespaces.join('::') unless namespaces.empty?
end

Expand All @@ -30,7 +30,7 @@ def generate
private def klass_decl
<<~RBS
#{header}
extend _ActiveRecord_Relation_ClassMethods[#{klass_name}, #{relation_class_name}, #{pk_type}]
extend ::_ActiveRecord_Relation_ClassMethods[#{klass_name}, #{relation_class_name}, #{pk_type}]
#{columns}
#{associations}
Expand Down Expand Up @@ -62,7 +62,7 @@ def generate

private def generated_relation_methods_decl
<<~RBS
module GeneratedRelationMethods
module #{generated_relation_methods_name(abs: false)}
#{enum_scope_methods(singleton: false)}
#{scopes(singleton: false)}
#{delegated_type_scope(singleton: false)}
Expand All @@ -72,33 +72,33 @@ module GeneratedRelationMethods

private def relation_decl
<<~RBS
class #{relation_class_name} < ::ActiveRecord::Relation
include GeneratedRelationMethods
include _ActiveRecord_Relation[#{klass_name}, #{pk_type}]
include Enumerable[#{klass_name}]
class #{relation_class_name(abs: false)} < ::ActiveRecord::Relation
include #{generated_relation_methods_name}
include ::_ActiveRecord_Relation[#{klass_name}, #{pk_type}]
include ::Enumerable[#{klass_name}]
end
RBS
end

private def collection_proxy_decl
<<~RBS
class ActiveRecord_Associations_CollectionProxy < ::ActiveRecord::Associations::CollectionProxy
include GeneratedRelationMethods
include _ActiveRecord_Relation[#{klass_name}, #{pk_type}]
include #{generated_relation_methods_name}
include ::_ActiveRecord_Relation[#{klass_name}, #{pk_type}]
end
RBS
end

private def header
namespace = +''
klass_name.split('::').map do |mod_name|
klass_name(abs: false).split('::').map do |mod_name|
namespace += "::#{mod_name}"
mod_object = Object.const_get(namespace)
case mod_object
when Class
# @type var superclass: Class
superclass = _ = mod_object.superclass
superclass_name = Util.module_name(superclass)
superclass_name = Util.module_name(superclass, abs: false)
@dependencies << superclass_name

"class #{mod_name} < ::#{superclass_name}"
Expand All @@ -111,7 +111,7 @@ class ActiveRecord_Associations_CollectionProxy < ::ActiveRecord::Associations::
end

private def footer
"end\n" * klass_name.split('::').size
"end\n" * klass_name(abs: false).split('::').size
end

private def associations
Expand All @@ -133,9 +133,9 @@ class ActiveRecord_Associations_CollectionProxy < ::ActiveRecord::Associations::

<<~RUBY.chomp
def #{a.name}: () -> #{collection_type}
def #{a.name}=: (#{collection_type} | Array[#{type}]) -> (#{collection_type} | Array[#{type}])
def #{singular_name}_ids: () -> Array[Integer]
def #{singular_name}_ids=: (Array[Integer]) -> Array[Integer]
def #{a.name}=: (#{collection_type} | ::Array[#{type}]) -> (#{collection_type} | ::Array[#{type}])
def #{singular_name}_ids: () -> ::Array[::Integer]
def #{singular_name}_ids=: (::Array[::Integer]) -> ::Array[::Integer]
RUBY
end.join("\n")
end
Expand Down Expand Up @@ -190,17 +190,17 @@ def reload_#{a.name}: () -> #{type_optional}
case reflection.macro
when :has_one_attached
<<~EOS
def #{name}: () -> ActiveStorage::Attached::One
def #{name}=: (ActionDispatch::Http::UploadedFile) -> ActionDispatch::Http::UploadedFile
| (Rack::Test::UploadedFile) -> Rack::Test::UploadedFile
| (ActiveStorage::Blob) -> ActiveStorage::Blob
| (String) -> String
| ({ io: IO, filename: String, content_type: String? }) -> { io: IO, filename: String, content_type: String? }
def #{name}: () -> ::ActiveStorage::Attached::One
def #{name}=: (::ActionDispatch::Http::UploadedFile) -> ::ActionDispatch::Http::UploadedFile
| (::Rack::Test::UploadedFile) -> ::Rack::Test::UploadedFile
| (::ActiveStorage::Blob) -> ::ActiveStorage::Blob
| (::String) -> ::String
| ({ io: ::IO, filename: ::String, content_type: ::String? }) -> { io: ::IO, filename: ::String, content_type: ::String? }
| (nil) -> nil
EOS
when :has_many_attached
<<~EOS
def #{name}: () -> ActiveStorage::Attached::Many
def #{name}: () -> ::ActiveStorage::Attached::Many
def #{name}=: (untyped) -> untyped
EOS
else
Expand Down Expand Up @@ -460,7 +460,7 @@ def authenticate_#{attribute}: (String) -> (#{klass_name} | false)
private def parse_model_file
return @parse_model_file if defined?(@parse_model_file)

path = Rails.root.join('app/models/', klass_name.underscore + '.rb')
path = Rails.root.join('app/models/', klass_name(abs: false).underscore + '.rb')
return @parse_model_file = nil unless path.exist?
return [] unless path.exist?

Expand All @@ -479,15 +479,24 @@ def authenticate_#{attribute}: (String) -> (#{klass_name} | false)
end
end

private def relation_class_name
"ActiveRecord_Relation"
private def relation_class_name(abs: true)
abs ? "#{klass_name}::ActiveRecord_Relation" : "ActiveRecord_Relation"
end

private def klass_name(abs: true)
abs ? "::#{@klass_name}" : @klass_name
end

private def generated_relation_methods_name(abs: true)
abs ? "#{klass_name}::GeneratedRelationMethods" : "GeneratedRelationMethods"
end


private def columns
mod_sig = +"module GeneratedAttributeMethods\n"
mod_sig << klass.columns.map do |col|
class_name = if enum_definitions.any? { |hash| hash.key?(col.name) || hash.key?(col.name.to_sym) }
'String'
'::String'
else
sql_type_to_class(col.type)
end
Expand All @@ -502,12 +511,12 @@ def #{col.name}_change: () -> [#{class_name_opt}, #{class_name_opt}]
def #{col.name}_will_change!: () -> void
def #{col.name}_was: () -> #{class_name_opt}
def #{col.name}_previously_changed?: () -> bool
def #{col.name}_previous_change: () -> Array[#{class_name_opt}]?
def #{col.name}_previous_change: () -> ::Array[#{class_name_opt}]?
def #{col.name}_previously_was: () -> #{class_name_opt}
def #{col.name}_before_last_save: () -> #{class_name_opt}
def #{col.name}_change_to_be_saved: () -> Array[#{class_name_opt}]?
def #{col.name}_change_to_be_saved: () -> ::Array[#{class_name_opt}]?
def #{col.name}_in_database: () -> #{class_name_opt}
def saved_change_to_#{col.name}: () -> Array[#{class_name_opt}]?
def saved_change_to_#{col.name}: () -> ::Array[#{class_name_opt}]?
def saved_change_to_#{col.name}?: () -> bool
def will_save_change_to_#{col.name}?: () -> bool
def restore_#{col.name}!: () -> void
Expand All @@ -528,33 +537,33 @@ def clear_#{col.name}_change: () -> void
private def sql_type_to_class(t)
case t
when :integer
'Integer'
'::Integer'
when :float
'Float'
'::Float'
when :decimal
'BigDecimal'
'::BigDecimal'
when :string, :text, :citext, :uuid, :binary
'String'
'::String'
when :datetime
'ActiveSupport::TimeWithZone'
'::ActiveSupport::TimeWithZone'
when :boolean
"bool"
when :jsonb, :json
"untyped"
when :date
'Date'
'::Date'
when :time
'Time'
'::Time'
when :inet
"IPAddr"
"::IPAddr"
else
# Unknown column type, give up
'untyped'
end
end

private
attr_reader :klass, :klass_name
attr_reader :klass
end
end
end
6 changes: 5 additions & 1 deletion lib/rbs_rails/dependency_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def initialize
def build
dep_rbs = +""
deps.uniq!
while dep = deps.shift
while dep = shift
next unless done.add?(dep)

case dep_object = Object.const_get(dep)
Expand Down Expand Up @@ -39,5 +39,9 @@ def build
Util.format_rbs(dep_rbs)
end
end

private def shift
deps.shift&.sub(/^::/, '')
end
end
end
6 changes: 4 additions & 2 deletions lib/rbs_rails/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ module Util

extend self

def module_name(mod)
MODULE_NAME.bind_call(mod)
def module_name(mod, abs: true)
name = MODULE_NAME.bind_call(mod)
name ="::#{name}" if abs
name
end

def format_rbs(rbs)
Expand Down
9 changes: 6 additions & 3 deletions sig/rbs_rails/active_record.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class RbsRails::ActiveRecord::Generator
@parse_model_file: nil | Parser::AST::Node
@dependencies: Array[String]
@enum_definitions: Array[Hash[Symbol, untyped]]
@klass_name: String

IGNORED_ENUM_KEYS: Array[Symbol]

Expand Down Expand Up @@ -68,7 +69,11 @@ class RbsRails::ActiveRecord::Generator
def traverse: (Parser::AST::Node node) { (Parser::AST::Node) -> untyped } -> untyped
| (Parser::AST::Node node) -> Enumerator[Parser::AST::Node, untyped]

def relation_class_name: () -> untyped
def relation_class_name: (?abs: boolish) -> String

def klass_name: (?abs: boolish) -> String

def generated_relation_methods_name: (?abs: boolish) -> String

def columns: () -> untyped

Expand All @@ -79,6 +84,4 @@ class RbsRails::ActiveRecord::Generator
private

attr_reader klass: singleton(ActiveRecord::Base)

attr_reader klass_name: String
end
4 changes: 4 additions & 0 deletions sig/rbs_rails/dependency_builder.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@ module RbsRails
def initialize: () -> void

def build: () -> (String | nil)

private

def shift: () -> (String | nil)
end
end
2 changes: 1 addition & 1 deletion sig/rbs_rails/util.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module RbsRails

extend Util

def module_name: (Module) -> String
def module_name: (Module, ?abs: boolish) -> String

def format_rbs: (String) -> String
end
Expand Down
Loading

0 comments on commit 4ba3f0f

Please sign in to comment.