tapioca 0.4.22 → 0.4.26

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: 8e3ea6e1fb437f52cfb699c43b4c3d46115592ac09a69aec5a8d0701906f42cd
4
- data.tar.gz: 9fba45117a3f1f72ab8d3278838fb7d4a860eaa7cadc03535d99be618e8994c9
3
+ metadata.gz: 9f5e0d26fdadddd8d95b78403ee2cd71240d8d43475bffec2af018b543c2114b
4
+ data.tar.gz: '0746977c9a6501ea37011cde413597191822d3cc6e7cbd5258b65acab8ce81e0'
5
5
  SHA512:
6
- metadata.gz: 6519978a03ff03499f223d810a9f0d2bfd74e406017efb300a72fff0d95e1e08b64d2165ae1b54bad48f8767c5f831fe5f4398185282a5643224499355d7badc
7
- data.tar.gz: 28ace672d799beb84aa802fe0773e574d3a827c53e15564d643dbe04e6330d6abb11d640a06b064641781258600ce73f3b5695915caaf9ce0813679dede867b2
6
+ metadata.gz: 80cf81f29ba50819ddba39cd388aa6f59d93bf99ac02c0a596f888793191e85b48fa9537f258fcd188b73b92ceb30268eb56d1aadac2f9026b9ba101196e24b4
7
+ data.tar.gz: a78072381e07709ebc2331e6cf988510e2e7a52c4cf24c66e4fb46a08293042cfb3b86619b5176fa023ae317107f741ed668fe8684042f50e927c760aab22612
data/exe/tapioca CHANGED
@@ -5,6 +5,8 @@ require 'sorbet-runtime'
5
5
 
6
6
  begin
7
7
  T::Configuration.default_checked_level = :never
8
+ # Suppresses call validation errors
9
+ T::Configuration.call_validation_error_handler = ->(*) {}
8
10
  # Suppresses errors caused by T.cast, T.let, T.must, etc.
9
11
  T::Configuration.inline_type_error_handler = ->(*) {}
10
12
  # Suppresses errors caused by incorrect parameter ordering
@@ -19,6 +19,7 @@ module Tapioca
19
19
  #
20
20
  # ~~~rb
21
21
  # class NotifyUserJob < ActiveJob::Base
22
+ # sig { params(user: User).returns(Mail) }
22
23
  # def perform(user)
23
24
  # # ...
24
25
  # end
@@ -31,10 +32,10 @@ module Tapioca
31
32
  # # notify_user_job.rbi
32
33
  # # typed: true
33
34
  # class NotifyUserJob
34
- # sig { params(user: T.untyped).returns(NotifyUserJob) }
35
+ # sig { params(user: User).returns(T.any(NotifyUserJob, FalseClass)) }
35
36
  # def self.perform_later(user); end
36
37
  #
37
- # sig { params(user: T.untyped).returns(NotifyUserJob) }
38
+ # sig { params(user: User).returns(Mail) }
38
39
  # def self.perform_now(user); end
39
40
  # end
40
41
  # ~~~
@@ -48,16 +49,23 @@ module Tapioca
48
49
 
49
50
  method = constant.instance_method(:perform)
50
51
  parameters = compile_method_parameters_to_parlour(method)
52
+ return_type = compile_method_return_type_to_parlour(method)
51
53
 
52
- %w[perform_later perform_now].each do |name|
53
- create_method(
54
- job,
55
- name,
56
- parameters: parameters,
57
- return_type: constant.name,
58
- class_method: true
59
- )
60
- end
54
+ create_method(
55
+ job,
56
+ "perform_later",
57
+ parameters: parameters,
58
+ return_type: "T.any(#{constant.name}, FalseClass)",
59
+ class_method: true
60
+ )
61
+
62
+ create_method(
63
+ job,
64
+ "perform_now",
65
+ parameters: parameters,
66
+ return_type: return_type,
67
+ class_method: true
68
+ )
61
69
  end
62
70
  end
63
71
 
@@ -17,7 +17,7 @@ module Tapioca
17
17
 
18
18
  attr_reader(:gem, :indent)
19
19
 
20
- sig { params(gem: Gemfile::Gem, indent: Integer).void }
20
+ sig { params(gem: Gemfile::GemSpec, indent: Integer).void }
21
21
  def initialize(gem, indent = 0)
22
22
  @gem = gem
23
23
  @indent = indent
@@ -145,7 +145,15 @@ module Tapioca
145
145
  def compile_object(tree, name, value)
146
146
  return if symbol_ignored?(name)
147
147
  klass = class_of(value)
148
- klass_name = name_of(klass)
148
+
149
+ klass_name = if klass == ObjectSpace::WeakMap
150
+ # WeakMap is an implicit generic with one type variable
151
+ "ObjectSpace::WeakMap[T.untyped]"
152
+ elsif T::Generic === klass
153
+ generic_name_of(klass)
154
+ else
155
+ name_of(klass)
156
+ end
149
157
 
