tapioca 0.10.4 → 0.11.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/lib/tapioca/cli.rb +14 -5
- data/lib/tapioca/commands/annotations.rb +2 -0
- data/lib/tapioca/commands/configure.rb +1 -0
- data/lib/tapioca/commands/dsl.rb +17 -3
- data/lib/tapioca/commands/gem.rb +4 -2
- data/lib/tapioca/dsl/compilers/aasm.rb +78 -17
- data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_record_columns.rb +3 -3
- data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +8 -5
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +140 -83
- data/lib/tapioca/dsl/compilers/active_record_scope.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_record_secure_token.rb +74 -0
- data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +14 -11
- data/lib/tapioca/dsl/compilers/active_resource.rb +22 -15
- data/lib/tapioca/dsl/compilers/active_storage.rb +4 -2
- data/lib/tapioca/dsl/compilers/graphql_input_object.rb +21 -1
- data/lib/tapioca/dsl/compilers/kredis.rb +130 -0
- data/lib/tapioca/dsl/compilers/smart_properties.rb +7 -4
- data/lib/tapioca/dsl/compilers/url_helpers.rb +7 -4
- data/lib/tapioca/dsl/extensions/active_record.rb +9 -0
- data/lib/tapioca/dsl/extensions/kredis.rb +114 -0
- data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +37 -27
- data/lib/tapioca/dsl/helpers/active_record_constants_helper.rb +1 -0
- data/lib/tapioca/dsl/pipeline.rb +12 -5
- data/lib/tapioca/gem/listeners/sorbet_enums.rb +1 -1
- data/lib/tapioca/gem/listeners/yard_doc.rb +13 -10
- data/lib/tapioca/gem/pipeline.rb +14 -0
- data/lib/tapioca/gemfile.rb +6 -2
- data/lib/tapioca/helpers/rbi_files_helper.rb +12 -6
- data/lib/tapioca/helpers/sorbet_helper.rb +7 -4
- data/lib/tapioca/helpers/source_uri.rb +10 -7
- data/lib/tapioca/loaders/gem.rb +4 -2
- data/lib/tapioca/loaders/loader.rb +99 -35
- data/lib/tapioca/rbi_ext/model.rb +8 -3
- data/lib/tapioca/rbi_formatter.rb +11 -8
- data/lib/tapioca/runtime/attached_class_of_32.rb +20 -0
- data/lib/tapioca/runtime/attached_class_of_legacy.rb +27 -0
- data/lib/tapioca/runtime/reflection.rb +11 -10
- data/lib/tapioca/runtime/trackers.rb +17 -0
- data/lib/tapioca/static/symbol_loader.rb +14 -14
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +8 -5
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f32d4fd559ee85f540926b3faa454aaf2ddd919b502438bf2deda24a4b04f855
|
4
|
+
data.tar.gz: 9368c2329923554e639310003630d36f9bf7a2f895df619cfe844dacd9a2c176
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c997e7598a5cef84e52935b0f9681ca636fef5fb866d30f1e6d19e2912ae38b5ec7499e69cde6cd147b4a723214d80abb109dbd523e48f143eae0b1edbefd46e
|
7
|
+
data.tar.gz: 33882ab5de1b8b43d775bdb20b0fab39d97ebe2ce7b346bb9828b64e27dd99bb7d46814ac441dd1b6b7aadb3b4aa02f93a652d4e6fa42c34ac83241eb9eb78d7
|
data/lib/tapioca/cli.rb
CHANGED
@@ -25,9 +25,12 @@ module Tapioca
|
|
25
25
|
|
26
26
|
desc "init", "get project ready for type checking"
|
27
27
|
def init
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
# We need to make sure that trackers stay enabled until the `gem` command is invoked
|
29
|
+
Runtime::Trackers.with_trackers_enabled do
|
30
|
+
invoke(:configure)
|
31
|
+
invoke(:annotations)
|
32
|
+
invoke(:gem)
|
33
|
+
end
|
31
34
|
invoke(:todo)
|
32
35
|
|
33
36
|
print_init_next_steps
|
@@ -127,11 +130,15 @@ module Tapioca
|
|
127
130
|
type: :string,
|
128
131
|
desc: "The path to the Rails application",
|
129
132
|
default: "."
|
130
|
-
def dsl(*
|
133
|
+
def dsl(*constant_or_paths)
|
131
134
|
set_environment(options)
|
132
135
|
|
136
|
+
# Assume anything starting with a capital letter or colon is a class, otherwise a path
|
137
|
+
constants, paths = constant_or_paths.partition { |c| c =~ /\A[A-Z:]/ }
|
138
|
+
|
133
139
|
command = Commands::Dsl.new(
|
134
140
|
requested_constants: constants,
|
141
|
+
requested_paths: paths.map { |p| Pathname.new(p) },
|
135
142
|
outpath: Pathname.new(options[:outdir]),
|
136
143
|
only: options[:only],
|
137
144
|
exclude: options[:exclude],
|
@@ -293,7 +300,9 @@ module Tapioca
|
|
293
300
|
end
|
294
301
|
|
295
302
|
desc "annotations", "Pull gem RBI annotations from remote sources"
|
296
|
-
option :sources,
|
303
|
+
option :sources,
|
304
|
+
type: :array,
|
305
|
+
default: [CENTRAL_REPO_ROOT_URI],
|
297
306
|
desc: "URIs of the sources to pull gem RBI annotations from"
|
298
307
|
option :netrc, type: :boolean, default: true, desc: "Use .netrc to authenticate to private sources"
|
299
308
|
option :netrc_file, type: :string, desc: "Path to .netrc file"
|
@@ -189,6 +189,8 @@ module Tapioca
|
|
189
189
|
|
190
190
|
sig { params(name: String, content: String).returns(String) }
|
191
191
|
def add_header(name, content)
|
192
|
+
# WARNING: Changing this header could impact how GitHub determines if the file should be hidden:
|
193
|
+
# https://github.com/github/linguist/pull/6143
|
192
194
|
header = <<~COMMENT
|
193
195
|
# DO NOT EDIT MANUALLY
|
194
196
|
# This file was pulled from a central RBI files repository.
|
data/lib/tapioca/commands/dsl.rb
CHANGED
@@ -10,6 +10,7 @@ module Tapioca
|
|
10
10
|
sig do
|
11
11
|
params(
|
12
12
|
requested_constants: T::Array[String],
|
13
|
+
requested_paths: T::Array[Pathname],
|
13
14
|
outpath: Pathname,
|
14
15
|
only: T::Array[String],
|
15
16
|
exclude: T::Array[String],
|
@@ -27,6 +28,7 @@ module Tapioca
|
|
27
28
|
end
|
28
29
|
def initialize(
|
29
30
|
requested_constants:,
|
31
|
+
requested_paths:,
|
30
32
|
outpath:,
|
31
33
|
only:,
|
32
34
|
exclude:,
|
@@ -42,6 +44,7 @@ module Tapioca
|
|
42
44
|
app_root: "."
|
43
45
|
)
|
44
46
|
@requested_constants = requested_constants
|
47
|
+
@requested_paths = requested_paths
|
45
48
|
@outpath = outpath
|
46
49
|
@only = only
|
47
50
|
@exclude = exclude
|
@@ -63,7 +66,7 @@ module Tapioca
|
|
63
66
|
def list_compilers
|
64
67
|
Loaders::Dsl.load_application(
|
65
68
|
tapioca_path: @tapioca_path,
|
66
|
-
eager_load: @requested_constants.empty?,
|
69
|
+
eager_load: @requested_constants.empty? && @requested_paths.empty?,
|
67
70
|
app_root: @app_root,
|
68
71
|
)
|
69
72
|
|
@@ -101,6 +104,15 @@ module Tapioca
|
|
101
104
|
end
|
102
105
|
say("")
|
103
106
|
|
107
|
+
unless @requested_paths.empty?
|
108
|
+
constants_from_paths = Static::SymbolLoader.symbols_from_paths(@requested_paths).to_a
|
109
|
+
if constants_from_paths.empty?
|
110
|
+
say_error("\nWarning: No constants found in: #{@requested_paths.map(&:to_s).join(", ")}", :yellow)
|
111
|
+
end
|
112
|
+
|
113
|
+
@requested_constants += constants_from_paths
|
114
|
+
end
|
115
|
+
|
104
116
|
outpath = @should_verify ? Pathname.new(Dir.mktmpdir) : @outpath
|
105
117
|
rbi_files_to_purge = existing_rbi_filenames(@requested_constants)
|
106
118
|
|
@@ -153,6 +165,7 @@ module Tapioca
|
|
153
165
|
def create_pipeline
|
154
166
|
Tapioca::Dsl::Pipeline.new(
|
155
167
|
requested_constants: constantize(@requested_constants),
|
168
|
+
requested_paths: @requested_paths,
|
156
169
|
requested_compilers: constantize_compilers(@only),
|
157
170
|
excluded_compilers: constantize_compilers(@exclude),
|
158
171
|
error_handler: ->(error) {
|
@@ -167,8 +180,9 @@ module Tapioca
|
|
167
180
|
filenames = if requested_constants.empty?
|
168
181
|
Pathname.glob(path / "**/*.rbi")
|
169
182
|
else
|
170
|
-
requested_constants.
|
171
|
-
dsl_rbi_filename(constant_name)
|
183
|
+
requested_constants.filter_map do |constant_name|
|
184
|
+
filename = dsl_rbi_filename(constant_name)
|
185
|
+
filename if File.exist?(filename)
|
172
186
|
end
|
173
187
|
end
|
174
188
|
|
data/lib/tapioca/commands/gem.rb
CHANGED
@@ -156,9 +156,11 @@ module Tapioca
|
|
156
156
|
|
157
157
|
rbi = RBI::File.new(strictness: @typed_overrides[gem.name] || "true")
|
158
158
|
|
159
|
-
@rbi_formatter.write_header!(
|
159
|
+
@rbi_formatter.write_header!(
|
160
|
+
rbi,
|
160
161
|
default_command(:gem, gem.name),
|
161
|
-
reason: "types exported from the `#{gem.name}` gem"
|
162
|
+
reason: "types exported from the `#{gem.name}` gem",
|
163
|
+
) if @file_header
|
162
164
|
|
163
165
|
rbi.root = Tapioca::Gem::Pipeline.new(gem, include_doc: @include_doc, include_loc: @include_loc).compile
|
164
166
|
|
@@ -44,8 +44,33 @@ module Tapioca
|
|
44
44
|
# https://github.com/aasm/aasm/blob/0e03746/lib/aasm/core/event.rb#L21-L29
|
45
45
|
EVENT_CALLBACKS =
|
46
46
|
T.let(
|
47
|
-
[
|
48
|
-
|
47
|
+
[
|
48
|
+
"after",
|
49
|
+
"after_commit",
|
50
|
+
"after_transaction",
|
51
|
+
"before",
|
52
|
+
"before_transaction",
|
53
|
+
"ensure",
|
54
|
+
"error",
|
55
|
+
"before_success",
|
56
|
+
"success",
|
57
|
+
].freeze,
|
58
|
+
T::Array[String],
|
59
|
+
)
|
60
|
+
|
61
|
+
# Taken directly from the AASM::Base class, here:
|
62
|
+
# https://github.com/aasm/aasm/blob/0e03746a2b86558ee1bf7bd7db873938cbb3b29b/lib/aasm/base.rb#L145-L171
|
63
|
+
GLOBAL_CALLBACKS =
|
64
|
+
T.let(
|
65
|
+
[
|
66
|
+
"after_all_transitions",
|
67
|
+
"after_all_transactions",
|
68
|
+
"before_all_transactions",
|
69
|
+
"before_all_events",
|
70
|
+
"after_all_events",
|
71
|
+
"error_on_all_events",
|
72
|
+
"ensure_on_all_events",
|
73
|
+
].freeze,
|
49
74
|
T::Array[String],
|
50
75
|
)
|
51
76
|
|
@@ -53,23 +78,47 @@ module Tapioca
|
|
53
78
|
|
54
79
|
sig { override.void }
|
55
80
|
def decorate
|
56
|
-
|
57
|
-
return
|
81
|
+
state_machine_store = ::AASM::StateMachineStore.fetch(constant)
|
82
|
+
return unless state_machine_store
|
83
|
+
|
84
|
+
state_machines = state_machine_store.machine_names.map { |n| constant.aasm(n) }
|
85
|
+
return if state_machines.all? { |m| m.states.empty? }
|
58
86
|
|
59
87
|
root.create_path(constant) do |model|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
88
|
+
state_machines.each do |state_machine|
|
89
|
+
namespace = state_machine.__send__(:namespace)
|
90
|
+
|
91
|
+
# Create all of the constants and methods for each state
|
92
|
+
state_machine.states.each do |state|
|
93
|
+
name = state.name
|
94
|
+
name = "#{namespace}_#{name}" if namespace
|
95
|
+
|
96
|
+
model.create_constant("STATE_#{name.upcase}", value: "T.let(T.unsafe(nil), Symbol)")
|
97
|
+
model.create_method("#{name}?", return_type: "T::Boolean")
|
98
|
+
end
|
65
99
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
100
|
+
# Create all of the methods for each event
|
101
|
+
parameters = [create_rest_param("opts", type: "T.untyped")]
|
102
|
+
state_machine.events.each do |event|
|
103
|
+
model.create_method(event.name.to_s, parameters: parameters)
|
104
|
+
model.create_method("#{event.name}!", parameters: parameters)
|
105
|
+
model.create_method("#{event.name}_without_validation!", parameters: parameters)
|
106
|
+
model.create_method("may_#{event.name}?", return_type: "T::Boolean")
|
107
|
+
|
108
|
+
# For events, if there's a namespace the default methods are created in addition to
|
109
|
+
# namespaced ones.
|
110
|
+
next unless namespace
|
111
|
+
|
112
|
+
name = "#{event.name}_#{namespace}"
|
113
|
+
|
114
|
+
model.create_method(name.to_s, parameters: parameters)
|
115
|
+
model.create_method("#{name}!", parameters: parameters)
|
116
|
+
model.create_method("may_#{name}?", return_type: "T::Boolean")
|
117
|
+
|
118
|
+
# There's no namespaced method created for `_without_validation`, so skip
|
119
|
+
# defining a method for:
|
120
|
+
# "#{name}_without_validation!"
|
121
|
+
end
|
73
122
|
end
|
74
123
|
|
75
124
|
# Create the overall state machine method, which will return an
|
@@ -97,6 +146,18 @@ module Tapioca
|
|
97
146
|
],
|
98
147
|
)
|
99
148
|
|
149
|
+
constant_name = name_of(constant)
|
150
|
+
|
151
|
+
GLOBAL_CALLBACKS.each do |method|
|
152
|
+
machine.create_method(
|
153
|
+
method,
|
154
|
+
parameters: [
|
155
|
+
create_opt_param("symbol", type: "T.nilable(Symbol)", default: "nil"),
|
156
|
+
create_block_param("block", type: "T.nilable(T.proc.bind(#{constant_name}).void)"),
|
157
|
+
],
|
158
|
+
)
|
159
|
+
end
|
160
|
+
|
100
161
|
# Create a private event class that we can pass around for the
|
101
162
|
# purpose of binding all of the callbacks without having to
|
102
163
|
# explicitly bind self in each one.
|
@@ -106,7 +167,7 @@ module Tapioca
|
|
106
167
|
method,
|
107
168
|
parameters: [
|
108
169
|
create_opt_param("symbol", type: "T.nilable(Symbol)", default: "nil"),
|
109
|
-
create_block_param("block", type: "T.nilable(T.proc.bind(#{
|
170
|
+
create_block_param("block", type: "T.nilable(T.proc.bind(#{constant_name}).void)"),
|
110
171
|
],
|
111
172
|
)
|
112
173
|
end
|
@@ -156,7 +156,7 @@ module Tapioca
|
|
156
156
|
sig { params(mod: Module).returns(T::Array[String]) }
|
157
157
|
def gather_includes(mod)
|
158
158
|
mod.ancestors
|
159
|
-
.reject { |ancestor| ancestor.is_a?(Class) || ancestor == mod || ancestor.
|
159
|
+
.reject { |ancestor| ancestor.is_a?(Class) || ancestor == mod || name_of(ancestor).nil? }
|
160
160
|
.map { |ancestor| T.must(qualified_name_of(ancestor)) }
|
161
161
|
.reverse
|
162
162
|
end
|
@@ -16,7 +16,8 @@ module Tapioca
|
|
16
16
|
# `Tapioca::Dsl::Compilers::ActiveRecordColumns` refines RBI files for subclasses of
|
17
17
|
# [`ActiveRecord::Base`](https://api.rubyonrails.org/classes/ActiveRecord/Base.html).
|
18
18
|
# This compiler is only responsible for defining the attribute methods that would be
|
19
|
-
# created for
|
19
|
+
# created for columns and virtual attributes that are defined in the Active Record
|
20
|
+
# model.
|
20
21
|
#
|
21
22
|
# For example, with the following model class:
|
22
23
|
# ~~~rb
|
@@ -109,8 +110,7 @@ module Tapioca
|
|
109
110
|
|
110
111
|
root.create_path(constant) do |model|
|
111
112
|
model.create_module(AttributeMethodsModuleName) do |mod|
|
112
|
-
constant.
|
113
|
-
column_name = column_name.to_s
|
113
|
+
constant.attribute_names.each do |column_name|
|
114
114
|
add_methods_for_attribute(mod, column_name)
|
115
115
|
end
|
116
116
|
|
@@ -72,11 +72,14 @@ module Tapioca
|
|
72
72
|
|
73
73
|
sig { returns(Class) }
|
74
74
|
def fixture_loader
|
75
|
-
@fixture_loader ||= T.let(
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
75
|
+
@fixture_loader ||= T.let(
|
76
|
+
Class.new do
|
77
|
+
T.unsafe(self).include(ActiveRecord::TestFixtures)
|
78
|
+
T.unsafe(self).fixture_path = Rails.root.join("test", "fixtures")
|
79
|
+
T.unsafe(self).fixtures(:all)
|
80
|
+
end,
|
81
|
+
T.nilable(Class),
|
82
|
+
)
|
80
83
|
end
|
81
84
|
|
82
85
|
sig { returns(T::Array[String]) }
|