rbs_rails 0.11.0 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,12 +12,14 @@ module RbsRails
12
12
  end
13
13
 
14
14
  class Generator
15
+ IGNORED_ENUM_KEYS = %i[_prefix _suffix _default _scopes]
16
+
15
17
  def initialize(klass, dependencies:)
16
18
  @klass = klass
17
19
  @dependencies = dependencies
18
- @klass_name = Util.module_name(klass)
20
+ @klass_name = Util.module_name(klass, abs: false)
19
21
 
20
- namespaces = klass_name.split('::').tap{ |names| names.pop }
22
+ namespaces = klass_name(abs: false).split('::').tap{ |names| names.pop }
21
23
  @dependencies << namespaces.join('::') unless namespaces.empty?
22
24
  end
23
25
 
@@ -28,7 +30,7 @@ module RbsRails
28
30
  private def klass_decl
29
31
  <<~RBS
30
32
  #{header}
31
- extend _ActiveRecord_Relation_ClassMethods[#{klass_name}, #{relation_class_name}, #{pk_type}]
33
+ extend ::_ActiveRecord_Relation_ClassMethods[#{klass_name}, #{relation_class_name}, #{pk_type}]
32
34
 
33
35
  #{columns}
34
36
  #{associations}
@@ -60,7 +62,7 @@ module RbsRails
60
62
 
61
63
  private def generated_relation_methods_decl
62
64
  <<~RBS
63
- module GeneratedRelationMethods
65
+ module #{generated_relation_methods_name(abs: false)}
64
66
  #{enum_scope_methods(singleton: false)}
65
67
  #{scopes(singleton: false)}
66
68
  #{delegated_type_scope(singleton: false)}
@@ -70,10 +72,10 @@ module RbsRails
70
72
 
71
73
  private def relation_decl
72
74
  <<~RBS
73
- class #{relation_class_name} < ::ActiveRecord::Relation
74
- include GeneratedRelationMethods
75
- include _ActiveRecord_Relation[#{klass_name}, #{pk_type}]
76
- include Enumerable[#{klass_name}]
75
+ class #{relation_class_name(abs: false)} < ::ActiveRecord::Relation
76
+ include #{generated_relation_methods_name}
77
+ include ::_ActiveRecord_Relation[#{klass_name}, #{pk_type}]
78
+ include ::Enumerable[#{klass_name}]
77
79
  end
78
80
  RBS
79
81
  end
@@ -81,22 +83,22 @@ module RbsRails
81
83
  private def collection_proxy_decl
82
84
  <<~RBS
83
85
  class ActiveRecord_Associations_CollectionProxy < ::ActiveRecord::Associations::CollectionProxy
84
- include GeneratedRelationMethods
85
- include _ActiveRecord_Relation[#{klass_name}, #{pk_type}]
86
+ include #{generated_relation_methods_name}
87
+ include ::_ActiveRecord_Relation[#{klass_name}, #{pk_type}]
86
88
  end
87
89
  RBS
88
90
  end
89
91
 
90
92
  private def header
91
93
  namespace = +''
92
- klass_name.split('::').map do |mod_name|
94
+ klass_name(abs: false).split('::').map do |mod_name|
93
95
  namespace += "::#{mod_name}"
94
96
  mod_object = Object.const_get(namespace)
95
97
  case mod_object
96
98
  when Class
97
99
  # @type var superclass: Class
98
100
  superclass = _ = mod_object.superclass
99
- superclass_name = Util.module_name(superclass)
101
+ superclass_name = Util.module_name(superclass, abs: false)
100
102
  @dependencies << superclass_name
101
103
 
102
104
  "class #{mod_name} < ::#{superclass_name}"
@@ -109,7 +111,7 @@ module RbsRails
109
111
  end
110
112
 
111
113
  private def footer
112
- "end\n" * klass_name.split('::').size
114
+ "end\n" * klass_name(abs: false).split('::').size
113
115
  end
114
116
 
115
117
  private def associations
@@ -131,9 +133,9 @@ module RbsRails
131
133
 
132
134
  <<~RUBY.chomp
133
135
  def #{a.name}: () -> #{collection_type}
134
- def #{a.name}=: (#{collection_type} | Array[#{type}]) -> (#{collection_type} | Array[#{type}])
135
- def #{singular_name}_ids: () -> Array[Integer]
136
- def #{singular_name}_ids=: (Array[Integer]) -> Array[Integer]
136
+ def #{a.name}=: (#{collection_type} | ::Array[#{type}]) -> (#{collection_type} | ::Array[#{type}])
137
+ def #{singular_name}_ids: () -> ::Array[::Integer]
138
+ def #{singular_name}_ids=: (::Array[::Integer]) -> ::Array[::Integer]
137
139
  RUBY
138
140
  end.join("\n")
139
141
  end
@@ -147,7 +149,7 @@ module RbsRails
147
149
  <<~RUBY.chomp
148
150
  def #{a.name}: () -> #{type_optional}
149
151
  def #{a.name}=: (#{type_optional}) -> #{type_optional}
150
- def build_#{a.name}: (untyped) -> #{type}
152
+ def build_#{a.name}: (?untyped) -> #{type}
151
153
  def create_#{a.name}: (untyped) -> #{type}
152
154
  def create_#{a.name}!: (untyped) -> #{type}
153
155
  def reload_#{a.name}: () -> #{type_optional}
@@ -159,11 +161,13 @@ module RbsRails
159
161
  klass.reflect_on_all_associations(:belongs_to).map do |a|
160
162
  @dependencies << a.klass.name unless a.polymorphic?
161
163
 
164
+ is_optional = a.options[:optional]
165
+
162
166
  type = a.polymorphic? ? 'untyped' : Util.module_name(a.klass)
163
167
  type_optional = optional(type)
164
168
  # @type var methods: Array[String]
165
169
  methods = []
166
- methods << "def #{a.name}: () -> #{type}"
170
+ methods << "def #{a.name}: () -> #{is_optional ? type_optional : type}"
167
171
  methods << "def #{a.name}=: (#{type_optional}) -> #{type_optional}"
168
172
  methods << "def reload_#{a.name}: () -> #{type_optional}"
169
173
  if !a.polymorphic?
@@ -186,21 +190,21 @@ module RbsRails
186
190
  case reflection.macro
187
191
  when :has_one_attached
188
192
  <<~EOS
189
- def #{name}: () -> ActiveStorage::Attached::One
190
- def #{name}=: (ActionDispatch::Http::UploadedFile) -> ActionDispatch::Http::UploadedFile
191
- | (Rack::Test::UploadedFile) -> Rack::Test::UploadedFile
192
- | (ActiveStorage::Blob) -> ActiveStorage::Blob
193
- | (String) -> String
194
- | ({ io: IO, filename: String, content_type: String? }) -> { io: IO, filename: String, content_type: String? }
193
+ def #{name}: () -> ::ActiveStorage::Attached::One
194
+ def #{name}=: (::ActionDispatch::Http::UploadedFile) -> ::ActionDispatch::Http::UploadedFile
195
+ | (::Rack::Test::UploadedFile) -> ::Rack::Test::UploadedFile
196
+ | (::ActiveStorage::Blob) -> ::ActiveStorage::Blob
197
+ | (::String) -> ::String
198
+ | ({ io: ::IO, filename: ::String, content_type: ::String? }) -> { io: ::IO, filename: ::String, content_type: ::String? }
195
199
  | (nil) -> nil
196
200
  EOS
197
201
  when :has_many_attached
198
202
  <<~EOS
199
- def #{name}: () -> ActiveStorage::Attached::Many
203
+ def #{name}: () -> ::ActiveStorage::Attached::Many
200
204
  def #{name}=: (untyped) -> untyped
201
205
  EOS
202
206
  else
203
- raise
207
+ raise "unknown macro: #{reflection.macro}"
204
208
  end
205
209
  end.join("\n")
206
210
  sigs << "end"
@@ -316,7 +320,7 @@ module RbsRails
316
320
  methods = []
317
321
  enum_definitions.each do |hash|
318
322
  hash.each do |name, values|
319
- next if name == :_prefix || name == :_suffix || name == :_default
323
+ next if IGNORED_ENUM_KEYS.include?(name)
320
324
 
321
325
  values.each do |label, value|
322
326
  value_method_name = enum_method_name(hash, name, label)
@@ -334,7 +338,7 @@ module RbsRails
334
338
  methods = []
335
339
  enum_definitions.each do |hash|
336
340
  hash.each do |name, values|
337
- next if name == :_prefix || name == :_suffix || name == :_default
341
+ next if IGNORED_ENUM_KEYS.include?(name)
338
342
 
339
343
  values.each do |label, value|
340
344
  value_method_name = enum_method_name(hash, name, label)
@@ -456,7 +460,7 @@ module RbsRails
456
460
  private def parse_model_file
457
461
  return @parse_model_file if defined?(@parse_model_file)
458
462
 
459
- path = Rails.root.join('app/models/', klass_name.underscore + '.rb')
463
+ path = Rails.root.join('app/models/', klass_name(abs: false).underscore + '.rb')
460
464
  return @parse_model_file = nil unless path.exist?
461
465
  return [] unless path.exist?
462
466
 
@@ -467,24 +471,32 @@ module RbsRails
467
471
  end
468
472
 
469
473
  private def traverse(node, &block)
470
- return to_enum(__method__ || raise, node) unless block_given?
474
+ return to_enum(__method__ || raise, node) unless block
471
475
 
472
- # @type var block: ^(Parser::AST::Node) -> untyped
473
476
  block.call node
474
477
  node.children.each do |child|
475
478
  traverse(child, &block) if child.is_a?(Parser::AST::Node)
476
479
  end
477
480
  end
478
481
 
479
- private def relation_class_name
480
- "ActiveRecord_Relation"
482
+ private def relation_class_name(abs: true)
483
+ abs ? "#{klass_name}::ActiveRecord_Relation" : "ActiveRecord_Relation"
484
+ end
485
+
486
+ private def klass_name(abs: true)
487
+ abs ? "::#{@klass_name}" : @klass_name
481
488
  end
482
489
 
490
+ private def generated_relation_methods_name(abs: true)
491
+ abs ? "#{klass_name}::GeneratedRelationMethods" : "GeneratedRelationMethods"
492
+ end
493
+
494
+
483
495
  private def columns
484
496
  mod_sig = +"module GeneratedAttributeMethods\n"
485
497
  mod_sig << klass.columns.map do |col|
486
498
  class_name = if enum_definitions.any? { |hash| hash.key?(col.name) || hash.key?(col.name.to_sym) }
487
- 'String'
499
+ '::String'
488
500
  else
489
501
  sql_type_to_class(col.type)
490
502
  end
@@ -499,12 +511,12 @@ module RbsRails
499
511
  def #{col.name}_will_change!: () -> void
500
512
  def #{col.name}_was: () -> #{class_name_opt}
501
513
  def #{col.name}_previously_changed?: () -> bool
502
- def #{col.name}_previous_change: () -> Array[#{class_name_opt}]?
514
+ def #{col.name}_previous_change: () -> ::Array[#{class_name_opt}]?
503
515
  def #{col.name}_previously_was: () -> #{class_name_opt}
504
516
  def #{col.name}_before_last_save: () -> #{class_name_opt}
505
- def #{col.name}_change_to_be_saved: () -> Array[#{class_name_opt}]?
517
+ def #{col.name}_change_to_be_saved: () -> ::Array[#{class_name_opt}]?
506
518
  def #{col.name}_in_database: () -> #{class_name_opt}
507
- def saved_change_to_#{col.name}: () -> Array[#{class_name_opt}]?
519
+ def saved_change_to_#{col.name}: () -> ::Array[#{class_name_opt}]?
508
520
  def saved_change_to_#{col.name}?: () -> bool
509
521
  def will_save_change_to_#{col.name}?: () -> bool
510
522
  def restore_#{col.name}!: () -> void
@@ -525,25 +537,25 @@ module RbsRails
525
537
  private def sql_type_to_class(t)
526
538
  case t
527
539
  when :integer
528
- 'Integer'
540
+ '::Integer'
529
541
  when :float
530
- 'Float'
542
+ '::Float'
531
543
  when :decimal
532
- 'BigDecimal'
544
+ '::BigDecimal'
533
545
  when :string, :text, :citext, :uuid, :binary
534
- 'String'
546
+ '::String'
535
547
  when :datetime
536
- 'ActiveSupport::TimeWithZone'
548
+ '::ActiveSupport::TimeWithZone'
537
549
  when :boolean
538
550
  "bool"
539
551
  when :jsonb, :json
540
552
  "untyped"
541
553
  when :date
542
- 'Date'
554
+ '::Date'
543
555
  when :time
544
- 'Time'
556
+ '::Time'
545
557
  when :inet
546
- "IPAddr"
558
+ "::IPAddr"
547
559
  else
548
560
  # Unknown column type, give up
549
561
  'untyped'
@@ -551,7 +563,7 @@ module RbsRails
551
563
  end
552
564
 
553
565
  private
554
- attr_reader :klass, :klass_name
566
+ attr_reader :klass
555
567
  end
556
568
  end
557
569
  end
@@ -10,7 +10,7 @@ module RbsRails
10
10
  def build
11
11
  dep_rbs = +""
12
12
  deps.uniq!
13
- while dep = deps.shift
13
+ while dep = shift
14
14
  next unless done.add?(dep)
15
15
 
16
16
  case dep_object = Object.const_get(dep)
@@ -39,5 +39,9 @@ module RbsRails
39
39
  Util.format_rbs(dep_rbs)
40
40
  end
41
41
  end
42
+
43
+ private def shift
44
+ deps.shift&.sub(/^::/, '')
45
+ end
42
46
  end
43
47
  end
@@ -3,17 +3,17 @@ require 'rake/tasklib'
3
3
 
4
4
  module RbsRails
5
5
  class RakeTask < Rake::TaskLib
6
- attr_accessor :ignore_model_if, :name, :signature_root_dir
6
+ attr_accessor :ignore_model_if, :name
7
+ attr_writer :signature_root_dir
7
8
 
8
9
  def initialize(name = :rbs_rails, &block)
9
10
  super()
10
11
 
11
12
  @name = name
13
+ @signature_root_dir = Rails.root / 'sig/rbs_rails'
12
14
 
13
15
  block.call(self) if block
14
16
 
15
- setup_signature_root_dir!
16
-
17
17
  def_generate_rbs_for_models
18
18
  def_generate_rbs_for_path_helpers
19
19
  def_all
@@ -64,10 +64,10 @@ module RbsRails
64
64
  end
65
65
  end
66
66
 
67
- private def setup_signature_root_dir!
68
- @signature_root_dir ||= Rails.root / 'sig/rbs_rails'
69
- @signature_root_dir = Pathname(@signature_root_dir)
70
- @signature_root_dir.mkpath
67
+ private def signature_root_dir
68
+ Pathname(@signature_root_dir).tap do |dir|
69
+ dir.mkpath
70
+ end
71
71
  end
72
72
  end
73
73
  end
@@ -4,19 +4,23 @@ module RbsRails
4
4
 
5
5
  extend self
6
6
 
7
- if '2.7' <= RUBY_VERSION
8
- def module_name(mod)
9
- # HACK: RBS doesn't have UnboundMethod#bind_call
10
- (_ = MODULE_NAME).bind_call(mod)
11
- end
12
- else
13
- def module_name(mod)
14
- MODULE_NAME.bind(mod).call
15
- end
7
+ def module_name(mod, abs: true)
8
+ name = MODULE_NAME.bind_call(mod)
9
+ name ="::#{name}" if abs
10
+ name
16
11
  end
17
12
 
18
13
  def format_rbs(rbs)
19
- decls = RBS::Parser.parse_signature(rbs)
14
+ decls =
15
+ if Gem::Version.new('3') <= Gem::Version.new(RBS::VERSION)
16
+ parsed = _ = RBS::Parser.parse_signature(rbs)
17
+ parsed[1] + parsed[2]
18
+ else
19
+ # TODO: Remove this type annotation when rbs_rails drops support of RBS 2.x.
20
+ # @type var parsed: [RBS::Declarations::t]
21
+ parsed = _ = RBS::Parser.parse_signature(rbs)
22
+ end
23
+
20
24
  StringIO.new.tap do |io|
21
25
  RBS::Writer.new(out: io).write(decls)
22
26
  end.string
@@ -2,5 +2,5 @@ module RbsRails
2
2
  # Because of copy_signatures is defined by lib/rbs_rails.rb
3
3
  # @dynamic self.copy_signatures
4
4
 
5
- VERSION = "0.11.0"
5
+ VERSION = "0.12.1"
6
6
  end