tapioca 0.7.0 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tapioca/commands/todo.rb +4 -2
  3. data/lib/tapioca/dsl/compiler.rb +2 -2
  4. data/lib/tapioca/dsl/compilers/aasm.rb +1 -1
  5. data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +1 -1
  6. data/lib/tapioca/dsl/compilers/action_mailer.rb +1 -1
  7. data/lib/tapioca/dsl/compilers/active_job.rb +1 -1
  8. data/lib/tapioca/dsl/compilers/active_model_attributes.rb +1 -1
  9. data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +1 -1
  10. data/lib/tapioca/dsl/compilers/active_record_associations.rb +1 -1
  11. data/lib/tapioca/dsl/compilers/active_record_columns.rb +1 -1
  12. data/lib/tapioca/dsl/compilers/active_record_enum.rb +1 -1
  13. data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +3 -1
  14. data/lib/tapioca/dsl/compilers/active_record_relations.rb +8 -8
  15. data/lib/tapioca/dsl/compilers/active_record_scope.rb +1 -1
  16. data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +1 -1
  17. data/lib/tapioca/dsl/compilers/active_resource.rb +1 -1
  18. data/lib/tapioca/dsl/compilers/active_storage.rb +6 -2
  19. data/lib/tapioca/dsl/compilers/active_support_concern.rb +1 -1
  20. data/lib/tapioca/dsl/compilers/active_support_current_attributes.rb +1 -1
  21. data/lib/tapioca/dsl/compilers/config.rb +2 -2
  22. data/lib/tapioca/dsl/compilers/frozen_record.rb +1 -1
  23. data/lib/tapioca/dsl/compilers/identity_cache.rb +1 -1
  24. data/lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb +1 -1
  25. data/lib/tapioca/dsl/compilers/protobuf.rb +13 -3
  26. data/lib/tapioca/dsl/compilers/rails_generators.rb +1 -1
  27. data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +1 -1
  28. data/lib/tapioca/dsl/compilers/smart_properties.rb +1 -1
  29. data/lib/tapioca/dsl/compilers/state_machines.rb +1 -1
  30. data/lib/tapioca/dsl/compilers/url_helpers.rb +5 -2
  31. data/lib/tapioca/dsl/helpers/param_helper.rb +4 -1
  32. data/lib/tapioca/dsl/pipeline.rb +28 -1
  33. data/lib/tapioca/gem/listeners/sorbet_signatures.rb +1 -1
  34. data/lib/tapioca/gem/pipeline.rb +1 -1
  35. data/lib/tapioca/helpers/{rbi_helper.rb → signatures_helper.rb} +1 -1
  36. data/lib/tapioca/helpers/sorbet_helper.rb +2 -2
  37. data/lib/tapioca/helpers/type_variable_helper.rb +43 -0
  38. data/lib/tapioca/internal.rb +3 -2
  39. data/lib/tapioca/rbi_ext/model.rb +12 -2
  40. data/lib/tapioca/runtime/generic_type_registry.rb +4 -2
  41. data/lib/tapioca/runtime/reflection.rb +5 -1
  42. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +50 -20
  43. data/lib/tapioca/version.rb +1 -1
  44. metadata +8 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef378ec3f3035d85d6aebfa4624896d216bcccd7d9332cbdc9d64be469b79b48
4
- data.tar.gz: 2f34d64fadd075ed1653ec26d27c73a02bfff949440fc6d1fd8bf80116161b48
3
+ metadata.gz: 1b06e8ec67c72db19639c21a8a123ecbe7c3c58ad27eb8956d6e3772cb68dc1e
4
+ data.tar.gz: e8c0bb1073cc08c2fc9d7eea7b523ebe1bc87e7f162c0413e2f0f29be67481c4
5
5
  SHA512:
6
- metadata.gz: 78b6ce07ee08391457763a8e9069b0ff0efaa1be26cdeec7f334d2b45afa6ec12fd152d24c42d4c2b6834db25af77f74d6401bf577fd749ed446ef122dc01161
7
- data.tar.gz: 0b1998a9a72153d24747838606ff636cf8718efc67aa98e0c9d3ff01849d677840cd73f0adb8f289cc8c6f7e07b20bd37594bbcd1aea1b91761132fd07a1a9db
6
+ metadata.gz: fd44669e05b95b61ea62c3c5e7a640bc664a036418d66fad6734065caadaa52ec545408376d4e9ada732d2a976dc599b92fc374ec53ad2a1ffa247adee989acd
7
+ data.tar.gz: 8f6e3a4223c42f9271321b31c8f26199a9b371865041f3455b3e3350e356adaf0eca2c5d83bcec9e0247f76ed0434c1b93627e19f8c3d10893e084e5c88f7d3e
@@ -74,10 +74,12 @@ module Tapioca
74
74
  .each_line
75
75
  .map do |line|
76
76
  next if line.include?("<")
77
- next if line.include?("class_of")
78
- line.strip.gsub("T.untyped::", "")
77
+
78
+ line.strip
79
+ .gsub(/T\.class_of\(([:\w]+)\)/, '\1') # Turn T.class_of(Foo)::Bar into Foo::Bar
79
80
  end