150
158
  if klass_name == "T::Private::Types::TypeAlias"
151
159
  tree << RBI::Const.new(name, "T.type_alias { #{T.unsafe(value).aliased_type} }")
@@ -155,8 +163,6 @@ module Tapioca
155
163
  return if klass_name&.start_with?("T::Types::", "T::Private::")
156
164
 
157
165
  type_name = klass_name || "T.untyped"
158
- # TODO: Do this in a more generic and clean way.
159
- type_name = "#{type_name}[T.untyped]" if type_name == "ObjectSpace::WeakMap"
160
166
 
161
167
  tree << RBI::Const.new(name, "T.let(T.unsafe(nil), #{type_name})")
162
168
  end
@@ -774,6 +780,19 @@ module Tapioca
774
780
  name
775
781
  end
776
782
 
783
+ sig { params(constant: T.all(Module, T::Generic)).returns(String) }
784
+ def generic_name_of(constant)
785
+ type_name = T.must(constant.name)
786
+ return type_name if type_name =~ /\[.*\]$/
787
+
788
+ type_variables = Tapioca::GenericTypeRegistry.lookup_type_variables(constant)
789
+ return type_name unless type_variables
790
+
791
+ type_variable_names = type_variables.map { "T.untyped" }.join(", ")
792
+
793
+ "#{type_name}[#{type_variable_names}]"
794
+ end
795
+
777
796
  sig { params(constant: Module).returns(T.nilable(String)) }
778
797
  def name_of_proxy_target(constant)
779
798
  klass = class_of(constant)
@@ -8,7 +8,7 @@ module Tapioca
8
8
 
9
9
  sig do
10
10
  params(
11
- gem: Gemfile::Gem,
11
+ gem: Gemfile::GemSpec,
12
12
  indent: Integer
13
13
  ).returns(String)
14
14
  end
@@ -20,7 +20,7 @@ module Tapioca
20
20
  sig { returns(Bundler::Definition) }
21
21
  attr_reader(:definition)
22
22
 
23
- sig { returns(T::Array[Gem]) }
23
+ sig { returns(T::Array[GemSpec]) }
24
24
  attr_reader(:dependencies)
25
25
 
26
26
  sig { returns(T::Array[String]) }
@@ -32,18 +32,18 @@ module Tapioca
32
32
  @lockfile = T.let(File.new(Bundler.default_lockfile), File)
33
33
  @definition = T.let(Bundler::Dsl.evaluate(gemfile, lockfile, {}), Bundler::Definition)
34
34
  dependencies, missing_specs = load_dependencies
35
- @dependencies = T.let(dependencies, T::Array[Gem])
35
+ @dependencies = T.let(dependencies, T::Array[GemSpec])
36
36
  @missing_specs = T.let(missing_specs, T::Array[String])
37
37
  end
38
38
 
39
- sig { params(gem_name: String).returns(T.nilable(Gem)) }
39
+ sig { params(gem_name: String).returns(T.nilable(GemSpec)) }
40
40
  def gem(gem_name)
41
41
  dependencies.detect { |dep| dep.name == gem_name }
42
42
  end
43
43
 
44
44
  sig { void }
45
- def require
46
- T.unsafe(runtime).setup(*groups).require(*groups)
45
+ def require_bundle
46
+ T.unsafe(runtime).require(*groups)
47
47
  end
48
48
 
49
49
  private
@@ -51,23 +51,32 @@ module Tapioca
51
51
  sig { returns(File) }
52
52
  attr_reader(:gemfile, :lockfile)
53
53
 
54
- sig { returns([T::Array[Gem], T::Array[String]]) }
54
+ sig { returns([T::Array[GemSpec], T::Array[String]]) }
55
55
  def load_dependencies
56
- deps = definition.locked_gems.dependencies.values
57
-
58
- missing_specs = T::Array[String].new
59
-
60
- dependencies = definition
61
- .resolve
62
- .materialize(deps, missing_specs)
63
- .map { |spec| Gem.new(spec) }
56
+ materialized_dependencies, missing_specs = materialize_deps
57
+ dependencies = materialized_dependencies
58
+ .map { |spec| GemSpec.new(spec) }
64
59
  .reject { |gem| gem.ignore?(dir) }
65
60
  .uniq(&:rbi_file_name)
66
61
  .sort_by(&:rbi_file_name)
67
-
68
62
  [dependencies, missing_specs]
69
63
  end
70
64
 
