tapioca 0.13.3 → 0.14.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: feabe451c23d5c95ab011b2996a0f53daee19e20d7bf7075aeb4da7fa812f9a5
4
- data.tar.gz: 1a47b4e7a3942786a0fd064c8c49bb02aae2f79f23bf22a2933a6608ba68ca5e
3
+ metadata.gz: 469c53709eb6cb5de25abc9526d40c8dff3b852bf218bcbbc966078271754bfd
4
+ data.tar.gz: fbc47526d02ef8fea90ad262007865ee56ab56a72dc5832c375540f42a3d9e11
5
5
  SHA512:
6
- metadata.gz: 982979631a9a78a2f6b589be02f2064b94fd6b95675316a2bd2271a21f2366af752c994ade6194d412f5bbabf5666623416e728d2c4d56dd336d5b17d8803f03
7
- data.tar.gz: 1fb7b58f1f361a5a05d25a7dfad6b491efc65c084be0c3e293755e81192ac8e25c8477b1f6f75c12fe0740cf8e8ed38921e5e314b63f54efb7189aa9edd03cd3
6
+ metadata.gz: f64c8009bf0e0d5a4b11595cc0bf9c72c5aca3fee4bcae7da5b036009dc0e27c9c5fc2d921564f9664aef0f2b1a648000e3228902d3d2a8b13338af85773d48e
7
+ data.tar.gz: b751f2a0618927d616edebad5841333af85cb5c7d773bd8904c119d521ab871a65b3405c72efe56426faccdada8b32204f2e5a56cde3ddc4f067884270f106b4
data/README.md CHANGED
@@ -500,6 +500,7 @@ Options:
500
500
  # Default: .
501
501
  [--halt-upon-load-error], [--no-halt-upon-load-error], [--skip-halt-upon-load-error] # Halt upon a load error while loading the Rails application
502
502
  # Default: true
503
+ [--skip-constant=constant [constant ...]] # Do not generate RBI definitions for the given application constant(s)
503
504
  -c, [--config=<config file path>] # Path to the Tapioca configuration file
504
505
  # Default: sorbet/tapioca/config.yml
505
506
  -V, [--verbose], [--no-verbose], [--skip-verbose] # Verbose output for debugging purposes
