rbs_rails 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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