65
+ sig { returns([T::Array[::Gem::Specification], T::Array[String]]) }
66
+ def materialize_deps
67
+ deps = definition.locked_gems.dependencies.values
68
+ missing_specs = T::Array[String].new
69
+ materialized_dependencies = if definition.resolve.method(:materialize).arity == 1 # Support bundler >= v2.2.25
70
+ md = definition.resolve.materialize(deps)
71
+ missing_spec_names = md.missing_specs.map(&:name)
72
+ missing_specs = T.cast(md.missing_specs.map { |spec| "#{spec.name} (#{spec.version})" }, T::Array[String])
73
+ md.to_a.reject { |spec| missing_spec_names.include?(spec.name) }
74
+ else
75
+ definition.resolve.materialize(deps, missing_specs)
76
+ end
77
+ [materialized_dependencies, missing_specs]
78
+ end
79
+
71
80
  sig { returns(Bundler::Runtime) }
72
81
  def runtime
73
82
  Bundler::Runtime.new(File.dirname(gemfile.path), definition)
@@ -83,7 +92,7 @@ module Tapioca
83
92
  File.expand_path(gemfile.path + "/..")
84
93
  end
85
94
 
86
- class Gem
95
+ class GemSpec
87
96
  extend(T::Sig)
88
97
 