80
81
  .compact
82
+ .sort
81
83
  end
82
84
  end
83
85
  end
@@ -17,7 +17,7 @@ module Tapioca
17
17
  include Runtime::Reflection
18
18
  extend Runtime::Reflection
19
19
 
20
- ConstantType = type_member(upper: Module)
20
+ ConstantType = type_member { { upper: Module } }
21
21
 
22
22
  abstract!
23
23
 
@@ -54,7 +54,7 @@ module Tapioca
54
54
  sig { returns(T::Set[Module]) }
55
55
  def self.processable_constants
56
56
  @processable_constants ||= T.let(
57
- Set.new(gather_constants).tap(&:compare_by_identity),
57
+ T::Set[Module].new(gather_constants).compare_by_identity,
58
58
  T.nilable(T::Set[Module])
59
59
  )
60
60
  T.must(@processable_constants)
@@ -49,7 +49,7 @@ module Tapioca
49
49
  T::Array[String]
50
50
  )
51
51
 
52
- ConstantType = type_member(fixed: T.all(::AASM::ClassMethods, Class))
52
+ ConstantType = type_member { { fixed: T.all(::AASM::ClassMethods, Class) } }
53
53
 
54
54
  sig { override.void }
55
55
  def decorate
@@ -68,7 +68,7 @@ module Tapioca
68
68
  class ActionControllerHelpers < Compiler
69
69
  extend T::Sig
70
70
 
71
- ConstantType = type_member(fixed: T.class_of(::ActionController::Base))
71
+ ConstantType = type_member { { fixed: T.class_of(::ActionController::Base) } }
72
72
 
73
73
  sig { override.void }
74
74
  def decorate
@@ -36,7 +36,7 @@ module Tapioca
36
36
  class ActionMailer < Compiler
37
37
  extend T::Sig
38
38
 
39
- ConstantType = type_member(fixed: T.class_of(::ActionMailer::Base))
39
+ ConstantType = type_member { { fixed: T.class_of(::ActionMailer::Base) } }
40
40
 
41
41
  sig { override.void }
42
42
  def decorate
@@ -40,7 +40,7 @@ module Tapioca
40
40
  class ActiveJob < Compiler
41
41
  extend T::Sig
42
42
 
43
- ConstantType = type_member(fixed: T.class_of(::ActiveJob::Base))
43
+ ConstantType = type_member { { fixed: T.class_of(::ActiveJob::Base) } }
44
44
 
45
45
  sig { override.void }
46
46
  def decorate
@@ -39,7 +39,7 @@ module Tapioca
39
39
  class ActiveModelAttributes < Compiler
40
40
  extend T::Sig
41
41
 
42
- ConstantType = type_member(fixed: T.all(Class, ::ActiveModel::Attributes::ClassMethods))
42
+ ConstantType = type_member { { fixed: T.all(Class, ::ActiveModel::Attributes::ClassMethods) } }
43
43
 
44
44
  sig { override.void }
45
45
  def decorate
@@ -60,7 +60,7 @@ module Tapioca
60
60
  class ActiveModelSecurePassword < Compiler
61
61
  extend T::Sig
62
62
 
63
- ConstantType = type_member(fixed: T.all(Class, ::ActiveModel::SecurePassword::ClassMethods))
63
+ ConstantType = type_member { { fixed: T.all(Class, ::ActiveModel::SecurePassword::ClassMethods) } }
64
64
 
65
65
  sig { override.void }
66
66
  def decorate
@@ -119,7 +119,7 @@ module Tapioca
119
119
  end
120
120
  end
121
121
 
122
- ConstantType = type_member(fixed: T.class_of(ActiveRecord::Base))
122
+ ConstantType = type_member { { fixed: T.class_of(ActiveRecord::Base) } }
123
123
 
124
124
  sig { override.void }
125
125
  def decorate
@@ -101,7 +101,7 @@ module Tapioca
101
101
  extend T::Sig
102
102
  include Helpers::ActiveRecordConstantsHelper
103
103
 
104
- ConstantType = type_member(fixed: T.class_of(ActiveRecord::Base))
104
+ ConstantType = type_member { { fixed: T.class_of(ActiveRecord::Base) } }
105
105
 
106
106
  sig { override.void }
107
107
  def decorate
@@ -58,7 +58,7 @@ module Tapioca
58
58
  class ActiveRecordEnum < Compiler
59
59
  extend T::Sig
60
60
 
61
- ConstantType = type_member(fixed: T.class_of(::ActiveRecord::Base))
61
+ ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
62
62
 
63
63
  sig { override.void }
64
64
  def decorate
@@ -38,7 +38,7 @@ module Tapioca
38
38
  class ActiveRecordFixtures < Compiler
39
39
  extend T::Sig
40
40
 
41
- ConstantType = type_member(fixed: T.class_of(ActiveSupport::TestCase))
41
+ ConstantType = type_member { { fixed: T.class_of(ActiveSupport::TestCase) } }
42
42
 