@@ -885,7 +886,7 @@ Check duplicated definitions in shim RBIs
885
886
  ```
886
887
  <!-- END_HELP_COMMAND_CHECK_SHIMS -->
887
888
 
888
- Depending on the amount of meta-programming used in your project this can mean an overwhelming amount of manual work. In this case, you should consider [writting a custom DSL compiler](#writing-custom-dsl-compilers).
889
+ Depending on the amount of meta-programming used in your project this can mean an overwhelming amount of manual work. In this case, you should consider [writing a custom DSL compiler](#writing-custom-dsl-compilers).
889
890
 
890
891
  ### Configuration
891
892
 
@@ -933,6 +934,7 @@ dsl:
933
934
  list_compilers: false
934
935
  app_root: "."
935
936
  halt_upon_load_error: true
937
+ skip_constant: []
936
938
  gem:
937
939
  outdir: sorbet/rbi/gems
938
940
  file_header: true
data/lib/tapioca/cli.rb CHANGED
@@ -135,6 +135,11 @@ module Tapioca
135
135
  type: :boolean,
136
136
  desc: "Halt upon a load error while loading the Rails application",
137
137
  default: true
138
+ option :skip_constant,
139
+ type: :array,
140
+ banner: "constant [constant ...]",
141
+ desc: "Do not generate RBI definitions for the given application constant(s)",
142
+ default: []
138
143
  def dsl(*constant_or_paths)
139
144
  set_environment(options)
140
145
 
@@ -149,6 +154,7 @@ module Tapioca
149
154
  exclude: options[:exclude],
150
155
  file_header: options[:file_header],
151
156
  tapioca_path: TAPIOCA_DIR,
157
+ skip_constant: options[:skip_constant],
152
158
  quiet: options[:quiet],
153
159
  verbose: options[:verbose],
154
160
  number_of_workers: options[:workers],
@@ -18,6 +18,7 @@ module Tapioca
18
18
  exclude: T::Array[String],
19
19
  file_header: T::Boolean,
20
20
  tapioca_path: String,
21
+ skip_constant: T::Array[String],
21
22
  quiet: T::Boolean,
22
23
  verbose: T::Boolean,
23
24
  number_of_workers: T.nilable(Integer),
@@ -36,6 +37,7 @@ module Tapioca
36
37
  exclude:,
37
38
  file_header:,
38
39
  tapioca_path:,
40
+ skip_constant: [],
39
41
  quiet: false,
40
42
  verbose: false,
41
43
  number_of_workers: nil,
@@ -60,6 +62,7 @@ module Tapioca
60
62
  @rbi_formatter = rbi_formatter
61
63
  @app_root = app_root
62
64
  @halt_upon_load_error = halt_upon_load_error
65
+ @skip_constant = skip_constant
63
66
 
64
67
  super()
65
68
  end
@@ -124,6 +127,7 @@ module Tapioca
124
127
  error_handler: ->(error) {
125
128
  say_error(error, :bold, :red)
126
129
  },
130
+ skipped_constants: constantize(@skip_constant),
127
131
  number_of_workers: @number_of_workers,
128
132
  )
129
133
  end
@@ -81,7 +81,7 @@ module Tapioca
81
81
  # Create helper method module
82
82
  controller.create_module(helper_methods_name) do |helper_methods|
83
83
  # If the controller has no helper defined, then it just inherits
84
- # the Action Controlller base helper methods module, so we should
84
+ # the Action Controller base helper methods module, so we should
85
85
  # just add that as an include and stop doing more processing.
86
86
  if helpers_module.name == "ActionController::Base::HelperMethods"
87
87
  next helper_methods.create_include(T.must(qualified_name_of(helpers_module)))
@@ -66,7 +66,7 @@ module Tapioca
66
66
  # pre Rails 6.0, this used to be a single static module
67
67
  [ActiveModel::SecurePassword::InstanceMethodsOnActivation]
68
68
  else
69
- # post Rails 6.0, this is now using a dynmaic module builder pattern
69
+ # post Rails 6.0, this is now using a dynamic module builder pattern
70
70
  # and we can have multiple different ones included into the model
71
71
  constant.ancestors.grep(ActiveModel::SecurePassword::InstanceMethodsOnActivation)
72
72
  end
@@ -92,6 +92,12 @@ module Tapioca
92
92
  #
93
93
  # sig { returns(T.nilable(::Category)) }
94
94
  # def reload_category; end
95
+ #
96
+ # sig { void }
97
+ # def reset_author; end
98
+ #
99
+ # sig { void }
100
+ # def reset_category; end
95
101
  # end
96
102
  # end
97
103
  # ~~~
@@ -196,6 +202,10 @@ module Tapioca
196
202
  "reload_#{association_name}",
197
203
  return_type: association_type,
198
204
  )
205
+ klass.create_method(
206
+ "reset_#{association_name}",
207
+ return_type: "void",
208
+ )
199
209
  unless reflection.polymorphic?
200
210
  klass.create_method(
201
211
  "build_#{association_name}",
@@ -1,7 +1,9 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- return unless defined?(Rails) && defined?(ActiveSupport::TestCase) && defined?(ActiveRecord::TestFixtures)
4
+ return unless defined?(Rails) &&
5
+ defined?(ActiveSupport::TestCase) &&
6
+ defined?(ActiveRecord::TestFixtures)
5
7
 
6
8
  module Tapioca
7
9
  module Dsl
@@ -24,8 +26,10 @@ module Tapioca
24
26
  # # test_case.rbi
25
27
  # # typed: true
26
28
  # class ActiveSupport::TestCase
27
- # sig { params(fixture_names: T.any(String, Symbol)).returns(T.untyped) }
28
- # def posts(*fixture_names); end
29
+ # sig { params(fixture_name: T.any(String, Symbol), other_fixtures: NilClass).returns(Post) }
30
+ # sig { params(fixture_name: T.any(String, Symbol), other_fixtures: T.any(String, Symbol))
31
+ # .returns(T::Array[Post]) }
32
+ # def posts(fixture_name, *other_fixtures); end
29
33
  # end
30
34
  # ~~~
31
35
  class ActiveRecordFixtures < Compiler
@@ -104,10 +108,90 @@ module Tapioca
104
108
 
105
109
  sig { params(mod: RBI::Scope, name: String).void }
106
110
  def create_fixture_method(mod, name)
107
- mod.create_method(
108
- name,
109
- parameters: [create_rest_param("fixture_names", type: "T.any(String, Symbol)")],
110
- return_type: "T.untyped",
111
+ return_type = return_type_for_fixture(name)
112
+ mod << RBI::Method.new(name) do |node|
113
+ node.add_param("fixture_name")
114
+ node.add_rest_param("other_fixtures")
115
+
116
+ node.add_sig do |sig|
117
+ sig.add_param("fixture_name", "T.any(String, Symbol)")
118
+ sig.add_param("other_fixtures", "NilClass")
119
+ sig.return_type = return_type
120
+ end
121
+
122
+ node.add_sig do |sig|
123
+ sig.add_param("fixture_name", "T.any(String, Symbol)")
124
+ sig.add_param("other_fixtures", "T.any(String, Symbol)")
125
+ sig.return_type = "T::Array[#{return_type}]"
126
+ end
127
+ end
128
+ end
129
+
130
+ sig { params(fixture_name: String).returns(String) }
131
+ def return_type_for_fixture(fixture_name)
132
+ fixture_class_mapping_from_fixture_files[fixture_name] ||
133
+ fixture_class_from_fixture_set(fixture_name) ||
134
+ fixture_class_from_active_record_base_class_mapping[fixture_name] ||
135
+ "T.untyped"
136
+ end
137
+
138
+ sig { params(fixture_name: String).returns(T.nilable(String)) }
139
+ def fixture_class_from_fixture_set(fixture_name)
140
+ # only rails 7.1+ support fixture sets so this is conditional
141
+ return unless fixture_loader.respond_to?(:fixture_sets)
142
+
143
+ model_name_from_fixture_set = T.unsafe(fixture_loader).fixture_sets[fixture_name]
144
+ return unless model_name_from_fixture_set
145
+
146
+ model_name = ActiveRecord::FixtureSet.default_fixture_model_name(model_name_from_fixture_set)
147
+ return unless Object.const_defined?(model_name)
148
+
149
+ model_name
150
+ end
151
+
152
+ sig { returns(T::Hash[String, String]) }
153
+ def fixture_class_from_active_record_base_class_mapping
154
+ @fixture_class_mapping ||= T.let(
155
+ begin
156
+ ActiveRecord::Base.descendants.each_with_object({}) do |model_class, mapping|
157
+ class_name = model_class.name
158
+
159
+ fixture_name = class_name.underscore.gsub("/", "_")
160
+ fixture_name = fixture_name.pluralize if ActiveRecord::Base.pluralize_table_names
161
+
162
+ mapping[fixture_name] = class_name
163
+
164
+ mapping
165
+ end
166
+ end,
167
+ T.nilable(T::Hash[String, String]),
168
+ )
169
+ end
170
+
171
+ sig { returns(T::Hash[String, String]) }
172
+ def fixture_class_mapping_from_fixture_files
173
+ @fixture_file_class_mapping ||= T.let(
174
+ begin
175
+ fixture_paths = if T.unsafe(fixture_loader).respond_to?(:fixture_paths)
176
+ T.unsafe(fixture_loader).fixture_paths
177
+ else
178
+ T.unsafe(fixture_loader).fixture_path
179
+ end
180
+
181
+ Array(fixture_paths).each_with_object({}) do |path, mapping|
182
+ Dir["#{path}{.yml,/{**,*}/*.yml}"].select do |file|
183
+ next unless ::File.file?(file)
184
+
185
+ ActiveRecord::FixtureSet::File.open(file) do |fh|
186
+ next unless fh.model_class
187
+
188
+ fixture_name = file.delete_prefix(path.to_s).delete_prefix("/").delete_suffix(".yml")
189
+ mapping[fixture_name] = fh.model_class
190
+ end
191
+ end
192
+ end
193
+ end,
194
+ T.nilable(T::Hash[String, String]),
111
195
  )
112
196
  end
113
197
  end
@@ -3,6 +3,7 @@
3
3
 
4
4
  return unless defined?(ActiveRecord::Base)
5
5
 
6
+ require "tapioca/dsl/helpers/active_model_type_helper"
6
7
  require "tapioca/dsl/helpers/active_record_constants_helper"
7
8
 
8
9
  module Tapioca
@@ -24,15 +25,15 @@ module Tapioca
24
25
  # 1. A `Model::PrivateRelation` that subclasses `ActiveRecord::Relation`. This synthetic class represents
25
26
  # a relation on `Model` whose methods which return a relation always return a `Model::PrivateRelation` instance.
26
27
  #
27
- # 2. `Model::PrivateAssocationRelation` that subclasses `ActiveRecord::AssociationRelation`. This synthetic
28
+ # 2. `Model::PrivateAssociationRelation` that subclasses `ActiveRecord::AssociationRelation`. This synthetic
28
29
  # class represents a relation on a singular association of type `Model` (e.g. `foo.model`) whose methods which
29
- # return a relation will always return a `Model::PrivateAssocationRelation` instance. The difference between this
30
+ # return a relation will always return a `Model::PrivateAssociationRelation` instance. The difference between this
30
31
  # class and the previous one is mainly that an association relation also keeps track of the resource association
31
32
  # for this relation.
32
33
  #
33
34
  # 3. `Model::PrivateCollectionProxy` that subclasses from `ActiveRecord::Associations::CollectionProxy`.
34
35
  # This synthetic class represents a relation on a plural association of type `Model` (e.g. `foo.models`)
35
- # whose methods which return a relation will always return a `Model::PrivateAssocationRelation` instance.
36
+ # whose methods which return a relation will always return a `Model::PrivateAssociationRelation` instance.
36
37
  # This class represents a collection of `Model` instances with some extra methods to `build`, `create`,
37
38
  # etc new `Model` instances in the collection.
38
39
  #
@@ -364,7 +365,8 @@ module Tapioca
364
365
  parameters: [
365
366
  create_param("column_name", type: "T.any(String, Symbol)"),
366
367
  ],
367
- return_type: "T::Hash[T.untyped, #{method_name == :average ? "Numeric" : "T.untyped"}]",
368
+ return_type: "T::Hash[T.untyped, " \
369
+ "#{method_name == :average ? "T.any(Integer, Float, BigDecimal)" : "T.untyped"}]",
368
370
  )
369
371
  when :calculate
370
372
  klass.create_method(
@@ -373,7 +375,7 @@ module Tapioca
373
375
  create_param("operation", type: "Symbol"),
374
376
  create_param("column_name", type: "T.any(String, Symbol)"),
375
377
  ],
376
- return_type: "T::Hash[T.untyped, Numeric]",
378
+ return_type: "T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]",
377
379
  )
378
380
  when :count
379
381
  klass.create_method(
@@ -390,7 +392,7 @@ module Tapioca
390
392
  create_opt_param("column_name", type: "T.nilable(T.any(String, Symbol))", default: "nil"),
391
393
  create_block_param("block", type: "T.nilable(T.proc.params(record: T.untyped).returns(T.untyped))"),
392
394
  ],
393
- return_type: "T::Hash[T.untyped, Numeric]",
395
+ return_type: "T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]",
394
396
  )
395
397
  end
396
398
  end
@@ -560,6 +562,11 @@ module Tapioca
560
562
 
561
563
  QUERY_METHODS.each do |method_name|
562
564
  case method_name
565
+ when :distinct
566
+ create_relation_method(
567
+ method_name.to_s,
568
+ parameters: [create_opt_param("value", type: "T::Boolean", default: "true")],
569
+ )
563
570
  when :extract_associated
564
571
  parameters = [create_param("association", type: "Symbol")]
565
572
  return_type = "T::Array[T.untyped]"
@@ -657,9 +664,30 @@ module Tapioca
657
664
  )
658
665
  when :find
659
666
  # From ActiveRecord::ConnectionAdapter::Quoting#quote, minus nil
660
- id_types = "T.any(String, Symbol, ::ActiveSupport::Multibyte::Chars, T::Boolean, BigDecimal, Numeric, " \
661
- "::ActiveRecord::Type::Binary::Data, ::ActiveRecord::Type::Time::Value, Date, Time, " \
662
- "::ActiveSupport::Duration, T::Class[T.anything])"
667
+ id_types = [
668
+ "String",
669
+ "Symbol",
670
+ "::ActiveSupport::Multibyte::Chars",
671
+ "T::Boolean",
672
+ "BigDecimal",
673
+ "Numeric",
674
+ "::ActiveRecord::Type::Binary::Data",
675
+ "::ActiveRecord::Type::Time::Value",
676
+ "Date",
677
+ "Time",
678
+ "::ActiveSupport::Duration",
679
+ "T::Class[T.anything]",
680
+ ].to_set
681
+
682
+ if constant.table_exists?
683
+ primary_key_type = constant.type_for_attribute(constant.primary_key)
684
+ type = Tapioca::Dsl::Helpers::ActiveModelTypeHelper.type_for(primary_key_type)
685
+ type = RBIHelper.as_non_nilable_type(type)
686
+ id_types << type if type != "T.untyped"
687
+ end
688
+
689
+ id_types = "T.any(#{id_types.to_a.join(", ")})"
690
+
663
691
  array_type = if constant.try(:composite_primary_key?)
664
692
  "T::Array[T::Array[#{id_types}]]"
665
693
  else
@@ -781,7 +809,7 @@ module Tapioca
781
809
  parameters: [
782
810
  create_param("column_name", type: "T.any(String, Symbol)"),
783
811
  ],
784
- return_type: method_name == :average ? "Numeric" : "T.untyped",
812
+ return_type: method_name == :average ? "T.any(Integer, Float, BigDecimal)" : "T.untyped",
785
813
  )
786
814
  when :calculate
787
815
  create_common_method(
@@ -790,7 +818,7 @@ module Tapioca
790
818
  create_param("operation", type: "Symbol"),
791
819
  create_param("column_name", type: "T.any(String, Symbol)"),
792
820
  ],
793
- return_type: "Numeric",
821
+ return_type: "T.any(Integer, Float, BigDecimal)",
794
822
  )
795
823
  when :count
796
824
  sigs = [
@@ -822,13 +850,28 @@ module Tapioca
822
850
  return_type: "T.untyped",
823
851
  )
824
852
  when :sum
825
- create_common_method(
826
- "sum",
853
+ sigs = [
854
+ common_relation_methods_module.create_sig(
855
+ parameters: { initial_value_or_column: "T.untyped" },
856
+ return_type: "T.any(Integer, Float, BigDecimal)",
857
+ ),
858
+ common_relation_methods_module.create_sig(
859
+ type_parameters: ["U"],
860
+ parameters:
861
+ {
862
+ initial_value_or_column: "T.nilable(T.type_parameter(:U))",
863
+ block: "T.proc.params(object: #{constant_name}).returns(T.type_parameter(:U))",
864
+ },
865
+ return_type: "T.type_parameter(:U)",
866
+ ),
867
+ ]
868
+ common_relation_methods_module.create_method_with_sigs(
869
+ method_name.to_s,
870
+ sigs: sigs,
827
871
  parameters: [
828
- create_opt_param("column_name", type: "T.nilable(T.any(String, Symbol))", default: "nil"),
829
- create_block_param("block", type: "T.nilable(T.proc.params(record: T.untyped).returns(T.untyped))"),
872
+ RBI::OptParam.new("initial_value_or_column", "nil"),
873
+ RBI::BlockParam.new("block"),
830
874
  ],
831
- return_type: "Numeric",
832
875
  )
833
876
  end
834
877
  end
@@ -55,7 +55,7 @@ module Tapioca
55
55
  # sig { returns(T.nilable([T.nilable(Date), T.nilable(Date)])) }
56
56
  # def saved_change_to_review_date; end
57
57
  #
58
- # sig { params(reviewd: T::Boolean).returns(T::Boolean) }
58
+ # sig { params(reviewed: T::Boolean).returns(T::Boolean) }
59
59
  # def reviewed=(reviewed); end
60
60
  #
61
61
  # sig { returns(T::Boolean) }
@@ -66,7 +66,7 @@ module Tapioca
66
66
  root.create_constant(config_constant_name, value: "T.let(T.unsafe(nil), #{option_class_name})")
67
67
 
68
68
  root.create_class(option_class_name, superclass_name: "::Config::Options") do |mod|
69
- # We need this to be generic only becuase `Config::Options` is an
69
+ # We need this to be generic only because `Config::Options` is an
70
70
  # enumerable and, thus, needs to redeclare the `Elem` type member.
71
71
  #
72
72
  # We declare it as a fixed member of `T.untyped` so that if anyone
@@ -239,7 +239,7 @@ module Tapioca
239
239
  return false unless descriptor.label == :repeated
240
240
 
241
241
  # Try to create a new instance with the field that maps to the descriptor name
242
- # being assinged a hash value. If this goes through, then it's a map type.
242
+ # being assigned a hash value. If this goes through, then it's a map type.
243
243
  constant.new(**{ descriptor.name => {} })
244
244
  true
245
245
  rescue ArgumentError
@@ -15,6 +15,9 @@ module Tapioca
15
15
  sig { returns(T::Array[Pathname]) }
16
16
  attr_reader :requested_paths
17
17
 
18
+ sig { returns(T::Array[Module]) }
19
+ attr_reader :skipped_constants
20
+
18
21
  sig { returns(T.proc.params(error: String).void) }
19
22
  attr_reader :error_handler
20
23
 
@@ -28,6 +31,7 @@ module Tapioca
28
31
  requested_compilers: T::Array[T.class_of(Compiler)],
29
32
  excluded_compilers: T::Array[T.class_of(Compiler)],
30
33
  error_handler: T.proc.params(error: String).void,
34
+ skipped_constants: T::Array[Module],
31
35
  number_of_workers: T.nilable(Integer),
32
36
  ).void
33
37
  end
@@ -37,6 +41,7 @@ module Tapioca
37
41
  requested_compilers: [],
38
42
  excluded_compilers: [],
39
43
  error_handler: $stderr.method(:puts).to_proc,
44
+ skipped_constants: [],
40
45
  number_of_workers: nil
41
46
  )
42
47
  @active_compilers = T.let(
@@ -46,6 +51,7 @@ module Tapioca
46
51
  @requested_constants = requested_constants
47
52
  @requested_paths = requested_paths
48
53
  @error_handler = error_handler
54
+ @skipped_constants = skipped_constants
49
55
  @number_of_workers = number_of_workers
50
56
  @errors = T.let([], T::Array[String])
51
57
  end
@@ -56,7 +62,7 @@ module Tapioca
56
62
  ).returns(T::Array[T.type_parameter(:T)])
57
63
  end
58
64
  def run(&blk)
59
- constants_to_process = gather_constants(requested_constants, requested_paths)
65
+ constants_to_process = gather_constants(requested_constants, requested_paths, skipped_constants)
60
66
  .select { |c| Module === c } # Filter value constants out
61
67
  .sort_by! { |c| T.must(Runtime::Reflection.name_of(c)) }
62
68
 
@@ -128,15 +134,30 @@ module Tapioca
128
134
  active_compilers
129
135
  end
130
136
 
131
- sig { params(requested_constants: T::Array[Module], requested_paths: T::Array[Pathname]).returns(T::Set[Module]) }
132
- def gather_constants(requested_constants, requested_paths)
137
+ sig do
138
+ params(
139
+ requested_constants: T::Array[Module],
140
+ requested_paths: T::Array[Pathname],
141
+ skipped_constants: T::Array[Module],
142
+ ).returns(T::Set[Module])
143
+ end
144
+ def gather_constants(requested_constants, requested_paths, skipped_constants)
133
145
  constants = Set.new.compare_by_identity
134
146
  active_compilers.each do |compiler|
135
147
  constants.merge(compiler.processable_constants)
136
148
  end
137
149
  constants = filter_anonymous_and_reloaded_constants(constants)
150
+ constants -= skipped_constants
138
151
 
139
- constants &= requested_constants unless requested_constants.empty? && requested_paths.empty?
152
+ unless requested_constants.empty? && requested_paths.empty?
153
+ constants &= requested_constants
154
+
155
+ requested_and_skipped = requested_constants & skipped_constants
156
+ if requested_and_skipped.any?
157
+ $stderr.puts("WARNING: Requested constants are being skipped due to configuration:" \
158
+ "#{requested_and_skipped}. Check the supplied arguments and your `sorbet/tapioca/config.yml` file.")
159
+ end
160
+ end
140
161
  constants
141
162
  end
142
163
 
@@ -96,6 +96,15 @@ module Tapioca
96
96
  end
97
97
  end
98
98
 
99
+ sig { params(type: String).returns(String) }
100
+ def as_non_nilable_type(type)
101
+ if type.match(/\A(?:::)?T.nilable\((.+)\)\z/)
102
+ T.must(::Regexp.last_match(1))
103
+ else
104
+ type
105
+ end
106
+ end
107
+
99
108
  sig { params(name: String).returns(T::Boolean) }
100
109
  def valid_method_name?(name)
101
110
  # try to parse a method definition with this name
@@ -4,6 +4,7 @@
4
4
  require "tapioca/helpers/test/content"
5
5
  require "tapioca/helpers/test/isolation"
6
6
  require "tapioca/helpers/test/template"
7
+ require "tapioca/helpers/sorbet_helper"
7
8
 
8
9
  module Tapioca
9
10
  module Helpers
@@ -53,6 +54,8 @@ module Tapioca
53
54
  class CompilerContext
54
55
  extend T::Sig
55
56
 
57
+ include SorbetHelper
58
+
56
59
  sig { returns(T.class_of(Tapioca::Dsl::Compiler)) }
57
60
  attr_reader :compiler_class
58
61
 
@@ -95,7 +98,26 @@ module Tapioca
95
98
  compiler = compiler_class.new(pipeline, file.root, constant)
96
99
  compiler.decorate
97
100
 
98
- Tapioca::DEFAULT_RBI_FORMATTER.print_file(file)
101
+ rbi = Tapioca::DEFAULT_RBI_FORMATTER.print_file(file)
102
+ result = sorbet(
103
+ "--no-config",
104
+ "--stop-after",
105
+ "parser",
106
+ "-e",
107
+ "\"#{rbi}\"",
108
+ )
109
+
110
+ unless result.status
111
+ raise(SyntaxError, <<~MSG)
112
+ Expected generated RBI file for `#{constant_name}` to not have any parsing errors.
113
+
114
+ Got these parsing errors:
115
+
116
+ #{result.err}
117
+ MSG
118
+ end
119
+
120
+ rbi
99
121
  end
