tapioca 0.10.5 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/tapioca/cli.rb +5 -1
- 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/dsl/compilers/aasm.rb +67 -15
- 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_relations.rb +117 -66
- 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/graphql_input_object.rb +21 -1
- data/lib/tapioca/dsl/compilers/kredis.rb +130 -0
- 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_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/pipeline.rb +14 -0
- data/lib/tapioca/loaders/loader.rb +93 -32
- data/lib/tapioca/rbi_ext/model.rb +1 -1
- 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/static/symbol_loader.rb +14 -14
- data/lib/tapioca/version.rb +1 -1
- 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
@@ -130,11 +130,15 @@ module Tapioca
|
|
130
130
|
type: :string,
|
131
131
|
desc: "The path to the Rails application",
|
132
132
|
default: "."
|
133
|
-
def dsl(*
|
133
|
+
def dsl(*constant_or_paths)
|
134
134
|
set_environment(options)
|
135
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
|
+
|
136
139
|
command = Commands::Dsl.new(
|
137
140
|
requested_constants: constants,
|
141
|
+
requested_paths: paths.map { |p| Pathname.new(p) },
|
138
142
|
outpath: Pathname.new(options[:outdir]),
|
139
143
|
only: options[:only],
|
140
144
|
exclude: options[:exclude],
|
@@ -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
|
|
@@ -58,27 +58,67 @@ module Tapioca
|
|
58
58
|
T::Array[String],
|
59
59
|
)
|
60
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,
|
74
|
+
T::Array[String],
|
75
|
+
)
|
76
|
+
|
61
77
|
ConstantType = type_member { { fixed: T.all(::AASM::ClassMethods, Class) } }
|
62
78
|
|
63
79
|
sig { override.void }
|
64
80
|
def decorate
|
65
|
-
|
66
|
-
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? }
|
67
86
|
|
68
87
|
root.create_path(constant) do |model|
|
69
|
-
|
70
|
-
|
71
|
-
model.create_constant("STATE_#{state.name.upcase}", value: "T.let(T.unsafe(nil), Symbol)")
|
72
|
-
model.create_method("#{state.name}?", return_type: "T::Boolean")
|
73
|
-
end
|
88
|
+
state_machines.each do |state_machine|
|
89
|
+
namespace = state_machine.__send__(:namespace)
|
74
90
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
99
|
+
|
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
|
82
122
|
end
|
83
123
|
|
84
124
|
# Create the overall state machine method, which will return an
|
@@ -106,6 +146,18 @@ module Tapioca
|
|
106
146
|
],
|
107
147
|
)
|
108
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
|
+
|
109
161
|
# Create a private event class that we can pass around for the
|
110
162
|
# purpose of binding all of the callbacks without having to
|
111
163
|
# explicitly bind self in each one.
|
@@ -115,7 +167,7 @@ module Tapioca
|
|
115
167
|
method,
|
116
168
|
parameters: [
|
117
169
|
create_opt_param("symbol", type: "T.nilable(Symbol)", default: "nil"),
|
118
|
-
create_block_param("block", type: "T.nilable(T.proc.bind(#{
|
170
|
+
create_block_param("block", type: "T.nilable(T.proc.bind(#{constant_name}).void)"),
|
119
171
|
],
|
120
172
|
)
|
121
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
|
|