43
43
  sig { override.void }
44
44
  def decorate
@@ -60,6 +60,8 @@ module Tapioca
60
60
 
61
61
  sig { override.returns(T::Enumerable[Module]) }
62
62
  def self.gather_constants
63
+ return [] unless Rails.application
64
+
63
65
  [ActiveSupport::TestCase]
64
66
  end
65
67
 
@@ -118,7 +118,7 @@ module Tapioca
118
118
  # sig { returns(T::Array[::Post]) }
119
119
  # def to_ary; end
120
120
  #
121
- # Elem = type_member(fixed: ::Post)
121
+ # Elem = type_member { { fixed: ::Post } }
122
122
  # end
123
123
  #
124
124
  # class PrivateCollectionProxy < ::ActiveRecord::Associations::CollectionProxy
@@ -141,7 +141,7 @@ module Tapioca
141
141
  # sig { returns(T::Array[::Post]) }
142
142
  # def to_ary; end
143
143
  #
144
- # Elem = type_member(fixed: ::Post)
144
+ # Elem = type_member { { fixed: ::Post } }
145
145
  # end
146
146
  # end
147
147
  # ~~~
@@ -150,7 +150,7 @@ module Tapioca
150
150
  include Helpers::ActiveRecordConstantsHelper
151
151
  include SorbetHelper
152
152
 
153
- ConstantType = type_member(fixed: T.class_of(::ActiveRecord::Base))
153
+ ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
154
154
 
155
155
  sig { override.void }
156
156
  def decorate
@@ -253,7 +253,7 @@ module Tapioca
253
253
  model.create_class(RelationClassName, superclass_name: superclass) do |klass|
254
254
  klass.create_include(CommonRelationMethodsModuleName)
255
255
  klass.create_include(RelationMethodsModuleName)
256
- klass.create_constant("Elem", value: "type_member(fixed: #{constant_name})")
256
+ klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
257
257
 
258
258
  klass.create_method("to_ary", return_type: "T::Array[#{constant_name}]")
259
259
  end
@@ -269,7 +269,7 @@ module Tapioca
269
269
  model.create_class(AssociationRelationClassName, superclass_name: superclass) do |klass|
270
270
  klass.create_include(CommonRelationMethodsModuleName)
271
271
  klass.create_include(AssociationRelationMethodsModuleName)
272
- klass.create_constant("Elem", value: "type_member(fixed: #{constant_name})")
272
+ klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
273
273
 
274
274
  klass.create_method("to_ary", return_type: "T::Array[#{constant_name}]")
275
275
  end
@@ -281,7 +281,7 @@ module Tapioca
281
281
  def create_relation_where_chain_class(model)
282
282
  model.create_class(RelationWhereChainClassName, superclass_name: RelationClassName) do |klass|
283
283
  create_where_chain_methods(klass, RelationClassName)
284
- klass.create_constant("Elem", value: "type_member(fixed: #{constant_name})")
284
+ klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
285
285
  end
286
286
  end
287
287
 
@@ -292,7 +292,7 @@ module Tapioca
292
292
  superclass_name: AssociationRelationClassName
293
293
  ) do |klass|
294
294
  create_where_chain_methods(klass, AssociationRelationClassName)
295
- klass.create_constant("Elem", value: "type_member(fixed: #{constant_name})")
295
+ klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
296
296
  end
297
297
  end
298
298
 
@@ -329,7 +329,7 @@ module Tapioca
329
329
  model.create_class(AssociationsCollectionProxyClassName, superclass_name: superclass) do |klass|
330
330
  klass.create_include(CommonRelationMethodsModuleName)
331
331
  klass.create_include(AssociationRelationMethodsModuleName)
332
- klass.create_constant("Elem", value: "type_member(fixed: #{constant_name})")
332
+ klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
333
333
 
334
334
  klass.create_method("to_ary", return_type: "T::Array[#{constant_name}]")
335
335
  create_collection_proxy_methods(klass)
@@ -46,7 +46,7 @@ module Tapioca
46
46
  extend T::Sig
47
47
  include Helpers::ActiveRecordConstantsHelper
48
48
 
49
- ConstantType = type_member(fixed: T.class_of(::ActiveRecord::Base))
49
+ ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
50
50
 
51
51
  sig { override.void }
52
52
  def decorate
@@ -90,7 +90,7 @@ module Tapioca
90
90
  class ActiveRecordTypedStore < Compiler
91
91
  extend T::Sig
92
92
 
93
- ConstantType = type_member(fixed: T.class_of(::ActiveRecord::Base))
93
+ ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
94
94
 
95
95
  sig { override.void }
96
96
  def decorate
@@ -61,7 +61,7 @@ module Tapioca
61
61
  class ActiveResource < Compiler
62
62
  extend T::Sig
63
63
 
64
- ConstantType = type_member(fixed: T.class_of(::ActiveResource::Base))
64
+ ConstantType = type_member { { fixed: T.class_of(::ActiveResource::Base) } }
65
65
 
66
66
  sig { override.void }