100
122
 
101
123
  sig { returns(T::Array[String]) }
@@ -49,8 +49,6 @@ module Tapioca
49
49
  def load_rails_application(environment_load: false, eager_load: false, app_root: ".", halt_upon_load_error: true)
50
50
  return unless File.exist?("#{app_root}/config/application.rb")
51
51
 
52
- silence_deprecations
53
-
54
52
  if environment_load
55
53
  require "./#{app_root}/config/environment"
56
54
  else
@@ -186,14 +184,6 @@ module Tapioca
186
184
  nil
187
185
  end
188
186
 
189
- sig { void }
190
- def silence_deprecations
191
- # Stop any ActiveSupport Deprecations from being reported
192
- if defined?(ActiveSupport::Deprecation)
193
- ActiveSupport::Deprecation.silenced = true
194
- end
195
- end
196
-
197
187
  sig { void }
198
188
  def eager_load_rails_app
199
189
  application = Rails.application
@@ -128,14 +128,15 @@ module RBI
128
128
  sig do
129
129
  params(
130
130
  parameters: T::Hash[T.any(String, Symbol), String],
131
+ type_parameters: T::Array[String],
131
132
  return_type: String,
132
133
  ).returns(RBI::Sig)
133
134
  end
134
- def create_sig(parameters:, return_type: "T.untyped")
135
+ def create_sig(parameters:, type_parameters: [], return_type: "T.untyped")
135
136
  params = parameters.map do |name, type|
