tapioca 0.5.3 → 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 -65
- 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_enum.rb +1 -1
- 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 +39 -33
- data/lib/tapioca/compilers/dsl/base.rb +26 -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/identity_cache.rb +0 -1
- 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 +34 -6
- data/lib/tapioca/compilers/sorbet.rb +2 -0
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +51 -48
- data/lib/tapioca/executor.rb +79 -0
- data/lib/tapioca/gemfile.rb +28 -4
- data/lib/tapioca/generators/base.rb +11 -18
- data/lib/tapioca/generators/dsl.rb +33 -38
- data/lib/tapioca/generators/gem.rb +64 -34
- 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 +13 -10
- 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 +37 -13
- data/lib/tapioca/config.rb +0 -45
- data/lib/tapioca/config_builder.rb +0 -73
- data/lib/tapioca/constant_locator.rb +0 -34
@@ -37,7 +37,7 @@ module RBI
|
|
37
37
|
|
38
38
|
sig { void }
|
39
39
|
def set_empty_body_content
|
40
|
-
comments << RBI::
|
40
|
+
comments << RBI::BlankLine.new unless comments.empty?
|
41
41
|
comments << RBI::Comment.new("THIS IS AN EMPTY RBI FILE.")
|
42
42
|
comments << RBI::Comment.new("see https://github.com/Shopify/tapioca/wiki/Manual-Gem-Requires")
|
43
43
|
end
|
@@ -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-
|
14
|
+
date: 2021-12-17 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -45,58 +45,70 @@ dependencies:
|
|
45
45
|
name: rbi
|
46
46
|
requirement: !ruby/object:Gem::Requirement
|
47
47
|
requirements:
|
48
|
+
- - "~>"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 0.0.0
|
48
51
|
- - ">="
|
49
52
|
- !ruby/object:Gem::Version
|
50
|
-
version:
|
53
|
+
version: 0.0.9
|
51
54
|
type: :runtime
|
52
55
|
prerelease: false
|
53
56
|
version_requirements: !ruby/object:Gem::Requirement
|
54
57
|
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.0.0
|
55
61
|
- - ">="
|
56
62
|
- !ruby/object:Gem::Version
|
57
|
-
version:
|
63
|
+
version: 0.0.9
|
58
64
|
- !ruby/object:Gem::Dependency
|
59
65
|
name: sorbet-static
|
60
66
|
requirement: !ruby/object:Gem::Requirement
|
61
67
|
requirements:
|
62
68
|
- - ">="
|
63
69
|
- !ruby/object:Gem::Version
|
64
|
-
version: 0.5.
|
70
|
+
version: 0.5.9204
|
65
71
|
type: :runtime
|
66
72
|
prerelease: false
|
67
73
|
version_requirements: !ruby/object:Gem::Requirement
|
68
74
|
requirements:
|
69
75
|
- - ">="
|
70
76
|
- !ruby/object:Gem::Version
|
71
|
-
version: 0.5.
|
77
|
+
version: 0.5.9204
|
72
78
|
- !ruby/object:Gem::Dependency
|
73
79
|
name: sorbet-runtime
|
74
80
|
requirement: !ruby/object:Gem::Requirement
|
75
81
|
requirements:
|
76
82
|
- - ">="
|
77
83
|
- !ruby/object:Gem::Version
|
78
|
-
version:
|
84
|
+
version: 0.5.9204
|
79
85
|
type: :runtime
|
80
86
|
prerelease: false
|
81
87
|
version_requirements: !ruby/object:Gem::Requirement
|
82
88
|
requirements:
|
83
89
|
- - ">="
|
84
90
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
91
|
+
version: 0.5.9204
|
86
92
|
- !ruby/object:Gem::Dependency
|
87
93
|
name: spoom
|
88
94
|
requirement: !ruby/object:Gem::Requirement
|
89
95
|
requirements:
|
96
|
+
- - "~>"
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 1.1.0
|
90
99
|
- - ">="
|
91
100
|
- !ruby/object:Gem::Version
|
92
|
-
version:
|
101
|
+
version: 1.1.4
|
93
102
|
type: :runtime
|
94
103
|
prerelease: false
|
95
104
|
version_requirements: !ruby/object:Gem::Requirement
|
96
105
|
requirements:
|
106
|
+
- - "~>"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: 1.1.0
|
97
109
|
- - ">="
|
98
110
|
- !ruby/object:Gem::Version
|
99
|
-
version:
|
111
|
+
version: 1.1.4
|
100
112
|
- !ruby/object:Gem::Dependency
|
101
113
|
name: thor
|
102
114
|
requirement: !ruby/object:Gem::Requirement
|
@@ -149,6 +161,7 @@ files:
|
|
149
161
|
- lib/tapioca/compilers/dsl/active_record_columns.rb
|
150
162
|
- lib/tapioca/compilers/dsl/active_record_enum.rb
|
151
163
|
- lib/tapioca/compilers/dsl/active_record_fixtures.rb
|
164
|
+
- lib/tapioca/compilers/dsl/active_record_relations.rb
|
152
165
|
- lib/tapioca/compilers/dsl/active_record_scope.rb
|
153
166
|
- lib/tapioca/compilers/dsl/active_record_typed_store.rb
|
154
167
|
- lib/tapioca/compilers/dsl/active_resource.rb
|
@@ -157,10 +170,14 @@ files:
|
|
157
170
|
- lib/tapioca/compilers/dsl/active_support_current_attributes.rb
|
158
171
|
- lib/tapioca/compilers/dsl/base.rb
|
159
172
|
- lib/tapioca/compilers/dsl/config.rb
|
173
|
+
- lib/tapioca/compilers/dsl/extensions/frozen_record.rb
|
160
174
|
- lib/tapioca/compilers/dsl/frozen_record.rb
|
175
|
+
- lib/tapioca/compilers/dsl/helper/active_record_constants.rb
|
161
176
|
- lib/tapioca/compilers/dsl/identity_cache.rb
|
162
177
|
- lib/tapioca/compilers/dsl/mixed_in_class_attributes.rb
|
178
|
+
- lib/tapioca/compilers/dsl/param_helper.rb
|
163
179
|
- lib/tapioca/compilers/dsl/protobuf.rb
|
180
|
+
- lib/tapioca/compilers/dsl/rails_generators.rb
|
164
181
|
- lib/tapioca/compilers/dsl/sidekiq_worker.rb
|
165
182
|
- lib/tapioca/compilers/dsl/smart_properties.rb
|
166
183
|
- lib/tapioca/compilers/dsl/state_machines.rb
|
@@ -173,9 +190,7 @@ files:
|
|
173
190
|
- lib/tapioca/compilers/symbol_table/symbol_loader.rb
|
174
191
|
- lib/tapioca/compilers/symbol_table_compiler.rb
|
175
192
|
- lib/tapioca/compilers/todos_compiler.rb
|
176
|
-
- lib/tapioca/
|
177
|
-
- lib/tapioca/config_builder.rb
|
178
|
-
- lib/tapioca/constant_locator.rb
|
193
|
+
- lib/tapioca/executor.rb
|
179
194
|
- lib/tapioca/gemfile.rb
|
180
195
|
- lib/tapioca/generators.rb
|
181
196
|
- lib/tapioca/generators/base.rb
|
@@ -186,6 +201,11 @@ files:
|
|
186
201
|
- lib/tapioca/generators/todo.rb
|
187
202
|
- lib/tapioca/generic_type_registry.rb
|
188
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
|
189
209
|
- lib/tapioca/internal.rb
|
190
210
|
- lib/tapioca/loader.rb
|
191
211
|
- lib/tapioca/rbi_ext/model.rb
|
@@ -193,6 +213,10 @@ files:
|
|
193
213
|
- lib/tapioca/sorbet_ext/fixed_hash_patch.rb
|
194
214
|
- lib/tapioca/sorbet_ext/generic_name_patch.rb
|
195
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
|
196
220
|
- lib/tapioca/version.rb
|
197
221
|
homepage: https://github.com/Shopify/tapioca
|
198
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,34 +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
|
-
@class_files[key] ||= Set.new
|
21
|
-
@class_files[key] << tp.path
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# Returns the files in which this class or module was opened. Doesn't know
|
26
|
-
# about situations where the class was opened prior to +require+ing,
|
27
|
-
# or where metaprogramming was used via +eval+, etc.
|
28
|
-
def self.files_for(klass)
|
29
|
-
name = String === klass ? klass : name_of(klass)
|
30
|
-
files = @class_files[name]
|
31
|
-
files || Set.new
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|