67
67
  def decorate
@@ -46,8 +46,12 @@ module Tapioca
46
46
  class ActiveStorage < Compiler
47
47
  extend T::Sig
48
48
 
49
- ConstantType = type_member(fixed: T.all(Module,
50
- ::ActiveStorage::Reflection::ActiveRecordExtensions::ClassMethods))
49
+ ConstantType = type_member do
50
+ {
51
+ fixed: T.all(Module,
52
+ ::ActiveStorage::Reflection::ActiveRecordExtensions::ClassMethods),
53
+ }
54
+ end
51
55
 
52
56
  sig { override.void }
53
57
  def decorate
@@ -44,7 +44,7 @@ module Tapioca
44
44
  class ActiveSupportConcern < Compiler
45
45
  extend T::Sig
46
46
 
47
- ConstantType = type_member(fixed: Module)
47
+ ConstantType = type_member { { fixed: Module } }
48
48
 
49
49
  sig { override.void }
50
50
  def decorate
@@ -62,7 +62,7 @@ module Tapioca
62
62
  class ActiveSupportCurrentAttributes < Compiler
63
63
  extend T::Sig
64
64
 
65
- ConstantType = type_member(fixed: T.class_of(::ActiveSupport::CurrentAttributes))
65
+ ConstantType = type_member { { fixed: T.class_of(::ActiveSupport::CurrentAttributes) } }
66
66
 
67
67
  sig { override.void }
68
68
  def decorate
@@ -49,7 +49,7 @@ module Tapioca
49
49
 
50
50
  CONFIG_OPTIONS_SUFFIX = "ConfigOptions"
51
51
 
52
- ConstantType = type_member(fixed: Module)
52
+ ConstantType = type_member { { fixed: Module } }
53
53
 
54
54
  sig { override.void }
55
55
  def decorate
@@ -77,7 +77,7 @@ module Tapioca
77
77
  # enumerates the entries, we don't make any assumptions about their
78
78
  # types.
79
79
  mod.create_extend("T::Generic")
80
- mod.create_type_member("Elem", value: "type_member(fixed: T.untyped)")
80
+ mod.create_type_variable("Elem", type: "type_member", fixed: "T.untyped")
81
81
 
82
82
  method_names.each do |method_name|
83
83
  # Create getter method
@@ -65,7 +65,7 @@ module Tapioca
65
65
  class FrozenRecord < Compiler
66
66
  extend T::Sig
67
67
 
68
- ConstantType = type_member(fixed: T.class_of(::FrozenRecord::Base))
68
+ ConstantType = type_member { { fixed: T.class_of(::FrozenRecord::Base) } }
69
69
 
70
70
  sig { override.void }
71
71
  def decorate
@@ -69,7 +69,7 @@ module Tapioca
69
69
  T.proc.params(type: T.any(Module, String)).returns(String)
70
70
  )
71
71
 
72
- ConstantType = type_member(fixed: T.class_of(::ActiveRecord::Base))
72
+ ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
73
73
 
74
74
  sig { override.void }
75
75
  def decorate
@@ -51,7 +51,7 @@ module Tapioca
51
51
  class MixedInClassAttributes < Compiler
52
52
  extend T::Sig
53
53
 
54
- ConstantType = type_member(fixed: Module)
54
+ ConstantType = type_member { { fixed: Module } }
55
55
 
56
56
  sig { override.void }
57
57
  def decorate
@@ -70,7 +70,9 @@ module Tapioca
70
70
 
71
71
  extend T::Sig
72
72
 
73
- ConstantType = type_member(fixed: Module)
73
+ ConstantType = type_member { { fixed: Module } }
74
+
75
+ FIELD_RE = /^[a-z_][a-zA-Z0-9_]*$/
74
76
 
75
77
  sig { override.void }
76
78
  def decorate
@@ -88,7 +90,15 @@ module Tapioca
88
90
  create_kw_opt_param(field.name, type: field.init_type, default: field.default)
89
91
  end
90
92
 
91
- klass.create_method("initialize", parameters: parameters, return_type: "void")
93
+ if fields.all? { |field| FIELD_RE.match?(field.name) }
94
+ klass.create_method("initialize", parameters: parameters, return_type: "void")
95
+ else
96
+ # One of the fields has an incorrect name for a named parameter so creating the default initialize for
97
+ # it would create a RBI with a syntax error.
98
+ # The workaround is to create an initialize that takes a **kwargs instead.
99
+ kwargs_parameter = create_kw_rest_param("fields", type: "T.untyped")
100
+ klass.create_method("initialize", parameters: [kwargs_parameter], return_type: "void")
101
+ end
92
102
  end
93
103
  end
94
104
  end
@@ -107,7 +117,7 @@ module Tapioca
107
117
  klass.create_extend("T::Generic")
108
118
 
109
119
  names.each do |name|
110
- klass.create_type_member(name)
120
+ klass.create_type_variable(name, type: "type_member")
111
121
  end
112
122
  end
113
123
 
@@ -46,7 +46,7 @@ module Tapioca
46
46
  Regexp
