tapioca 0.5.6 → 0.6.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 +4 -4
- data/README.md +114 -23
- data/lib/tapioca/cli.rb +188 -64
- data/lib/tapioca/compilers/dsl/active_record_associations.rb +94 -8
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +5 -4
- data/lib/tapioca/compilers/dsl/active_record_relations.rb +703 -0
- data/lib/tapioca/compilers/dsl/active_record_scope.rb +43 -13
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +2 -4
- data/lib/tapioca/compilers/dsl/base.rb +25 -42
- data/lib/tapioca/compilers/dsl/extensions/frozen_record.rb +29 -0
- data/lib/tapioca/compilers/dsl/frozen_record.rb +37 -0
- data/lib/tapioca/compilers/dsl/helper/active_record_constants.rb +27 -0
- data/lib/tapioca/compilers/dsl/param_helper.rb +52 -0
- data/lib/tapioca/compilers/dsl/rails_generators.rb +120 -0
- data/lib/tapioca/compilers/dsl_compiler.rb +32 -6
- data/lib/tapioca/compilers/sorbet.rb +2 -0
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +47 -46
- data/lib/tapioca/executor.rb +79 -0
- data/lib/tapioca/gemfile.rb +23 -0
- data/lib/tapioca/generators/base.rb +11 -18
- data/lib/tapioca/generators/dsl.rb +33 -38
- data/lib/tapioca/generators/gem.rb +50 -29
- data/lib/tapioca/generators/init.rb +41 -16
- data/lib/tapioca/generators/todo.rb +6 -6
- data/lib/tapioca/helpers/cli_helper.rb +26 -0
- data/lib/tapioca/helpers/config_helper.rb +84 -0
- data/lib/tapioca/helpers/test/content.rb +51 -0
- data/lib/tapioca/helpers/test/isolation.rb +125 -0
- data/lib/tapioca/helpers/test/template.rb +34 -0
- data/lib/tapioca/internal.rb +3 -2
- data/lib/tapioca/rbi_ext/model.rb +12 -9
- data/lib/tapioca/reflection.rb +13 -0
- data/lib/tapioca/trackers/autoload.rb +70 -0
- data/lib/tapioca/trackers/constant_definition.rb +42 -0
- data/lib/tapioca/trackers/mixin.rb +78 -0
- data/lib/tapioca/trackers.rb +14 -0
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +28 -2
- metadata +19 -7
- data/lib/tapioca/config.rb +0 -45
- data/lib/tapioca/config_builder.rb +0 -73
- data/lib/tapioca/constant_locator.rb +0 -40
@@ -67,10 +67,11 @@ module RBI
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
sig { params(name: String, block: T.nilable(T.proc.params(scope: Scope).void)).
|
70
|
+
sig { params(name: String, block: T.nilable(T.proc.params(scope: Scope).void)).returns(Scope) }
|
71
71
|
def create_module(name, &block)
|
72
|
-
|
73
|
-
|
72
|
+
T.cast(create_node(RBI::Module.new(name)), RBI::Scope).tap do |node|
|
73
|
+
block&.call(node)
|
74
|
+
end
|
74
75
|
end
|
75
76
|
|
76
77
|
sig do
|
@@ -78,11 +79,12 @@ module RBI
|
|
78
79
|
name: String,
|
79
80
|
superclass_name: T.nilable(String),
|
80
81
|
block: T.nilable(T.proc.params(scope: RBI::Scope).void)
|
81
|
-
).
|
82
|
+
).returns(Scope)
|
82
83
|
end
|
83
84
|
def create_class(name, superclass_name: nil, &block)
|
84
|
-
|
85
|
-
|
85
|
+
T.cast(create_node(RBI::Class.new(name, superclass_name: superclass_name)), RBI::Scope).tap do |node|
|
86
|
+
block&.call(node)
|
87
|
+
end
|
86
88
|
end
|
87
89
|
|
88
90
|
sig { params(name: String, value: String).void }
|
@@ -115,14 +117,15 @@ module RBI
|
|
115
117
|
name: String,
|
116
118
|
parameters: T::Array[TypedParam],
|
117
119
|
return_type: String,
|
118
|
-
class_method: T::Boolean
|
120
|
+
class_method: T::Boolean,
|
121
|
+
visibility: RBI::Visibility
|
119
122
|
).void
|
120
123
|
end
|
121
|
-
def create_method(name, parameters: [], return_type: "T.untyped", class_method: false)
|
124
|
+
def create_method(name, parameters: [], return_type: "T.untyped", class_method: false, visibility: RBI::Public.new)
|
122
125
|
return unless valid_method_name?(name)
|
123
126
|
|
124
127
|
sig = RBI::Sig.new(return_type: return_type)
|
125
|
-
method = RBI::Method.new(name, sigs: [sig], is_singleton: class_method)
|
128
|
+
method = RBI::Method.new(name, sigs: [sig], is_singleton: class_method, visibility: visibility)
|
126
129
|
parameters.each do |param|
|
127
130
|
method << param.param
|
128
131
|
sig << RBI::SigParam.new(param.param.name, param.type)
|
data/lib/tapioca/reflection.rb
CHANGED
@@ -19,6 +19,19 @@ module Tapioca
|
|
19
19
|
PRIVATE_INSTANCE_METHODS_METHOD = T.let(Module.instance_method(:private_instance_methods), UnboundMethod)
|
20
20
|
METHOD_METHOD = T.let(Kernel.instance_method(:method), UnboundMethod)
|
21
21
|
|
22
|
+
sig do
|
23
|
+
params(
|
24
|
+
symbol: String,
|
25
|
+
inherit: T::Boolean,
|
26
|
+
namespace: Module
|
27
|
+
).returns(BasicObject).checked(:never)
|
28
|
+
end
|
29
|
+
def constantize(symbol, inherit: false, namespace: Object)
|
30
|
+
namespace.const_get(symbol, inherit)
|
31
|
+
rescue NameError, LoadError, RuntimeError, ArgumentError, TypeError
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
22
35
|
sig { params(object: BasicObject).returns(Class).checked(:never) }
|
23
36
|
def class_of(object)
|
24
37
|
CLASS_METHOD.bind(object).call
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Tapioca
|
5
|
+
module Trackers
|
6
|
+
module Autoload
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
NOOP_METHOD = -> (*_args, **_kwargs, &_block) {}
|
10
|
+
|
11
|
+
@constant_names_registered_for_autoload = T.let([], T::Array[String])
|
12
|
+
|
13
|
+
class << self
|
14
|
+
extend T::Sig
|
15
|
+
|
16
|
+
sig { void }
|
17
|
+
def eager_load_all!
|
18
|
+
with_disabled_exits do
|
19
|
+
until @constant_names_registered_for_autoload.empty?
|
20
|
+
# Grab the next constant name
|
21
|
+
constant_name = T.must(@constant_names_registered_for_autoload.shift)
|
22
|
+
# Trigger autoload by constantizing the registered name
|
23
|
+
Reflection.constantize(constant_name, inherit: true)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
sig { params(constant_name: String).void }
|
29
|
+
def register(constant_name)
|
30
|
+
@constant_names_registered_for_autoload << constant_name
|
31
|
+
end
|
32
|
+
|
33
|
+
sig do
|
34
|
+
type_parameters(:Result)
|
35
|
+
.params(block: T.proc.returns(T.type_parameter(:Result)))
|
36
|
+
.returns(T.type_parameter(:Result))
|
37
|
+
end
|
38
|
+
def with_disabled_exits(&block)
|
39
|
+
original_abort = Kernel.instance_method(:abort)
|
40
|
+
original_exit = Kernel.instance_method(:exit)
|
41
|
+
|
42
|
+
begin
|
43
|
+
Kernel.define_method(:abort, NOOP_METHOD)
|
44
|
+
Kernel.define_method(:exit, NOOP_METHOD)
|
45
|
+
|
46
|
+
block.call
|
47
|
+
ensure
|
48
|
+
Kernel.define_method(:exit, original_exit)
|
49
|
+
Kernel.define_method(:abort, original_abort)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# We need to do the alias-method-chain dance since Bootsnap does the same,
|
58
|
+
# and prepended modules and alias-method-chain don't play well together.
|
59
|
+
#
|
60
|
+
# So, why does Bootsnap do alias-method-chain and not prepend? Glad you asked!
|
61
|
+
# That's because RubyGems does alias-method-chain for Kernel#require and such,
|
62
|
+
# so, if Bootsnap were to do prepend, it might end up breaking RubyGems.
|
63
|
+
class Module
|
64
|
+
alias_method(:autoload_without_tapioca, :autoload)
|
65
|
+
|
66
|
+
def autoload(const_name, path)
|
67
|
+
Tapioca::Trackers::Autoload.register("#{self}::#{const_name}")
|
68
|
+
autoload_without_tapioca(const_name, path)
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "set"
|
5
|
+
|
6
|
+
module Tapioca
|
7
|
+
module Trackers
|
8
|
+
# Registers a TracePoint immediately upon load to track points at which
|
9
|
+
# classes and modules are opened for definition. This is used to track
|
10
|
+
# correspondence between classes/modules and files, as this information isn't
|
11
|
+
# available in the ruby runtime without extra accounting.
|
12
|
+
module ConstantDefinition
|
13
|
+
extend Reflection
|
14
|
+
|
15
|
+
@class_files = {}
|
16
|
+
|
17
|
+
# Immediately activated upon load. Observes class/module definition.
|
18
|
+
TracePoint.trace(:class) do |tp|
|
19
|
+
unless tp.self.singleton_class?
|
20
|
+
key = name_of(tp.self)
|
21
|
+
file = tp.path
|
22
|
+
if file == "(eval)"
|
23
|
+
file = T.must(caller_locations)
|
24
|
+
.drop_while { |loc| loc.path == "(eval)" }
|
25
|
+
.first&.path
|
26
|
+
end
|
27
|
+
@class_files[key] ||= Set.new
|
28
|
+
@class_files[key] << file
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the files in which this class or module was opened. Doesn't know
|
33
|
+
# about situations where the class was opened prior to +require+ing,
|
34
|
+
# or where metaprogramming was used via +eval+, etc.
|
35
|
+
def self.files_for(klass)
|
36
|
+
name = String === klass ? klass : name_of(klass)
|
37
|
+
files = @class_files[name]
|
38
|
+
files || Set.new
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Tapioca
|
5
|
+
module Trackers
|
6
|
+
module Mixin
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
@mixin_map = {}.compare_by_identity
|
10
|
+
|
11
|
+
class Type < T::Enum
|
12
|
+
enums do
|
13
|
+
Prepend = new
|
14
|
+
Include = new
|
15
|
+
Extend = new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
sig do
|
20
|
+
params(
|
21
|
+
constant: Module,
|
22
|
+
mod: Module,
|
23
|
+
mixin_type: Type,
|
24
|
+
locations: T.nilable(T::Array[Thread::Backtrace::Location])
|
25
|
+
).void
|
26
|
+
end
|
27
|
+
def self.register(constant, mod, mixin_type, locations)
|
28
|
+
locations ||= []
|
29
|
+
locations.map!(&:absolute_path).uniq!
|
30
|
+
locs = mixin_locations_for(constant)
|
31
|
+
locs.fetch(mixin_type).store(mod, T.cast(locations, T::Array[String]))
|
32
|
+
end
|
33
|
+
|
34
|
+
sig { params(constant: Module).returns(T::Hash[Type, T::Hash[Module, T::Array[String]]]) }
|
35
|
+
def self.mixin_locations_for(constant)
|
36
|
+
@mixin_map[constant] ||= {
|
37
|
+
Type::Prepend => {}.compare_by_identity,
|
38
|
+
Type::Include => {}.compare_by_identity,
|
39
|
+
Type::Extend => {}.compare_by_identity,
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Module
|
47
|
+
prepend(Module.new do
|
48
|
+
def prepend_features(constant)
|
49
|
+
Tapioca::Trackers::Mixin.register(
|
50
|
+
constant,
|
51
|
+
self,
|
52
|
+
Tapioca::Trackers::Mixin::Type::Prepend,
|
53
|
+
caller_locations
|
54
|
+
)
|
55
|
+
super
|
56
|
+
end
|
57
|
+
|
58
|
+
def append_features(constant)
|
59
|
+
Tapioca::Trackers::Mixin.register(
|
60
|
+
constant,
|
61
|
+
self,
|
62
|
+
Tapioca::Trackers::Mixin::Type::Include,
|
63
|
+
caller_locations
|
64
|
+
)
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
def extend_object(obj)
|
69
|
+
Tapioca::Trackers::Mixin.register(
|
70
|
+
obj,
|
71
|
+
self,
|
72
|
+
Tapioca::Trackers::Mixin::Type::Extend,
|
73
|
+
caller_locations
|
74
|
+
) if Module === obj
|
75
|
+
super
|
76
|
+
end
|
77
|
+
end)
|
78
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# The load order below is important:
|
5
|
+
# ----------------------------------
|
6
|
+
# We want the mixin tracker to be the first thing that is
|
7
|
+
# loaded because other trackers might apply their own mixins
|
8
|
+
# into core types (like `Module` and `Kernel`). In order to
|
9
|
+
# catch and filter those mixins as coming from Tapioca, we need
|
10
|
+
# the mixin tracker to be in place, before any mixin operations
|
11
|
+
# are performed.
|
12
|
+
require "tapioca/trackers/mixin"
|
13
|
+
require "tapioca/trackers/constant_definition"
|
14
|
+
require "tapioca/trackers/autoload"
|
data/lib/tapioca/version.rb
CHANGED
data/lib/tapioca.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "sorbet-runtime"
|
5
5
|
|
6
6
|
module Tapioca
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
sig do
|
10
|
+
type_parameters(:Result)
|
11
|
+
.params(blk: T.proc.returns(T.type_parameter(:Result)))
|
12
|
+
.returns(T.type_parameter(:Result))
|
13
|
+
end
|
7
14
|
def self.silence_warnings(&blk)
|
8
15
|
original_verbosity = $VERBOSE
|
9
16
|
$VERBOSE = nil
|
@@ -15,10 +22,29 @@ module Tapioca
|
|
15
22
|
end
|
16
23
|
|
17
24
|
class Error < StandardError; end
|
25
|
+
|
26
|
+
SORBET_DIR = T.let("sorbet", String)
|
27
|
+
SORBET_CONFIG_FILE = T.let("#{SORBET_DIR}/config", String)
|
28
|
+
TAPIOCA_DIR = T.let("#{SORBET_DIR}/tapioca", String)
|
29
|
+
TAPIOCA_CONFIG_FILE = T.let("#{TAPIOCA_DIR}/config.yml", String)
|
30
|
+
|
31
|
+
DEFAULT_COMMAND = T.let("bin/tapioca", String)
|
32
|
+
DEFAULT_POSTREQUIRE_FILE = T.let("#{TAPIOCA_DIR}/require.rb", String)
|
33
|
+
DEFAULT_RBI_DIR = T.let("#{SORBET_DIR}/rbi", String)
|
34
|
+
DEFAULT_DSL_DIR = T.let("#{DEFAULT_RBI_DIR}/dsl", String)
|
35
|
+
DEFAULT_GEM_DIR = T.let("#{DEFAULT_RBI_DIR}/gems", String)
|
36
|
+
DEFAULT_SHIM_DIR = T.let("#{DEFAULT_RBI_DIR}/shims", String)
|
37
|
+
DEFAULT_TODO_FILE = T.let("#{DEFAULT_RBI_DIR}/todo.rbi", String)
|
38
|
+
|
39
|
+
DEFAULT_OVERRIDES = T.let({
|
40
|
+
# ActiveSupport overrides some core methods with different signatures
|
41
|
+
# so we generate a typed: false RBI for it to suppress errors
|
42
|
+
"activesupport" => "false",
|
43
|
+
}.freeze, T::Hash[String, String])
|
18
44
|
end
|
19
45
|
|
20
46
|
require "tapioca/reflection"
|
21
|
-
require "tapioca/
|
47
|
+
require "tapioca/trackers"
|
22
48
|
require "tapioca/compilers/dsl/base"
|
23
49
|
require "tapioca/compilers/dynamic_mixin_compiler"
|
24
50
|
require "tapioca/helpers/active_record_column_type_helper"
|
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
|
+
version: 0.6.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: 2021-12-
|
14
|
+
date: 2021-12-17 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.
|
53
|
+
version: 0.0.9
|
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.
|
63
|
+
version: 0.0.9
|
64
64
|
- !ruby/object:Gem::Dependency
|
65
65
|
name: sorbet-static
|
66
66
|
requirement: !ruby/object:Gem::Requirement
|
@@ -161,6 +161,7 @@ files:
|
|
161
161
|
- lib/tapioca/compilers/dsl/active_record_columns.rb
|
162
162
|
- lib/tapioca/compilers/dsl/active_record_enum.rb
|
163
163
|
- lib/tapioca/compilers/dsl/active_record_fixtures.rb
|
164
|
+
- lib/tapioca/compilers/dsl/active_record_relations.rb
|
164
165
|
- lib/tapioca/compilers/dsl/active_record_scope.rb
|
165
166
|
- lib/tapioca/compilers/dsl/active_record_typed_store.rb
|
166
167
|
- lib/tapioca/compilers/dsl/active_resource.rb
|
@@ -169,10 +170,14 @@ files:
|
|
169
170
|
- lib/tapioca/compilers/dsl/active_support_current_attributes.rb
|
170
171
|
- lib/tapioca/compilers/dsl/base.rb
|
171
172
|
- lib/tapioca/compilers/dsl/config.rb
|
173
|
+
- lib/tapioca/compilers/dsl/extensions/frozen_record.rb
|
172
174
|
- lib/tapioca/compilers/dsl/frozen_record.rb
|
175
|
+
- lib/tapioca/compilers/dsl/helper/active_record_constants.rb
|
173
176
|
- lib/tapioca/compilers/dsl/identity_cache.rb
|
174
177
|
- lib/tapioca/compilers/dsl/mixed_in_class_attributes.rb
|
178
|
+
- lib/tapioca/compilers/dsl/param_helper.rb
|
175
179
|
- lib/tapioca/compilers/dsl/protobuf.rb
|
180
|
+
- lib/tapioca/compilers/dsl/rails_generators.rb
|
176
181
|
- lib/tapioca/compilers/dsl/sidekiq_worker.rb
|
177
182
|
- lib/tapioca/compilers/dsl/smart_properties.rb
|
178
183
|
- lib/tapioca/compilers/dsl/state_machines.rb
|
@@ -185,9 +190,7 @@ files:
|
|
185
190
|
- lib/tapioca/compilers/symbol_table/symbol_loader.rb
|
186
191
|
- lib/tapioca/compilers/symbol_table_compiler.rb
|
187
192
|
- lib/tapioca/compilers/todos_compiler.rb
|
188
|
-
- lib/tapioca/
|
189
|
-
- lib/tapioca/config_builder.rb
|
190
|
-
- lib/tapioca/constant_locator.rb
|
193
|
+
- lib/tapioca/executor.rb
|
191
194
|
- lib/tapioca/gemfile.rb
|
192
195
|
- lib/tapioca/generators.rb
|
193
196
|
- lib/tapioca/generators/base.rb
|
@@ -198,6 +201,11 @@ files:
|
|
198
201
|
- lib/tapioca/generators/todo.rb
|
199
202
|
- lib/tapioca/generic_type_registry.rb
|
200
203
|
- lib/tapioca/helpers/active_record_column_type_helper.rb
|
204
|
+
- lib/tapioca/helpers/cli_helper.rb
|
205
|
+
- lib/tapioca/helpers/config_helper.rb
|
206
|
+
- lib/tapioca/helpers/test/content.rb
|
207
|
+
- lib/tapioca/helpers/test/isolation.rb
|
208
|
+
- lib/tapioca/helpers/test/template.rb
|
201
209
|
- lib/tapioca/internal.rb
|
202
210
|
- lib/tapioca/loader.rb
|
203
211
|
- lib/tapioca/rbi_ext/model.rb
|
@@ -205,6 +213,10 @@ files:
|
|
205
213
|
- lib/tapioca/sorbet_ext/fixed_hash_patch.rb
|
206
214
|
- lib/tapioca/sorbet_ext/generic_name_patch.rb
|
207
215
|
- lib/tapioca/sorbet_ext/name_patch.rb
|
216
|
+
- lib/tapioca/trackers.rb
|
217
|
+
- lib/tapioca/trackers/autoload.rb
|
218
|
+
- lib/tapioca/trackers/constant_definition.rb
|
219
|
+
- lib/tapioca/trackers/mixin.rb
|
208
220
|
- lib/tapioca/version.rb
|
209
221
|
homepage: https://github.com/Shopify/tapioca
|
210
222
|
licenses:
|
data/lib/tapioca/config.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module Tapioca
|
5
|
-
class Config < T::Struct
|
6
|
-
extend(T::Sig)
|
7
|
-
|
8
|
-
const(:outdir, String)
|
9
|
-
const(:prerequire, T.nilable(String))
|
10
|
-
const(:postrequire, String)
|
11
|
-
const(:exclude, T::Array[String])
|
12
|
-
const(:exclude_generators, T::Array[String])
|
13
|
-
const(:typed_overrides, T::Hash[String, String])
|
14
|
-
const(:todos_path, String)
|
15
|
-
const(:generators, T::Array[String])
|
16
|
-
const(:file_header, T::Boolean, default: true)
|
17
|
-
const(:doc, T::Boolean, default: false)
|
18
|
-
|
19
|
-
sig { returns(Pathname) }
|
20
|
-
def outpath
|
21
|
-
@outpath = T.let(@outpath, T.nilable(Pathname))
|
22
|
-
@outpath ||= Pathname.new(outdir)
|
23
|
-
end
|
24
|
-
|
25
|
-
private_class_method :new
|
26
|
-
|
27
|
-
SORBET_PATH = T.let("sorbet", String)
|
28
|
-
SORBET_CONFIG = T.let("#{SORBET_PATH}/config", String)
|
29
|
-
TAPIOCA_PATH = T.let("#{SORBET_PATH}/tapioca", String)
|
30
|
-
TAPIOCA_CONFIG = T.let("#{TAPIOCA_PATH}/config.yml", String)
|
31
|
-
|
32
|
-
DEFAULT_COMMAND = T.let("bin/tapioca", String)
|
33
|
-
DEFAULT_POSTREQUIRE = T.let("#{TAPIOCA_PATH}/require.rb", String)
|
34
|
-
DEFAULT_RBIDIR = T.let("#{SORBET_PATH}/rbi", String)
|
35
|
-
DEFAULT_DSLDIR = T.let("#{DEFAULT_RBIDIR}/dsl", String)
|
36
|
-
DEFAULT_GEMDIR = T.let("#{DEFAULT_RBIDIR}/gems", String)
|
37
|
-
DEFAULT_TODOSPATH = T.let("#{DEFAULT_RBIDIR}/todo.rbi", String)
|
38
|
-
|
39
|
-
DEFAULT_OVERRIDES = T.let({
|
40
|
-
# ActiveSupport overrides some core methods with different signatures
|
41
|
-
# so we generate a typed: false RBI for it to suppress errors
|
42
|
-
"activesupport" => "false",
|
43
|
-
}.freeze, T::Hash[String, String])
|
44
|
-
end
|
45
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "yaml"
|
5
|
-
|
6
|
-
module Tapioca
|
7
|
-
class ConfigBuilder
|
8
|
-
class << self
|
9
|
-
extend(T::Sig)
|
10
|
-
|
11
|
-
sig { params(command: Symbol, options: T::Hash[String, T.untyped]).returns(Config) }
|
12
|
-
def from_options(command, options)
|
13
|
-
merged_options = merge_options(default_options(command), config_options, options)
|
14
|
-
|
15
|
-
puts(<<~MSG) if merged_options.include?("generate_command")
|
16
|
-
DEPRECATION: The `-c` and `--cmd` flags will be removed in a future release.
|
17
|
-
MSG
|
18
|
-
|
19
|
-
Config.from_hash(merged_options)
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
sig { returns(T::Hash[String, T.untyped]) }
|
25
|
-
def config_options
|
26
|
-
if File.exist?(Config::TAPIOCA_CONFIG)
|
27
|
-
YAML.load_file(Config::TAPIOCA_CONFIG, fallback: {})
|
28
|
-
else
|
29
|
-
{}
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
sig { params(command: Symbol).returns(T::Hash[String, T.untyped]) }
|
34
|
-
def default_options(command)
|
35
|
-
default_outdir = case command
|
36
|
-
when :sync, :generate, :gem
|
37
|
-
Config::DEFAULT_GEMDIR
|
38
|
-
when :dsl
|
39
|
-
Config::DEFAULT_DSLDIR
|
40
|
-
else
|
41
|
-
Config::SORBET_PATH
|
42
|
-
end
|
43
|
-
|
44
|
-
DEFAULT_OPTIONS.merge("outdir" => default_outdir)
|
45
|
-
end
|
46
|
-
|
47
|
-
sig { params(options: T::Hash[String, T.untyped]).returns(T::Hash[String, T.untyped]) }
|
48
|
-
def merge_options(*options)
|
49
|
-
options.each_with_object({}) do |option, result|
|
50
|
-
result.merge!(option) do |_, this_val, other_val|
|
51
|
-
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
|
52
|
-
this_val.merge(other_val)
|
53
|
-
else
|
54
|
-
other_val
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
DEFAULT_OPTIONS = T.let({
|
62
|
-
"postrequire" => Config::DEFAULT_POSTREQUIRE,
|
63
|
-
"outdir" => nil,
|
64
|
-
"exclude" => [],
|
65
|
-
"exclude_generators" => [],
|
66
|
-
"typed_overrides" => Config::DEFAULT_OVERRIDES,
|
67
|
-
"todos_path" => Config::DEFAULT_TODOSPATH,
|
68
|
-
"generators" => [],
|
69
|
-
"file_header" => true,
|
70
|
-
"doc" => false,
|
71
|
-
}.freeze, T::Hash[String, T.untyped])
|
72
|
-
end
|
73
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# typed: true
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "set"
|
5
|
-
|
6
|
-
module Tapioca
|
7
|
-
# Registers a TracePoint immediately upon load to track points at which
|
8
|
-
# classes and modules are opened for definition. This is used to track
|
9
|
-
# correspondence between classes/modules and files, as this information isn't
|
10
|
-
# available in the ruby runtime without extra accounting.
|
11
|
-
module ConstantLocator
|
12
|
-
extend Reflection
|
13
|
-
|
14
|
-
@class_files = {}
|
15
|
-
|
16
|
-
# Immediately activated upon load. Observes class/module definition.
|
17
|
-
TracePoint.trace(:class) do |tp|
|
18
|
-
unless tp.self.singleton_class?
|
19
|
-
key = name_of(tp.self)
|
20
|
-
file = tp.path
|
21
|
-
if file == "(eval)"
|
22
|
-
file = T.must(caller_locations)
|
23
|
-
.drop_while { |loc| loc.path == "(eval)" }
|
24
|
-
.first&.path
|
25
|
-
end
|
26
|
-
@class_files[key] ||= Set.new
|
27
|
-
@class_files[key] << file
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# Returns the files in which this class or module was opened. Doesn't know
|
32
|
-
# about situations where the class was opened prior to +require+ing,
|
33
|
-
# or where metaprogramming was used via +eval+, etc.
|
34
|
-
def self.files_for(klass)
|
35
|
-
name = String === klass ? klass : name_of(klass)
|
36
|
-
files = @class_files[name]
|
37
|
-
files || Set.new
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|