tapioca 0.7.0 → 0.7.3

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.
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