47
47
  )
48
48
 
49
- ConstantType = type_member(fixed: T.class_of(::Rails::Generators::Base))
49
+ ConstantType = type_member { { fixed: T.class_of(::Rails::Generators::Base) } }
50
50
 
51
51
  sig { override.void }
52
52
  def decorate
@@ -43,7 +43,7 @@ module Tapioca
43
43
  class SidekiqWorker < Compiler
44
44
  extend T::Sig
45
45
 
46
- ConstantType = type_member(fixed: T.class_of(::Sidekiq::Worker))
46
+ ConstantType = type_member { { fixed: T.class_of(::Sidekiq::Worker) } }
47
47
 
48
48
  sig { override.void }
49
49
  def decorate
@@ -63,7 +63,7 @@ module Tapioca
63
63
  class SmartProperties < Compiler
64
64
  extend T::Sig
65
65
 
66
- ConstantType = type_member(fixed: T.class_of(::SmartProperties))
66
+ ConstantType = type_member { { fixed: T.class_of(::SmartProperties) } }
67
67
 
68
68
  sig { override.void }
69
69
  def decorate
@@ -118,7 +118,7 @@ module Tapioca
118
118
  class StateMachines < Compiler
119
119
  extend T::Sig
120
120
 
121
- ConstantType = type_member(fixed: T.all(Module, ::StateMachines::ClassMethods))
121
+ ConstantType = type_member { { fixed: T.all(Module, ::StateMachines::ClassMethods) } }
122
122
 
123
123
  sig { override.void }
124
124
  def decorate
@@ -87,7 +87,7 @@ module Tapioca
87
87
  class UrlHelpers < Compiler
88
88
  extend T::Sig
89
89
 
90
- ConstantType = type_member(fixed: Module)
90
+ ConstantType = type_member { { fixed: Module } }
91
91
 
92
92
  sig { override.void }
93
93
  def decorate
@@ -109,6 +109,8 @@ module Tapioca
109
109
 
110
110
  sig { override.returns(T::Enumerable[Module]) }
111
111
  def self.gather_constants
112
+ return [] unless Rails.application
113
+
112
114
  Object.const_set(:GeneratedUrlHelpersModule, Rails.application.routes.named_routes.url_helpers_module)
113
115
  Object.const_set(:GeneratedPathHelpersModule, Rails.application.routes.named_routes.path_helpers_module)
114
116
 
@@ -160,7 +162,8 @@ module Tapioca
160
162
  superclass_ancestors = ancestors_of(superclass) if superclass
161
163
  end
162
164
 
163
- (ancestors_of(mod) - superclass_ancestors).any? { |ancestor| helper == ancestor }
165
+ ancestors = Set.new.compare_by_identity.merge(ancestors_of(mod)).subtract(superclass_ancestors)
166
+ ancestors.any? { |ancestor| helper == ancestor }
164
167
  end
165
168
  end
166
169
  end
@@ -1,11 +1,14 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "tapioca/helpers/signatures_helper"
5
+
4
6
  module Tapioca
5
7
  module Dsl
6
8
  module Helpers
7
9
  module ParamHelper
8
10
  extend T::Sig
11
+ include SignaturesHelper
9
12
 
10
13
  sig { params(name: String, type: String).returns(RBI::TypedParam) }
11
14
  def create_param(name, type:)
@@ -44,7 +47,7 @@ module Tapioca
44
47
 
45
48
  sig { params(param: RBI::Param, type: String).returns(RBI::TypedParam) }
46
49
  def create_typed_param(param, type)
47
- RBI::TypedParam.new(param: param, type: type)
50
+ RBI::TypedParam.new(param: param, type: sanitize_signature_types(type))
48
51
  end
49
52
  end
50
53
  end
@@ -53,7 +53,7 @@ module Tapioca
53
53
  end
54
54
  def run(&blk)
55
55
  constants_to_process = gather_constants(requested_constants)
56
- .select { |c| Runtime::Reflection.name_of(c) && Module === c } # Filter anonymous or value constants
56
+ .select { |c| Module === c } # Filter value constants out
57
57
  .sort_by! { |c| T.must(Runtime::Reflection.name_of(c)) }
58
58
 
59
59
  if constants_to_process.empty?
@@ -112,10 +112,37 @@ module Tapioca
112
112
  sig { params(requested_constants: T::Array[Module]).returns(T::Set[Module]) }
113
113
  def gather_constants(requested_constants)
114
114
  constants = compilers.map(&:processable_constants).reduce(Set.new, :union)
115
+ constants = filter_anonymous_and_reloaded_constants(constants)
116
+
115
117
  constants &= requested_constants unless requested_constants.empty?
116
118
  constants
117
119
  end
118
120
 