89
98
  IGNORED_GEMS = T.let(%w{
@@ -108,8 +117,14 @@ module Tapioca
108
117
 
109
118
  sig { returns(T::Array[Pathname]) }
110
119
  def files
111
- @spec.full_require_paths.flat_map do |path|
112
- Pathname.glob((Pathname.new(path) / "**/*.rb").to_s)
120
+ if default_gem?
121
+ @spec.files.map do |file|
122
+ ruby_lib_dir.join(file)
123
+ end
124
+ else
125
+ @spec.full_require_paths.flat_map do |path|
126
+ Pathname.glob((Pathname.new(path) / "**/*.rb").to_s)
127
+ end
113
128
  end
114
129
  end
115
130
 
@@ -125,11 +140,25 @@ module Tapioca
125
140
 
126
141
  sig { params(path: String).returns(T::Boolean) }
127
142
  def contains_path?(path)
128
- to_realpath(path).start_with?(full_gem_path) || has_parent_gemspec?(path)
143
+ if default_gem?
144
+ files.any? { |file| file.to_s == to_realpath(path) }
145
+ else
146
+ to_realpath(path).start_with?(full_gem_path) || has_parent_gemspec?(path)
147
+ end
129
148
  end
130
149
 
131
150
  private
132
151
 
152
+ sig { returns(T::Boolean) }
153
+ def default_gem?
154
+ @spec.respond_to?(:default_gem?) && @spec.default_gem?
155
+ end
156
+
157
+ sig { returns(Pathname) }
158
+ def ruby_lib_dir
159
+ Pathname.new(RbConfig::CONFIG["rubylibdir"])
160
+ end
161
+
133
162
  sig { returns(String) }
134
163
  def version_string
135
164
  version = @spec.version.to_s
@@ -260,7 +260,7 @@ module Tapioca
260
260
  def load_application(eager_load:)
261
261
  say("Loading Rails application... ")
262
262
 
263
- loader.load_rails(
263
+ loader.load_rails_application(
264
264
  environment_load: true,
265
265
  eager_load: eager_load
266
266
  )
@@ -456,7 +456,7 @@ module Tapioca
456
456
 
457
457
  sig do
458
458
  params(gem_names: T::Array[String])
459
- .returns(T::Array[Gemfile::Gem])
459
+ .returns(T::Array[Gemfile::GemSpec])
460
460
  end
461
461
  def gems_to_generate(gem_names)
462
462
  return bundle.dependencies if gem_names.empty?
@@ -486,7 +486,7 @@ module Tapioca
486
486
  [statement, sigil].compact.join("\n").strip.concat("\n\n")
487
487
  end
488
488
 
489
- sig { params(gem: Gemfile::Gem).void }
489
+ sig { params(gem: Gemfile::GemSpec).void }
490
490
  def compile_gem_rbi(gem)
491
491
  compiler = Compilers::SymbolTableCompiler.new
492
492
  gem_name = set_color(gem.name, :yellow, :bold)
@@ -6,6 +6,7 @@ require "tapioca/loader"
6
6
  require "tapioca/constant_locator"
7
7
  require "tapioca/generic_type_registry"
8
8
  require "tapioca/sorbet_ext/generic_name_patch"
9
+ require "tapioca/sorbet_ext/fixed_hash_patch"
9
10
  require "tapioca/config"
10
11
  require "tapioca/config_builder"
11
12
  require "tapioca/generator"
@@ -14,10 +14,9 @@ module Tapioca
14
14
  def load_bundle(initialize_file, require_file)
15
15
  require_helper(initialize_file)
16
16
 
17
- load_rails
18
- load_rake
17
+ gemfile.require_bundle
19
18
 
20
- require_bundle
19
+ load_rails_application
21
20
 
22
21
  require_helper(require_file)
23
22
 
@@ -25,14 +24,11 @@ module Tapioca
25
24
  end
26
25
 
27
26
  sig { params(environment_load: T::Boolean, eager_load: T::Boolean).void }
28
- def load_rails(environment_load: false, eager_load: false)
27
+ def load_rails_application(environment_load: false, eager_load: false)
29
28
  return unless File.exist?("config/application.rb")
30
29
 
31
- safe_require("rails")
32
-
33
30
  silence_deprecations
34
31
 
35
- safe_require("rails/generators/test_case")
36
32
  if environment_load
37
33
  safe_require("./config/environment")
38
34
  else
@@ -56,11 +52,6 @@ module Tapioca
56
52
  require(file)
57
53
  end
58
54
 
59
- sig { void }
60
- def require_bundle
61
- gemfile.require
62
- end
63
-
64
55
  sig { returns(T::Array[T.untyped]) }
65
56
  def rails_engines
66
57
  engines = []
@@ -84,11 +75,6 @@ module Tapioca
84
75
  nil
85
76
  end
86
77
 
87
- sig { void }
88
- def load_rake
89
- safe_require("rake")
90
- end
91
-
92
78
  sig { void }
93
79
  def silence_deprecations
94
80
  # Stop any ActiveSupport Deprecations from being reported
@@ -11,9 +11,11 @@ module Tapioca
11
11
  def visit(node)
12
12
  return unless node.is_a?(Tree)
13
13
  visit_all(node.nodes)
14
+ original_order = node.nodes.map.with_index.to_h
14
15
  node.nodes.sort! do |a, b|
15
16
  res = node_rank(a) <=> node_rank(b)
16
17
  res = node_name(a) <=> node_name(b) if res == 0
18
+ res = (original_order[a] || 0) <=> (original_order[b] || 0) if res == 0
17
19
  res || 0
18
20
  end
19
21
  end
@@ -23,27 +25,29 @@ module Tapioca
23
25
  sig { params(node: Node).returns(Integer) }
24
26
  def node_rank(node)
25
27
  case node
26
- when Group then kind_rank(node.kind)
27
- when Include, Extend then 0
28
- when Helper then 1
29
- when TypeMember then 2
30
- when MixesInClassMethods then 3
31
- when TStructField then 4
32
- when TEnumBlock then 5
28
+ when Group then group_rank(node.kind)
29
+ when Include, Extend then 10
30
+ when Helper then 20
31
+ when TypeMember then 30
32
+ when MixesInClassMethods then 40
33
+ when TStructField then 50
34
+ when TEnumBlock then 60
33
35
  when Method
34
36
  if node.name == "initialize"
35
- 7
37
+ 71
38
+ elsif !node.is_singleton
39
+ 72
36
40
  else
37
- 8
41
+ 73
38
42
  end
39
- when Scope, Const then 9
43
+ when Scope, Const then 80
40
44
  else
41
- 10
45
+ 100
42
46
  end
43
47
  end
44
48
 
45
49
  sig { params(kind: Group::Kind).returns(Integer) }
46
- def kind_rank(kind)
50
+ def group_rank(kind)
47
51
  case kind
48
52
  when Group::Kind::Mixins then 0
49
53
  when Group::Kind::Helpers then 1
@@ -0,0 +1,20 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module T
5
+ module Types
6
+ class FixedHash
7
+ def name
8
+ entries = @types.map do |(k, v)|
9
+ if Symbol === k && ":#{k}" == k.inspect
10
+ "#{k}: #{v}"
11
+ else
12
+ "#{k.inspect} => #{v}"
13
+ end
14
+ end
15
+
16
+ "{#{entries.join(', ')}}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.4.22"
5
+ VERSION = "0.4.26"
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.4.22
4
+ version: 0.4.26
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: 2021-05-19 00:00:00.000000000 Z
14
+ date: 2021-09-06 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -168,6 +168,7 @@ files:
168
168
  - lib/tapioca/rbi/rewriters/nest_singleton_methods.rb
169
169
  - lib/tapioca/rbi/rewriters/sort_nodes.rb
170
170
  - lib/tapioca/rbi/visitor.rb
171
+ - lib/tapioca/sorbet_ext/fixed_hash_patch.rb
171
172
  - lib/tapioca/sorbet_ext/generic_name_patch.rb
172
173
  - lib/tapioca/sorbet_ext/name_patch.rb
173
174
  - lib/tapioca/version.rb
@@ -191,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
192
  - !ruby/object:Gem::Version
192
193
  version: '0'
193
194
  requirements: []
194
- rubygems_version: 3.2.17
195
+ rubygems_version: 3.2.20
195
196
  signing_key:
196
197
  specification_version: 4
197
198
  summary: A Ruby Interface file generator for gems, core types and the Ruby standard