tapioca 0.4.22 → 0.4.26

Sign up to get free protection for your applications and to get access to all the features.
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