121
+ sig { params(constants: T::Set[Module]).returns(T::Set[Module]) }
122
+ def filter_anonymous_and_reloaded_constants(constants)
123
+ # Group constants by their names
124
+ constants_by_name = constants
125
+ .group_by { |c| T.must(Runtime::Reflection.name_of(c)) }
126
+ .select { |name, _| !name.nil? }
127
+
128
+ # Find the constants that have been reloaded
129
+ reloaded_constants = constants_by_name.select { |_, constants| constants.size > 1 }.keys
130
+
131
+ unless reloaded_constants.empty?
132
+ reloaded_constant_names = reloaded_constants.map { |name| "`#{name}`" }.join(", ")
133
+
134
+ $stderr.puts("WARNING: Multiple constants with the same name: #{reloaded_constant_names}")
135
+ $stderr.puts("Make sure some object is not holding onto these constants during an app reload.")
136
+ end
137
+
138
+ # Look up all the constants back from their names. The resulting constant set will be the
139
+ # set of constants that are actually in memory with those names.
140
+ constants_by_name
141
+ .keys
142
+ .map { |name| T.cast(Runtime::Reflection.constantize(name), Module) }
143
+ .to_set
144
+ end
145
+
119
146
  sig { params(constant: Module).returns(T.nilable(RBI::File)) }
120
147
  def rbi_for_constant(constant)
121
148
  file = RBI::File.new(strictness: "true")
@@ -8,7 +8,7 @@ module Tapioca
8
8
  extend T::Sig
9
9
 
10
10
  include Runtime::Reflection
11
- include RBIHelper
11
+ include SignaturesHelper
12
12
 
13
13
  TYPE_PARAMETER_MATCHER = /T\.type_parameter\(:?([[:word:]]+)\)/
14
14
 
@@ -8,7 +8,7 @@ module Tapioca
8
8
  class Pipeline
9
9
  extend T::Sig
10
10
  include Runtime::Reflection
11
- include RBIHelper
11
+ include SignaturesHelper
12
12
 
13
13
  IGNORED_SYMBOLS = T.let(["YAML", "MiniTest", "Mutex"], T::Array[String])
14
14
 
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- module RBIHelper
5
+ module SignaturesHelper
6
6
  extend T::Sig
7
7
 
8
8
  sig { params(sig_string: String).returns(String) }
@@ -21,8 +21,8 @@ module Tapioca
21
21
  SORBET_EXE_PATH_ENV_VAR = "TAPIOCA_SORBET_EXE"
22
22
 
23
23
  FEATURE_REQUIREMENTS = T.let({
24
- # First tag that includes https://github.com/sorbet/sorbet/pull/4706
25
- to_ary_nil_support: ::Gem::Requirement.new(">= 0.5.9220"),
24
+ to_ary_nil_support: ::Gem::Requirement.new(">= 0.5.9220"), # https://github.com/sorbet/sorbet/pull/4706
25
+ type_variable_block_syntax: ::Gem::Requirement.new(">= 0.5.9892"), # https://github.com/sorbet/sorbet/pull/5639
26
26
  }.freeze, T::Hash[Symbol, ::Gem::Requirement])
27
27
 
28
28
  class CmdResult < T::Struct
@@ -0,0 +1,43 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Tapioca
5
+ module TypeVariableHelper
6
+ extend T::Sig
7
+ extend SorbetHelper
8
+
9
+ sig do
10
+ params(
11
+ type: String,
12
+ variance: Symbol,
13
+ fixed: T.nilable(String),
14
+ upper: T.nilable(String),
15
+ lower: T.nilable(String)
16
+ ).returns(String)
17
+ end
18
+ def self.serialize_type_variable(type, variance, fixed, upper, lower)
19
+ variance = nil if variance == :invariant
20
+
21
+ bounds = []
22
+ bounds << "fixed: #{fixed}" if fixed
23
+ bounds << "lower: #{lower}" if lower
24
+ bounds << "upper: #{upper}" if upper
25
+
26
+ parameters = []
27
+ block = []
28
+
29
+ parameters << ":#{variance}" if variance
30
+
31
+ if sorbet_supports?(:type_variable_block_syntax)
32
+ block = bounds
33
+ else
34
+ parameters.concat(bounds)
35
+ end
36
+
37
+ serialized = type.dup
38
+ serialized << "(#{parameters.join(", ")})" unless parameters.empty?
39
+ serialized << " { { #{block.join(", ")} } }" unless block.empty?
40
+ serialized
41
+ end
42
+ end
43
+ end
@@ -6,14 +6,15 @@ require "tapioca/runtime/reflection"
6
6
  require "tapioca/runtime/trackers"
7
7
  require "tapioca/runtime/dynamic_mixin_compiler"
8
8
  require "tapioca/runtime/loader"
9
+ require "tapioca/helpers/sorbet_helper"
10
+ require "tapioca/helpers/type_variable_helper"
9
11
  require "tapioca/sorbet_ext/generic_name_patch"
10
12
  require "tapioca/sorbet_ext/fixed_hash_patch"
11
13
  require "tapioca/runtime/generic_type_registry"
12
14
  require "tapioca/helpers/cli_helper"
13
15
  require "tapioca/helpers/config_helper"
14
- require "tapioca/helpers/rbi_helper"
16
+ require "tapioca/helpers/signatures_helper"
15
17
  require "tapioca/helpers/shims_helper"