136
137
  RBI::SigParam.new(name.to_s, type)
137
138
  end
138
- RBI::Sig.new(params: params, return_type: return_type)
139
+ RBI::Sig.new(type_params: type_parameters, params: params, return_type: return_type)
139
140
  end
140
141
 
141
142
  private
@@ -16,6 +16,8 @@ module Tapioca
16
16
  file.comments << RBI::Comment.new("DO NOT EDIT MANUALLY")
17
17
  file.comments << RBI::Comment.new("This is an autogenerated file for #{reason}.") unless reason.nil?
18
18
  file.comments << RBI::Comment.new("Please instead update this file by running `#{command}`.")
19
+ # Prevent the header from being attached to the top-level node when generating YARD docs
20
+ file.comments << RBI::BlankLine.new
19
21
  end
20
22
 
21
23
  sig { params(file: RBI::File).void }
@@ -158,7 +158,7 @@ module Tapioca
158
158
  # and the module that defines it
159
159
  owner = inherited_method.owner
160
160
 
161
- # If no one has overriden the inherited method yet, just subclass
161
+ # If no one has overridden the inherited method yet, just subclass
162
162
  return Class.new(constant) if Class == owner
163
163
 
164
164
  begin
@@ -60,7 +60,7 @@ module Tapioca
60
60
  #
61
61
  # Strings beginning with / match against the
62
62
  # prefix of these relative paths; others are
63
- # substring matchs.
63
+ # substring matches.
64
64
 
65
65
  # Matches must be against whole folder and file
66
66
  # names, so `foo` matches `/foo/bar.rb` and
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.13.3"
5
+ VERSION = "0.14.0"
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.13.3
4
+ version: 0.14.0
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: 2024-04-15 00:00:00.000000000 Z
14
+ date: 2024-05-07 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -281,14 +281,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
281
281
  requirements:
282
282
  - - ">="
283
283
  - !ruby/object:Gem::Version
284
- version: '3.0'
284
+ version: '3.1'
285
285
  required_rubygems_version: !ruby/object:Gem::Requirement
286
286
  requirements:
287
287
  - - ">="
288
288
  - !ruby/object:Gem::Version
289
289
  version: '0'
290
290
  requirements: []
291
- rubygems_version: 3.5.9
291
+ rubygems_version: 3.5.10
292
292
  signing_key:
293
293
  specification_version: 4
294
294
  summary: A Ruby Interface file generator for gems, core types and the Ruby standard