tapioca 0.4.27 → 0.5.3
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/Gemfile +15 -15
- data/README.md +2 -2
- data/Rakefile +5 -7
- data/exe/tapioca +2 -2
- data/lib/tapioca/cli.rb +172 -2
- data/lib/tapioca/compilers/dsl/aasm.rb +122 -0
- data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +52 -12
- data/lib/tapioca/compilers/dsl/action_mailer.rb +6 -9
- data/lib/tapioca/compilers/dsl/active_job.rb +8 -12
- data/lib/tapioca/compilers/dsl/active_model_attributes.rb +131 -0
- data/lib/tapioca/compilers/dsl/active_model_secure_password.rb +101 -0
- data/lib/tapioca/compilers/dsl/active_record_associations.rb +33 -54
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +10 -105
- data/lib/tapioca/compilers/dsl/active_record_enum.rb +8 -10
- data/lib/tapioca/compilers/dsl/active_record_fixtures.rb +86 -0
- data/lib/tapioca/compilers/dsl/active_record_scope.rb +7 -10
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +5 -8
- data/lib/tapioca/compilers/dsl/active_resource.rb +9 -37
- data/lib/tapioca/compilers/dsl/active_storage.rb +98 -0
- data/lib/tapioca/compilers/dsl/active_support_concern.rb +106 -0
- data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +13 -8
- data/lib/tapioca/compilers/dsl/base.rb +108 -82
- data/lib/tapioca/compilers/dsl/config.rb +111 -0
- data/lib/tapioca/compilers/dsl/frozen_record.rb +5 -7
- data/lib/tapioca/compilers/dsl/identity_cache.rb +66 -29
- data/lib/tapioca/compilers/dsl/mixed_in_class_attributes.rb +74 -0
- data/lib/tapioca/compilers/dsl/protobuf.rb +19 -69
- data/lib/tapioca/compilers/dsl/sidekiq_worker.rb +25 -12
- data/lib/tapioca/compilers/dsl/smart_properties.rb +21 -33
- data/lib/tapioca/compilers/dsl/state_machines.rb +56 -78
- data/lib/tapioca/compilers/dsl/url_helpers.rb +7 -10
- data/lib/tapioca/compilers/dsl_compiler.rb +25 -40
- data/lib/tapioca/compilers/dynamic_mixin_compiler.rb +198 -0
- data/lib/tapioca/compilers/requires_compiler.rb +2 -2
- data/lib/tapioca/compilers/sorbet.rb +25 -5
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +122 -206
- data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +4 -4
- data/lib/tapioca/compilers/symbol_table_compiler.rb +5 -11
- data/lib/tapioca/compilers/todos_compiler.rb +1 -1
- data/lib/tapioca/config.rb +3 -0
- data/lib/tapioca/config_builder.rb +5 -2
- data/lib/tapioca/constant_locator.rb +6 -8
- data/lib/tapioca/gemfile.rb +14 -11
- data/lib/tapioca/generators/base.rb +61 -0
- data/lib/tapioca/generators/dsl.rb +362 -0
- data/lib/tapioca/generators/gem.rb +345 -0
- data/lib/tapioca/generators/init.rb +79 -0
- data/lib/tapioca/generators/require.rb +52 -0
- data/lib/tapioca/generators/todo.rb +76 -0
- data/lib/tapioca/generators.rb +9 -0
- data/lib/tapioca/generic_type_registry.rb +25 -98
- data/lib/tapioca/helpers/active_record_column_type_helper.rb +98 -0
- data/lib/tapioca/internal.rb +2 -10
- data/lib/tapioca/loader.rb +11 -31
- data/lib/tapioca/rbi_ext/model.rb +166 -0
- data/lib/tapioca/reflection.rb +138 -0
- data/lib/tapioca/sorbet_ext/fixed_hash_patch.rb +1 -1
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +72 -4
- data/lib/tapioca/sorbet_ext/name_patch.rb +1 -1
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +3 -0
- metadata +45 -23
- data/lib/tapioca/cli/main.rb +0 -146
- data/lib/tapioca/core_ext/class.rb +0 -28
- data/lib/tapioca/core_ext/string.rb +0 -18
- data/lib/tapioca/generator.rb +0 -633
- data/lib/tapioca/rbi/model.rb +0 -405
- data/lib/tapioca/rbi/printer.rb +0 -410
- data/lib/tapioca/rbi/rewriters/group_nodes.rb +0 -106
- data/lib/tapioca/rbi/rewriters/nest_non_public_methods.rb +0 -65
- data/lib/tapioca/rbi/rewriters/nest_singleton_methods.rb +0 -42
- data/lib/tapioca/rbi/rewriters/sort_nodes.rb +0 -86
- data/lib/tapioca/rbi/visitor.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8201f29f7abb78a5625f206893b18ff2a8f1ac9ffcae2784a90446764680bda3
|
4
|
+
data.tar.gz: 680b85b7a109985b60e4a727fd3295507daec445f26983703c6ba27a2882b24a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0df81ab9e557367adc414569a5bc67e581b2c98a13aa728ba46bcc831dfe490d4c3b81b9fe828c677f9eae74521b94f13c2217014dd900ddbe43144085f1cb83
|
7
|
+
data.tar.gz: 72f0f551108b0d1e2d3b7ce5420ff638fc81bec650a1563b5f0223c04b4646ce625cf5203b047495c873b4cb454b7fd2d910cafffd1afc39b987bac081b7e958
|
data/Gemfile
CHANGED
@@ -11,28 +11,28 @@ gem("pry-byebug")
|
|
11
11
|
gem("rubocop-shopify", require: false)
|
12
12
|
gem("rubocop-sorbet", ">= 0.4.1")
|
13
13
|
gem("sorbet")
|
14
|
-
gem("yard", "~> 0.9.25")
|
15
14
|
|
16
15
|
group(:deployment, :development) do
|
17
16
|
gem("rake")
|
18
17
|
end
|
19
18
|
|
20
19
|
group(:development, :test) do
|
21
|
-
gem("smart_properties",
|
22
|
-
gem("frozen_record",
|
23
|
-
gem("sprockets",
|
24
|
-
gem("rails",
|
25
|
-
gem("state_machines",
|
26
|
-
gem("activerecord-typedstore",
|
20
|
+
gem("smart_properties", require: false)
|
21
|
+
gem("frozen_record", require: false)
|
22
|
+
gem("sprockets", require: false)
|
23
|
+
gem("rails", require: false)
|
24
|
+
gem("state_machines", require: false)
|
25
|
+
gem("activerecord-typedstore", require: false)
|
27
26
|
gem("sqlite3")
|
28
|
-
gem("identity_cache",
|
27
|
+
gem("identity_cache", require: false)
|
29
28
|
gem("cityhash", git: "https://github.com/csfrancis/cityhash.git",
|
30
29
|
ref: "3cfc7d01f333c01811d5e834f1495eaa29f87c36", require: false)
|
31
|
-
gem("
|
32
|
-
gem("
|
33
|
-
gem("
|
34
|
-
|
35
|
-
gem("
|
36
|
-
gem("
|
37
|
-
gem("
|
30
|
+
gem("activeresource", require: false)
|
31
|
+
gem("google-protobuf", require: false)
|
32
|
+
gem("shopify-money", require: false)
|
33
|
+
gem("sidekiq", require: false)
|
34
|
+
gem("nokogiri", require: false)
|
35
|
+
gem("config", require: false)
|
36
|
+
gem("aasm", require: false)
|
37
|
+
gem("bcrypt", require: false)
|
38
38
|
end
|
data/README.md
CHANGED
@@ -117,8 +117,8 @@ This will generate DSL RBIs for specified constants (or for all handled constant
|
|
117
117
|
|
118
118
|
## Contributing
|
119
119
|
|
120
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/tapioca. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://github.com/Shopify/tapioca/blob/
|
120
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/tapioca. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://github.com/Shopify/tapioca/blob/main/CODE_OF_CONDUCT.md) code of conduct.
|
121
121
|
|
122
122
|
## License
|
123
123
|
|
124
|
-
The gem is available as open source under the terms of the [MIT License](https://github.com/Shopify/tapioca/blob/
|
124
|
+
The gem is available as open source under the terms of the [MIT License](https://github.com/Shopify/tapioca/blob/main/LICENSE.txt).
|
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require "rake/testtask"
|
5
|
-
Dir[
|
5
|
+
Dir["tasks/**/*.rake"].each { |t| load t }
|
6
6
|
|
7
7
|
Rake.application.options.trace = false
|
8
8
|
|
@@ -10,15 +10,13 @@ Rake::TestTask.new do |t|
|
|
10
10
|
t.libs << "lib"
|
11
11
|
t.libs << "spec"
|
12
12
|
t.warning = false
|
13
|
-
t.test_files = FileList[
|
13
|
+
t.test_files = FileList["spec/**/*_spec.rb"]
|
14
14
|
end
|
15
15
|
|
16
16
|
task(:spec) do
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
exit(1)
|
21
|
-
end
|
17
|
+
Rake::Task[:test].execute
|
18
|
+
rescue RuntimeError
|
19
|
+
exit(1)
|
22
20
|
end
|
23
21
|
|
24
22
|
task(default: :spec)
|
data/exe/tapioca
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
4
|
+
require "sorbet-runtime"
|
5
5
|
|
6
6
|
begin
|
7
7
|
T::Configuration.default_checked_level = :never
|
@@ -20,4 +20,4 @@ end
|
|
20
20
|
|
21
21
|
require_relative "../lib/tapioca/internal"
|
22
22
|
|
23
|
-
Tapioca::Cli
|
23
|
+
Tapioca::Cli.start(ARGV)
|
data/lib/tapioca/cli.rb
CHANGED
@@ -1,8 +1,178 @@
|
|
1
1
|
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
4
|
+
require "thor"
|
5
5
|
|
6
6
|
module Tapioca
|
7
|
-
|
7
|
+
class Cli < Thor
|
8
|
+
class_option :outdir,
|
9
|
+
aliases: ["--out", "-o"],
|
10
|
+
banner: "directory",
|
11
|
+
desc: "The output directory for generated RBI files"
|
12
|
+
class_option :generate_command,
|
13
|
+
aliases: ["--cmd", "-c"],
|
14
|
+
banner: "command",
|
15
|
+
desc: "The command to run to regenerate RBI files"
|
16
|
+
class_option :file_header,
|
17
|
+
type: :boolean,
|
18
|
+
default: true,
|
19
|
+
desc: "Add a \"This file is generated\" header on top of each generated RBI file"
|
20
|
+
class_option :verbose,
|
21
|
+
aliases: ["-V"],
|
22
|
+
type: :boolean,
|
23
|
+
default: false,
|
24
|
+
desc: "Verbose output for debugging purposes"
|
25
|
+
|
26
|
+
map T.unsafe(["--version", "-v"] => :__print_version)
|
27
|
+
|
28
|
+
desc "init", "initializes folder structure"
|
29
|
+
def init
|
30
|
+
generator = Generators::Init.new(
|
31
|
+
sorbet_config: Config::SORBET_CONFIG,
|
32
|
+
default_postrequire: Config::DEFAULT_POSTREQUIRE,
|
33
|
+
default_command: Config::DEFAULT_COMMAND
|
34
|
+
)
|
35
|
+
generator.generate
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "require", "generate the list of files to be required by tapioca"
|
39
|
+
def require
|
40
|
+
generator = Generators::Require.new(
|
41
|
+
requires_path: ConfigBuilder.from_options(:require, options).postrequire,
|
42
|
+
sorbet_config_path: Config::SORBET_CONFIG,
|
43
|
+
default_command: Config::DEFAULT_COMMAND
|
44
|
+
)
|
45
|
+
Tapioca.silence_warnings do
|
46
|
+
generator.generate
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "todo", "generate the list of unresolved constants"
|
51
|
+
def todo
|
52
|
+
current_command = T.must(current_command_chain.first)
|
53
|
+
config = ConfigBuilder.from_options(current_command, options)
|
54
|
+
generator = Generators::Todo.new(
|
55
|
+
todos_path: config.todos_path,
|
56
|
+
file_header: config.file_header,
|
57
|
+
default_command: Config::DEFAULT_COMMAND
|
58
|
+
)
|
59
|
+
Tapioca.silence_warnings do
|
60
|
+
generator.generate
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "dsl [constant...]", "generate RBIs for dynamic methods"
|
65
|
+
option :generators,
|
66
|
+
type: :array,
|
67
|
+
aliases: ["--gen", "-g"],
|
68
|
+
banner: "generator [generator ...]",
|
69
|
+
desc: "Only run supplied DSL generators"
|
70
|
+
option :exclude_generators,
|
71
|
+
type: :array,
|
72
|
+
banner: "generator [generator ...]",
|
73
|
+
desc: "Exclude supplied DSL generators"
|
74
|
+
option :verify,
|
75
|
+
type: :boolean,
|
76
|
+
default: false,
|
77
|
+
desc: "Verifies RBIs are up-to-date"
|
78
|
+
option :quiet,
|
79
|
+
aliases: ["-q"],
|
80
|
+
type: :boolean,
|
81
|
+
desc: "Supresses file creation output"
|
82
|
+
def dsl(*constants)
|
83
|
+
current_command = T.must(current_command_chain.first)
|
84
|
+
config = ConfigBuilder.from_options(current_command, options)
|
85
|
+
generator = Generators::Dsl.new(
|
86
|
+
requested_constants: constants,
|
87
|
+
outpath: config.outpath,
|
88
|
+
generators: config.generators,
|
89
|
+
exclude_generators: config.exclude_generators,
|
90
|
+
file_header: config.file_header,
|
91
|
+
compiler_path: Tapioca::Compilers::Dsl::COMPILERS_PATH,
|
92
|
+
tapioca_path: Config::TAPIOCA_PATH,
|
93
|
+
default_command: Config::DEFAULT_COMMAND,
|
94
|
+
should_verify: options[:verify],
|
95
|
+
quiet: options[:quiet],
|
96
|
+
verbose: options[:verbose]
|
97
|
+
)
|
98
|
+
Tapioca.silence_warnings do
|
99
|
+
generator.generate
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
desc "gem [gem...]", "generate RBIs from gems"
|
104
|
+
option :all,
|
105
|
+
type: :boolean,
|
106
|
+
default: false,
|
107
|
+
desc: "Regenerate RBI files for all gems"
|
108
|
+
option :prerequire,
|
109
|
+
aliases: ["--pre", "-b"],
|
110
|
+
banner: "file",
|
111
|
+
desc: "A file to be required before Bundler.require is called"
|
112
|
+
option :postrequire,
|
113
|
+
aliases: ["--post", "-a"],
|
114
|
+
banner: "file",
|
115
|
+
desc: "A file to be required after Bundler.require is called"
|
116
|
+
option :exclude,
|
117
|
+
aliases: ["-x"],
|
118
|
+
type: :array,
|
119
|
+
banner: "gem [gem ...]",
|
120
|
+
desc: "Excludes the given gem(s) from RBI generation"
|
121
|
+
option :typed_overrides,
|
122
|
+
aliases: ["--typed", "-t"],
|
123
|
+
type: :hash,
|
124
|
+
banner: "gem:level [gem:level ...]",
|
125
|
+
desc: "Overrides for typed sigils for generated gem RBIs"
|
126
|
+
option :verify,
|
127
|
+
type: :boolean,
|
128
|
+
default: false,
|
129
|
+
desc: "Verifies RBIs are up-to-date"
|
130
|
+
option :doc,
|
131
|
+
type: :boolean,
|
132
|
+
default: false,
|
133
|
+
desc: "Include YARD documentation from sources when generating RBIs. Warning: this might be slow"
|
134
|
+
def gem(*gems)
|
135
|
+
Tapioca.silence_warnings do
|
136
|
+
all = options[:all]
|
137
|
+
verify = options[:verify]
|
138
|
+
current_command = T.must(current_command_chain.first)
|
139
|
+
config = ConfigBuilder.from_options(current_command, options)
|
140
|
+
generator = Generators::Gem.new(
|
141
|
+
gem_names: all ? [] : gems,
|
142
|
+
gem_excludes: config.exclude,
|
143
|
+
prerequire: config.prerequire,
|
144
|
+
postrequire: config.postrequire,
|
145
|
+
typed_overrides: config.typed_overrides,
|
146
|
+
default_command: Config::DEFAULT_COMMAND,
|
147
|
+
outpath: config.outpath,
|
148
|
+
file_header: config.file_header,
|
149
|
+
doc: config.doc
|
150
|
+
)
|
151
|
+
|
152
|
+
raise MalformattedArgumentError, "Options '--all' and '--verify' are mutually exclusive" if all && verify
|
153
|
+
|
154
|
+
unless gems.empty?
|
155
|
+
raise MalformattedArgumentError, "Option '--all' must be provided without any other arguments" if all
|
156
|
+
raise MalformattedArgumentError, "Option '--verify' must be provided without any other arguments" if verify
|
157
|
+
end
|
158
|
+
|
159
|
+
if gems.empty? && !all
|
160
|
+
generator.sync(should_verify: verify)
|
161
|
+
else
|
162
|
+
generator.generate
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
desc "--version, -v", "show version"
|
168
|
+
def __print_version
|
169
|
+
puts "Tapioca v#{Tapioca::VERSION}"
|
170
|
+
end
|
171
|
+
|
172
|
+
no_commands do
|
173
|
+
def self.exit_on_failure?
|
174
|
+
true
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
8
178
|
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "active_record"
|
6
|
+
require "aasm"
|
7
|
+
rescue LoadError
|
8
|
+
return
|
9
|
+
end
|
10
|
+
|
11
|
+
module Tapioca
|
12
|
+
module Compilers
|
13
|
+
module Dsl
|
14
|
+
# `Tapioca::Compilers::Dsl::AASM` generate types for AASM state machines.
|
15
|
+
# This gem dynamically defines constants and methods at runtime. For
|
16
|
+
# example, given a class:
|
17
|
+
#
|
18
|
+
# class MyClass
|
19
|
+
# include AASM
|
20
|
+
#
|
21
|
+
# aasm do
|
22
|
+
# state :sleeping, initial: true
|
23
|
+
# state :running, :cleaning
|
24
|
+
#
|
25
|
+
# event :run do
|
26
|
+
# transitions from: :sleeping, to: :running
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# This will result in the following constants being defined:
|
32
|
+
#
|
33
|
+
# STATE_SLEEPING, STATE_RUNNING, STATE_CLEANING
|
34
|
+
#
|
35
|
+
# and the following methods being defined:
|
36
|
+
#
|
37
|
+
# sleeping?, running?, cleaning?
|
38
|
+
# run, run!, run_without_validation!, may_run?
|
39
|
+
#
|
40
|
+
class AASM < Tapioca::Compilers::Dsl::Base
|
41
|
+
extend T::Sig
|
42
|
+
|
43
|
+
# Taken directly from the AASM::Core::Event class, here:
|
44
|
+
# https://github.com/aasm/aasm/blob/0e03746/lib/aasm/core/event.rb#L21-L29
|
45
|
+
EVENT_CALLBACKS =
|
46
|
+
T.let(
|
47
|
+
["after", "after_commit", "after_transaction", "before", "before_transaction", "ensure", "error",
|
48
|
+
"before_success", "success"].freeze,
|
49
|
+
T::Array[String]
|
50
|
+
)
|
51
|
+
|
52
|
+
sig { override.params(root: RBI::Tree, constant: T.all(::AASM::ClassMethods, Class)).void }
|
53
|
+
def decorate(root, constant)
|
54
|
+
aasm = constant.aasm
|
55
|
+
return if !aasm || aasm.states.empty?
|
56
|
+
|
57
|
+
root.create_path(constant) do |model|
|
58
|
+
# Create all of the constants and methods for each state
|
59
|
+
aasm.states.each do |state|
|
60
|
+
model.create_constant("STATE_#{state.name.upcase}", value: "T.let(T.unsafe(nil), Symbol)")
|
61
|
+
model.create_method("#{state.name}?", return_type: "T::Boolean")
|
62
|
+
end
|
63
|
+
|
64
|
+
# Create all of the methods for each event
|
65
|
+
parameters = [create_rest_param("opts", type: "T.untyped")]
|
66
|
+
aasm.events.each do |event|
|
67
|
+
model.create_method(event.name.to_s, parameters: parameters)
|
68
|
+
model.create_method("#{event.name}!", parameters: parameters)
|
69
|
+
model.create_method("#{event.name}_without_validation!", parameters: parameters)
|
70
|
+
model.create_method("may_#{event.name}?", return_type: "T::Boolean")
|
71
|
+
end
|
72
|
+
|
73
|
+
# Create the overall state machine method, which will return an
|
74
|
+
# instance of the PrivateAASMMachine class.
|
75
|
+
model.create_method(
|
76
|
+
"aasm",
|
77
|
+
parameters: [
|
78
|
+
create_rest_param("args", type: "T.untyped"),
|
79
|
+
create_block_param("block", type: "T.nilable(T.proc.bind(PrivateAASMMachine).void)"),
|
80
|
+
],
|
81
|
+
return_type: "PrivateAASMMachine",
|
82
|
+
class_method: true
|
83
|
+
)
|
84
|
+
|
85
|
+
# Create a private machine class that we can pass around for the
|
86
|
+
# purpose of binding various procs passed to methods without having
|
87
|
+
# to explicitly bind self in each one.
|
88
|
+
model.create_class("PrivateAASMMachine", superclass_name: "AASM::Base") do |machine|
|
89
|
+
machine.create_method(
|
90
|
+
"event",
|
91
|
+
parameters: [
|
92
|
+
create_param("name", type: "T.untyped"),
|
93
|
+
create_opt_param("options", default: "nil", type: "T.untyped"),
|
94
|
+
create_block_param("block", type: "T.proc.bind(PrivateAASMEvent).void"),
|
95
|
+
]
|
96
|
+
)
|
97
|
+
|
98
|
+
# Create a private event class that we can pass around for the
|
99
|
+
# purpose of binding all of the callbacks without having to
|
100
|
+
# explicitly bind self in each one.
|
101
|
+
machine.create_class("PrivateAASMEvent", superclass_name: "AASM::Core::Event") do |event|
|
102
|
+
EVENT_CALLBACKS.each do |method|
|
103
|
+
event.create_method(
|
104
|
+
method,
|
105
|
+
parameters: [
|
106
|
+
create_block_param("block", type: "T.proc.bind(#{constant.name}).void"),
|
107
|
+
]
|
108
|
+
)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
sig { override.returns(T::Enumerable[Module]) }
|
116
|
+
def gather_constants
|
117
|
+
T.cast(ObjectSpace.each_object(::AASM::ClassMethods), T::Enumerable[Module])
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "parlour"
|
5
|
-
|
6
4
|
begin
|
7
5
|
require "action_controller"
|
8
6
|
rescue LoadError
|
@@ -72,38 +70,54 @@ module Tapioca
|
|
72
70
|
|
73
71
|
sig do
|
74
72
|
override
|
75
|
-
.params(root:
|
73
|
+
.params(root: RBI::Tree, constant: T.class_of(::ActionController::Base))
|
76
74
|
.void
|
77
75
|
end
|
78
76
|
def decorate(root, constant)
|
77
|
+
helpers_module = constant._helpers
|
78
|
+
proxied_helper_methods = constant._helper_methods.map(&:to_s).map(&:to_sym)
|
79
|
+
|
79
80
|
helper_proxy_name = "HelperProxy"
|
80
81
|
helper_methods_name = "HelperMethods"
|
81
|
-
proxied_helper_methods = constant._helper_methods.map(&:to_s).map(&:to_sym)
|
82
82
|
|
83
83
|
# Define the helpers method
|
84
|
-
root.
|
85
|
-
create_method(
|
84
|
+
root.create_path(constant) do |controller|
|
85
|
+
controller.create_method("helpers", return_type: helper_proxy_name)
|
86
86
|
|
87
87
|
# Create helper method module
|
88
88
|
controller.create_module(helper_methods_name) do |helper_methods|
|
89
|
-
|
89
|
+
# If the controller has no helper defined, then it just inherits
|
90
|
+
# the Action Controlller base helper methods module, so we should
|
91
|
+
# just add that as an include and stop doing more processing.
|
92
|
+
if helpers_module.name == "ActionController::Base::HelperMethods"
|
93
|
+
next helper_methods.create_include(T.must(qualified_name_of(helpers_module)))
|
94
|
+
end
|
90
95
|
|
96
|
+
# Find all the included helper modules and generate an include
|
97
|
+
# for each of those helper modules
|
91
98
|
gather_includes(helpers_module).each do |ancestor|
|
92
99
|
helper_methods.create_include(ancestor)
|
93
100
|
end
|
94
101
|
|
102
|
+
# Generate a method definition in the helper module for each
|
103
|
+
# helper method defined via the `helper_method` call in the controller.
|
95
104
|
helpers_module.instance_methods(false).each do |method_name|
|
96
105
|
method = if proxied_helper_methods.include?(method_name)
|
97
|
-
constant
|
106
|
+
helper_method_proxy_target(constant, method_name)
|
98
107
|
else
|
99
108
|
helpers_module.instance_method(method_name)
|
100
109
|
end
|
101
|
-
|
110
|
+
|
111
|
+
if method
|
112
|
+
create_method_from_def(helper_methods, method)
|
113
|
+
else
|
114
|
+
create_unknown_proxy_method(helper_methods, method_name)
|
115
|
+
end
|
102
116
|
end
|
103
117
|
end
|
104
118
|
|
105
119
|
# Create helper proxy class
|
106
|
-
controller.create_class(helper_proxy_name,
|
120
|
+
controller.create_class(helper_proxy_name, superclass_name: "::ActionView::Base") do |proxy|
|
107
121
|
proxy.create_include(helper_methods_name)
|
108
122
|
end
|
109
123
|
end
|
@@ -111,16 +125,42 @@ module Tapioca
|
|
111
125
|
|
112
126
|
sig { override.returns(T::Enumerable[Module]) }
|
113
127
|
def gather_constants
|
114
|
-
::ActionController::Base.
|
128
|
+
descendants_of(::ActionController::Base).reject(&:abstract?).select(&:name)
|
115
129
|
end
|
116
130
|
|
117
131
|
private
|
118
132
|
|
133
|
+
sig do
|
134
|
+
params(
|
135
|
+
constant: T.class_of(::ActionController::Base),
|
136
|
+
method_name: Symbol
|
137
|
+
).returns(T.nilable(UnboundMethod))
|
138
|
+
end
|
139
|
+
def helper_method_proxy_target(constant, method_name)
|
140
|
+
# Lookup the proxy target method only if it is defined as a public/protected or private method.
|
141
|
+
if constant.method_defined?(method_name) || constant.private_method_defined?(method_name)
|
142
|
+
constant.instance_method(method_name)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
sig { params(helper_methods: RBI::Scope, method_name: Symbol).void }
|
147
|
+
def create_unknown_proxy_method(helper_methods, method_name)
|
148
|
+
helper_methods.create_method(
|
149
|
+
method_name.to_s,
|
150
|
+
parameters: [
|
151
|
+
create_rest_param("args", type: "T.untyped"),
|
152
|
+
create_kw_rest_param("kwargs", type: "T.untyped"),
|
153
|
+
create_block_param("blk", type: "T.untyped"),
|
154
|
+
],
|
155
|
+
return_type: "T.untyped"
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
119
159
|
sig { params(mod: Module).returns(T::Array[String]) }
|
120
160
|
def gather_includes(mod)
|
121
161
|
mod.ancestors
|
122
162
|
.reject { |ancestor| ancestor.is_a?(Class) || ancestor == mod || ancestor.name.nil? }
|
123
|
-
.map { |ancestor|
|
163
|
+
.map { |ancestor| T.must(qualified_name_of(ancestor)) }
|
124
164
|
.reverse
|
125
165
|
end
|
126
166
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "parlour"
|
5
|
-
|
6
4
|
begin
|
7
5
|
require "action_mailer"
|
8
6
|
rescue LoadError
|
@@ -38,17 +36,16 @@ module Tapioca
|
|
38
36
|
class ActionMailer < Base
|
39
37
|
extend T::Sig
|
40
38
|
|
41
|
-
sig { override.params(root:
|
39
|
+
sig { override.params(root: RBI::Tree, constant: T.class_of(::ActionMailer::Base)).void }
|
42
40
|
def decorate(root, constant)
|
43
|
-
root.
|
41
|
+
root.create_path(constant) do |mailer|
|
44
42
|
constant.action_methods.to_a.each do |mailer_method|
|
45
43
|
method_def = constant.instance_method(mailer_method)
|
46
|
-
parameters =
|
47
|
-
create_method(
|
48
|
-
mailer,
|
44
|
+
parameters = compile_method_parameters_to_rbi(method_def)
|
45
|
+
mailer.create_method(
|
49
46
|
mailer_method,
|
50
47
|
parameters: parameters,
|
51
|
-
return_type:
|
48
|
+
return_type: "::ActionMailer::MessageDelivery",
|
52
49
|
class_method: true
|
53
50
|
)
|
54
51
|
end
|
@@ -57,7 +54,7 @@ module Tapioca
|
|
57
54
|
|
58
55
|
sig { override.returns(T::Enumerable[Module]) }
|
59
56
|
def gather_constants
|
60
|
-
::ActionMailer::Base.
|
57
|
+
descendants_of(::ActionMailer::Base).reject(&:abstract?)
|
61
58
|
end
|
62
59
|
end
|
63
60
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "parlour"
|
5
|
-
|
6
4
|
begin
|
7
5
|
require "active_job"
|
8
6
|
rescue LoadError
|
@@ -42,25 +40,23 @@ module Tapioca
|
|
42
40
|
class ActiveJob < Base
|
43
41
|
extend T::Sig
|
44
42
|
|
45
|
-
sig { override.params(root:
|
43
|
+
sig { override.params(root: RBI::Tree, constant: T.class_of(::ActiveJob::Base)).void }
|
46
44
|
def decorate(root, constant)
|
47
|
-
|
48
|
-
next unless constant.instance_methods(false).include?(:perform)
|
45
|
+
return unless constant.instance_methods(false).include?(:perform)
|
49
46
|
|
47
|
+
root.create_path(constant) do |job|
|
50
48
|
method = constant.instance_method(:perform)
|
51
|
-
parameters =
|
52
|
-
return_type =
|
49
|
+
parameters = compile_method_parameters_to_rbi(method)
|
50
|
+
return_type = compile_method_return_type_to_rbi(method)
|
53
51
|
|
54
|
-
create_method(
|
55
|
-
job,
|
52
|
+
job.create_method(
|
56
53
|
"perform_later",
|
57
54
|
parameters: parameters,
|
58
55
|
return_type: "T.any(#{constant.name}, FalseClass)",
|
59
56
|
class_method: true
|
60
57
|
)
|
61
58
|
|
62
|
-
create_method(
|
63
|
-
job,
|
59
|
+
job.create_method(
|
64
60
|
"perform_now",
|
65
61
|
parameters: parameters,
|
66
62
|
return_type: return_type,
|
@@ -71,7 +67,7 @@ module Tapioca
|
|
71
67
|
|
72
68
|
sig { override.returns(T::Enumerable[Module]) }
|
73
69
|
def gather_constants
|
74
|
-
::ActiveJob::Base
|
70
|
+
descendants_of(::ActiveJob::Base)
|
75
71
|
end
|
76
72
|
end
|
77
73
|
end
|