16
- require "tapioca/helpers/sorbet_helper"
17
18
  require "tapioca/commands"
18
19
  require "tapioca/cli"
19
20
  require "tapioca/gemfile"
@@ -61,8 +61,18 @@ module RBI
61
61
  create_node(RBI::MixesInClassMethods.new(name))
62
62
  end
63
63
 
64
- sig { params(name: String, value: String).void }
65
- def create_type_member(name, value: "type_member")
64
+ sig do
65
+ params(
66
+ name: String,
67
+ type: String,
68
+ variance: Symbol,
69
+ fixed: T.nilable(String),
70
+ upper: T.nilable(String),
71
+ lower: T.nilable(String)
72
+ ).void
73
+ end
74
+ def create_type_variable(name, type:, variance: :invariant, fixed: nil, upper: nil, lower: nil)
75
+ value = Tapioca::TypeVariableHelper.serialize_type_variable(type, variance, fixed, upper, lower)
66
76
  create_node(RBI::TypeMember.new(name, value))
67
77
  end
68
78
 
@@ -111,8 +111,10 @@ module Tapioca
111
111
  constant.clone
112
112
  end
113
113
 
114
- # Let's set the `name` method to return the proper generic name
115
- generic_type.define_singleton_method(:name) { name }
114
+ # Let's set the `name` and `to_s` methods to return the proper generic name
115
+ name_proc = -> { name }
116
+ generic_type.define_singleton_method(:name, name_proc)
117
+ generic_type.define_singleton_method(:to_s, name_proc)
116
118
 
117
119
  # We need to define a `<=` method on the cloned constant, so that Sorbet
118
120
  # can do covariance/contravariance checks on the type variables.
@@ -140,7 +140,11 @@ module Tapioca
140
140
  #
141
141
  # class D < C; end
142
142
  # descendants_of(C) # => [B, A, D]
143
- sig { type_parameters(:U).params(klass: T.type_parameter(:U)).returns(T::Array[T.type_parameter(:U)]) }
143
+ sig do
144
+ type_parameters(:U)
145
+ .params(klass: T.all(Class, T.type_parameter(:U)))
146
+ .returns(T::Array[T.type_parameter(:U)])
147
+ end
144
148
  def descendants_of(klass)
145
149
  result = ObjectSpace.each_object(klass.singleton_class).reject do |k|
146
150
  T.cast(k, Module).singleton_class? || T.unsafe(k) == klass
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "tapioca/sorbet_ext/name_patch"
5
+ require "tapioca/helpers/sorbet_helper"
5
6
 
6
7
  module T
7
8
  module Generic
@@ -20,7 +21,7 @@ module T
20
21
  Tapioca::Runtime::GenericTypeRegistry.register_type(constant, types)
21
22
  end
22
23
 
23
- def type_member(variance = :invariant, fixed: nil, lower: T.untyped, upper: BasicObject)
24
+ def type_member(variance = :invariant, fixed: nil, lower: nil, upper: nil, &bounds_proc)
24
25
  # `T::Generic#type_member` just instantiates a `T::Type::TypeMember` instance and returns it.
25
26
  # We use that when registering the type member and then later return it from this method.
26
27
  Tapioca::TypeVariableModule.new(
@@ -29,13 +30,14 @@ module T
29
30
  variance,
30
31
  fixed,
31
32
  lower,
32
- upper
33
+ upper,
34
+ bounds_proc
33
35
  ).tap do |type_variable|
34
36
  Tapioca::Runtime::GenericTypeRegistry.register_type_variable(self, type_variable)
35
37
  end
36
38
  end
37
39
 
38
- def type_template(variance = :invariant, fixed: nil, lower: T.untyped, upper: BasicObject)
40
+ def type_template(variance = :invariant, fixed: nil, lower: nil, upper: nil, &bounds_proc)
39
41
  # `T::Generic#type_template` just instantiates a `T::Type::TypeTemplate` instance and returns it.
40
42
  # We use that when registering the type template and then later return it from this method.
41
43
  Tapioca::TypeVariableModule.new(
@@ -44,7 +46,8 @@ module T
44
46
  variance,
45
47
  fixed,
46
48
  lower,
47
- upper
49
+ upper,
50
+ bounds_proc
48
51
  ).tap do |type_variable|
49
52
  Tapioca::Runtime::GenericTypeRegistry.register_type_variable(self, type_variable)
50
53
  end
@@ -119,18 +122,31 @@ module Tapioca
119
122
  end
120
123
  end
121
124
 
125
+ # rubocop:disable Metrics/ParameterLists
122
126
  sig do
123
- params(context: Module, type: Type, variance: Symbol, fixed: T.untyped, lower: T.untyped, upper: T.untyped).void
127
+ params(
128
+ context: Module,
129
+ type: Type,
130
+ variance: Symbol,
131
+ fixed: T.untyped,
132
+ lower: T.untyped,
133
+ upper: T.untyped,
134
+ bounds_proc: T.nilable(T.proc.returns(T::Hash[Symbol, T.untyped]))
135
+ ).void
124
136
  end
125
- def initialize(context, type, variance, fixed, lower, upper) # rubocop:disable Metrics/ParameterLists
137
+ def initialize(context, type, variance, fixed, lower, upper, bounds_proc)
126
138
  @context = context
127
139
  @type = type
128
140
  @variance = variance
129
- @fixed = fixed
130
- @lower = lower
131
- @upper = upper
141
+ @bounds_proc = if bounds_proc
142
+ bounds_proc
143
+ else
144
+ build_bounds_proc(fixed, lower, upper)
145
+ end
146
+
132
147
  super()
133
148
  end
149
+ # rubocop:enable Metrics/ParameterLists
134
150
 
135
151
  sig { returns(T.nilable(String)) }
136
152
  def name
@@ -153,17 +169,18 @@ module Tapioca
153
169
 
154
170
  sig { returns(String) }
155
171
  def serialize
156
- parts = []
157
- parts << ":#{@variance}" unless @variance == :invariant
158
- parts << "fixed: #{@fixed}" if @fixed
159
- parts << "lower: #{@lower}" unless @lower == T.untyped
160
- parts << "upper: #{@upper}" unless @upper == BasicObject
161
-
162
- parameters = parts.join(", ")
163
-
164
- serialized = @type.serialize.dup
165
- serialized << "(#{parameters})" unless parameters.empty?
166
- serialized
172
+ bounds = @bounds_proc.call
173
+ fixed = bounds[:fixed].to_s if bounds.key?(:fixed)
174
+ lower = bounds[:lower].to_s if bounds.key?(:lower)
175
+ upper = bounds[:upper].to_s if bounds.key?(:upper)
176
+
177
+ TypeVariableHelper.serialize_type_variable(
178
+ @type.serialize,
179
+ @variance,
180
+ fixed,
181
+ upper,
182
+ lower
183
+ )
167
184
  end
168
185
 
169
186
  sig { returns(Tapioca::TypeVariable) }
@@ -173,6 +190,19 @@ module Tapioca
173
190
 
174
191
  private
175
192
 
193
+ sig do
194
+ params(fixed: T.untyped, lower: T.untyped, upper: T.untyped)
195
+ .returns(T.proc.returns(T::Hash[Symbol, T.untyped]))
196
+ end
197
+ def build_bounds_proc(fixed, lower, upper)
198
+ bounds = {}
199
+ bounds[:fixed] = fixed unless fixed.nil?
200
+ bounds[:lower] = lower unless lower.nil?
201
+ bounds[:upper] = upper unless upper.nil?
202
+
203
+ -> { bounds }
204
+ end
205
+
176
206
  sig do
177
207
  type_parameters(:Result)
178
208
  .params(block: T.proc.returns(T.type_parameter(:Result)))
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.7.0"
5
+ VERSION = "0.7.3"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tapioca
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ufuk Kayserilioglu
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2022-02-17 00:00:00.000000000 Z
14
+ date: 2022-05-30 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -50,7 +50,7 @@ dependencies:
50
50
  version: 0.0.0
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: 0.0.12
53
+ version: 0.0.14
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -60,7 +60,7 @@ dependencies:
60
60
  version: 0.0.0
61
61
  - - ">="
62
62
  - !ruby/object:Gem::Version
63
- version: 0.0.12
63
+ version: 0.0.14
64
64
  - !ruby/object:Gem::Dependency
65
65
  name: sorbet-runtime
66
66
  requirement: !ruby/object:Gem::Requirement
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: 1.1.0
99
99
  - - ">="
100
100
  - !ruby/object:Gem::Version
101
- version: 1.1.4
101
+ version: 1.1.11
102
102
  type: :runtime
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -108,7 +108,7 @@ dependencies:
108
108
  version: 1.1.0
109
109
  - - ">="
110
110
  - !ruby/object:Gem::Version
111
- version: 1.1.4
111
+ version: 1.1.11
112
112
  - !ruby/object:Gem::Dependency
113
113
  name: thor
114
114
  requirement: !ruby/object:Gem::Requirement
@@ -212,13 +212,14 @@ files:
212
212
  - lib/tapioca/gemfile.rb
213
213
  - lib/tapioca/helpers/cli_helper.rb
214
214
  - lib/tapioca/helpers/config_helper.rb
215
- - lib/tapioca/helpers/rbi_helper.rb
216
215
  - lib/tapioca/helpers/shims_helper.rb
216
+ - lib/tapioca/helpers/signatures_helper.rb
217
217
  - lib/tapioca/helpers/sorbet_helper.rb
218
218
  - lib/tapioca/helpers/test/content.rb
219
219
  - lib/tapioca/helpers/test/dsl_compiler.rb
220
220
  - lib/tapioca/helpers/test/isolation.rb
221
221
  - lib/tapioca/helpers/test/template.rb
222
+ - lib/tapioca/helpers/type_variable_helper.rb
222
223
  - lib/tapioca/internal.rb
223
224
  - lib/tapioca/rbi_ext/model.rb
224
225
  - lib/tapioca/rbi_formatter.rb