tapioca 0.4.24 → 0.5.1

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +14 -14
  3. data/README.md +2 -2
  4. data/Rakefile +5 -7
  5. data/exe/tapioca +2 -2
  6. data/lib/tapioca/cli.rb +256 -2
  7. data/lib/tapioca/compilers/dsl/aasm.rb +122 -0
  8. data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +52 -12
  9. data/lib/tapioca/compilers/dsl/action_mailer.rb +6 -9
  10. data/lib/tapioca/compilers/dsl/active_job.rb +8 -12
  11. data/lib/tapioca/compilers/dsl/active_model_attributes.rb +131 -0
  12. data/lib/tapioca/compilers/dsl/active_record_associations.rb +33 -54
  13. data/lib/tapioca/compilers/dsl/active_record_columns.rb +10 -105
  14. data/lib/tapioca/compilers/dsl/active_record_enum.rb +8 -10
  15. data/lib/tapioca/compilers/dsl/active_record_scope.rb +7 -10
  16. data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +5 -8
  17. data/lib/tapioca/compilers/dsl/active_resource.rb +9 -37
  18. data/lib/tapioca/compilers/dsl/active_storage.rb +98 -0
  19. data/lib/tapioca/compilers/dsl/active_support_concern.rb +108 -0
  20. data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +13 -8
  21. data/lib/tapioca/compilers/dsl/base.rb +96 -82
  22. data/lib/tapioca/compilers/dsl/config.rb +111 -0
  23. data/lib/tapioca/compilers/dsl/frozen_record.rb +5 -7
  24. data/lib/tapioca/compilers/dsl/identity_cache.rb +66 -29
  25. data/lib/tapioca/compilers/dsl/protobuf.rb +19 -69
  26. data/lib/tapioca/compilers/dsl/sidekiq_worker.rb +25 -12
  27. data/lib/tapioca/compilers/dsl/smart_properties.rb +19 -31
  28. data/lib/tapioca/compilers/dsl/state_machines.rb +56 -78
  29. data/lib/tapioca/compilers/dsl/url_helpers.rb +7 -10
  30. data/lib/tapioca/compilers/dsl_compiler.rb +22 -38
  31. data/lib/tapioca/compilers/requires_compiler.rb +2 -2
  32. data/lib/tapioca/compilers/sorbet.rb +26 -5
  33. data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +139 -154
  34. data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +4 -4
  35. data/lib/tapioca/compilers/symbol_table_compiler.rb +1 -1
  36. data/lib/tapioca/compilers/todos_compiler.rb +1 -1
  37. data/lib/tapioca/config.rb +2 -0
  38. data/lib/tapioca/config_builder.rb +4 -2
  39. data/lib/tapioca/constant_locator.rb +6 -8
  40. data/lib/tapioca/gemfile.rb +26 -19
  41. data/lib/tapioca/generator.rb +127 -43
  42. data/lib/tapioca/generic_type_registry.rb +25 -98
  43. data/lib/tapioca/helpers/active_record_column_type_helper.rb +98 -0
  44. data/lib/tapioca/internal.rb +1 -9
  45. data/lib/tapioca/loader.rb +14 -48
  46. data/lib/tapioca/rbi_ext/model.rb +122 -0
  47. data/lib/tapioca/reflection.rb +131 -0
  48. data/lib/tapioca/sorbet_ext/fixed_hash_patch.rb +1 -1
  49. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +72 -4
  50. data/lib/tapioca/sorbet_ext/name_patch.rb +1 -1
  51. data/lib/tapioca/version.rb +1 -1
  52. data/lib/tapioca.rb +2 -0
  53. metadata +34 -22
  54. data/lib/tapioca/cli/main.rb +0 -146
  55. data/lib/tapioca/core_ext/class.rb +0 -28
  56. data/lib/tapioca/core_ext/string.rb +0 -18
  57. data/lib/tapioca/rbi/model.rb +0 -405
  58. data/lib/tapioca/rbi/printer.rb +0 -410
  59. data/lib/tapioca/rbi/rewriters/group_nodes.rb +0 -106
  60. data/lib/tapioca/rbi/rewriters/nest_non_public_methods.rb +0 -65
  61. data/lib/tapioca/rbi/rewriters/nest_singleton_methods.rb +0 -42
  62. data/lib/tapioca/rbi/rewriters/sort_nodes.rb +0 -86
  63. data/lib/tapioca/rbi/visitor.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3346249d6372983bf2f589dc19126ec052dc93701d360e30d5b3f6955ece4f03
4
- data.tar.gz: 68857527a145259323b58089e08caf23144fa9bc987de1a40b03ee4d0afa4bcb
3
+ metadata.gz: 0f8af6316243d26a0446636e00af5c9210296f5e5ac1f6065506af426d72c066
4
+ data.tar.gz: 7124feeb9e7ecc16c2de3897ae9dd2bd3a432be6295d66ab5c440c4377f6d1e1
5
5
  SHA512:
6
- metadata.gz: 5d1affdb8f87456291175700165c84a121834abb89dd2bee50fb746926d752f05f1001dda59dad7f3688b081c97d94971829ebef8ea622f05acc2d264cc69632
7
- data.tar.gz: 7ba8a6d28322f9155dcd4351b1d68e698038ae322154d71d2fc8c26d06135f816259355584ded1f57b5b1aad96ea364b5e5fad64ddc32bcbe0561ea89b993189
6
+ metadata.gz: 720a2022478adcffea11b8a52b486dec808544611c9792c8508224c8565a3a4aaaed9f0a512bf51417da1259275ba6dbbd09b318f5e8e438544ae54558e0e028
7
+ data.tar.gz: 8b5148ed02e2105b0c44134b98c99cb0e2c03144e8eca2293c8cf558b8dcff3141a5812141cb369e83cd830acb847a540f14303d2472ba7877518d4de55545ca
data/Gemfile CHANGED
@@ -18,21 +18,21 @@ group(:deployment, :development) do
18
18
  end
19
19
 
20
20
  group(:development, :test) do
21
- gem("smart_properties", ">= 1.15.0", require: false)
22
- gem("frozen_record", ">= 0.17", require: false)
23
- gem("sprockets", "~> 3.7", require: false)
24
- gem("rails", "~> 5.2", require: false)
25
- gem("state_machines", "~> 0.5.0", require: false)
26
- gem("activerecord-typedstore", "~> 1.3", require: false)
21
+ gem("smart_properties", require: false)
22
+ gem("frozen_record", require: false)
23
+ gem("sprockets", require: false)
24
+ gem("rails", require: false)
25
+ gem("state_machines", require: false)
26
+ gem("activerecord-typedstore", require: false)
27
27
  gem("sqlite3")
28
- gem("identity_cache", "~> 1.0", require: false)
28
+ gem("identity_cache", require: false)
29
29
  gem("cityhash", git: "https://github.com/csfrancis/cityhash.git",
30
30
  ref: "3cfc7d01f333c01811d5e834f1495eaa29f87c36", require: false)
31
- gem("activemodel-serializers-xml", "~> 1.0", require: false)
32
- gem("activeresource", "~> 5.1", require: false)
33
- gem("google-protobuf", "~> 3.12.0", require: false)
34
- # Fix version to 0.14.1 since it is the last version to support Ruby 2.4
35
- gem("shopify-money", "= 0.14.1", require: false)
36
- gem("sidekiq", "~> 5.0", require: false) # Version 6 dropped support for Ruby 2.4
37
- gem("nokogiri", "1.10.10", require: false) # Lock to last supported for Ruby 2.4
31
+ gem("activeresource", require: false)
32
+ gem("google-protobuf", require: false)
33
+ gem("shopify-money", require: false)
34
+ gem("sidekiq", require: false)
35
+ gem("nokogiri", require: false)
36
+ gem("config", require: false)
37
+ gem("aasm", 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/master/CODE_OF_CONDUCT.md) code of conduct.
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/master/LICENSE.txt).
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['tasks/**/*.rake'].each { |t| load t }
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['spec/**/*_spec.rb']
13
+ t.test_files = FileList["spec/**/*_spec.rb"]
14
14
  end
15
15
 
16
16
  task(:spec) do
17
- begin
18
- Rake::Task[:test].execute
19
- rescue RuntimeError
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 'sorbet-runtime'
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::Main.start(ARGV)
23
+ Tapioca::Cli.start(ARGV)
data/lib/tapioca/cli.rb CHANGED
@@ -1,8 +1,262 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'thor'
4
+ require "thor"
5
5
 
6
6
  module Tapioca
7
- module Cli; end
7
+ class Cli < Thor
8
+ include(Thor::Actions)
9
+
10
+ class_option :outdir,
11
+ aliases: ["--out", "-o"],
12
+ banner: "directory",
13
+ desc: "The output directory for generated RBI files"
14
+ class_option :generate_command,
15
+ aliases: ["--cmd", "-c"],
16
+ banner: "command",
17
+ desc: "The command to run to regenerate RBI files"
18
+ class_option :file_header,
19
+ type: :boolean,
20
+ default: true,
21
+ desc: "Add a \"This file is generated\" header on top of each generated RBI file"
22
+ class_option :verbose,
23
+ aliases: ["-V"],
24
+ type: :boolean,
25
+ default: false,
26
+ desc: "Verbose output for debugging purposes"
27
+
28
+ map T.unsafe(["--version", "-v"] => :__print_version)
29
+
30
+ desc "init", "initializes folder structure"
31
+ def init
32
+ create_config
33
+ create_post_require
34
+ generate_binstub
35
+ end
36
+
37
+ desc "require", "generate the list of files to be required by tapioca"
38
+ def require
39
+ Tapioca.silence_warnings do
40
+ generator.build_requires
41
+ end
42
+ end
43
+
44
+ desc "todo", "generate the list of unresolved constants"
45
+ def todo
46
+ Tapioca.silence_warnings do
47
+ generator.build_todos
48
+ end
49
+ end
50
+
51
+ desc "dsl [constant...]", "generate RBIs for dynamic methods"
52
+ option :generators,
53
+ type: :array,
54
+ aliases: ["--gen", "-g"],
55
+ banner: "generator [generator ...]",
56
+ desc: "Only run supplied DSL generators"
57
+ option :exclude_generators,
58
+ type: :array,
59
+ banner: "generator [generator ...]",
60
+ desc: "Exclude supplied DSL generators"
61
+ option :verify,
62
+ type: :boolean,
63
+ default: false,
64
+ desc: "Verifies RBIs are up-to-date"
65
+ option :quiet,
66
+ aliases: ["-q"],
67
+ type: :boolean,
68
+ desc: "Supresses file creation output"
69
+ def dsl(*constants)
70
+ Tapioca.silence_warnings do
71
+ generator.build_dsl(
72
+ constants,
73
+ should_verify: options[:verify],
74
+ quiet: options[:quiet],
75
+ verbose: options[:verbose]
76
+ )
77
+ end
78
+ end
79
+
80
+ desc "gem [gem...]", "generate RBIs from gems"
81
+ option :all,
82
+ type: :boolean,
83
+ default: false,
84
+ desc: "Regenerate RBI files for all gems"
85
+ option :prerequire,
86
+ aliases: ["--pre", "-b"],
87
+ banner: "file",
88
+ desc: "A file to be required before Bundler.require is called"
89
+ option :postrequire,
90
+ aliases: ["--post", "-a"],
91
+ banner: "file",
92
+ desc: "A file to be required after Bundler.require is called"
93
+ option :exclude,
94
+ aliases: ["-x"],
95
+ type: :array,
96
+ banner: "gem [gem ...]",
97
+ desc: "Excludes the given gem(s) from RBI generation"
98
+ option :typed_overrides,
99
+ aliases: ["--typed", "-t"],
100
+ type: :hash,
101
+ banner: "gem:level [gem:level ...]",
102
+ desc: "Overrides for typed sigils for generated gem RBIs"
103
+ option :verify,
104
+ type: :boolean,
105
+ default: false,
106
+ desc: "Verifies RBIs are up-to-date"
107
+ def gem(*gems)
108
+ Tapioca.silence_warnings do
109
+ all = options[:all]
110
+ verify = options[:verify]
111
+
112
+ raise MalformattedArgumentError, "Options '--all' and '--verify' are mutually exclusive" if all && verify
113
+
114
+ unless gems.empty?
115
+ raise MalformattedArgumentError, "Option '--all' must be provided without any other arguments" if all
116
+ raise MalformattedArgumentError, "Option '--verify' must be provided without any other arguments" if verify
117
+ end
118
+
119
+ if gems.empty? && !all
120
+ generator.sync_rbis_with_gemfile(should_verify: verify)
121
+ else
122
+ generator.build_gem_rbis(all ? [] : gems)
123
+ end
124
+ end
125
+ end
126
+
127
+ desc "generate [gem...]", "DEPRECATED: generate RBIs from gems"
128
+ option :prerequire,
129
+ aliases: ["--pre", "-b"],
130
+ banner: "file",
131
+ desc: "A file to be required before Bundler.require is called"
132
+ option :postrequire,
133
+ aliases: ["--post", "-a"],
134
+ banner: "file",
135
+ desc: "A file to be required after Bundler.require is called"
136
+ option :exclude,
137
+ aliases: ["-x"],
138
+ type: :array,
139
+ banner: "gem [gem ...]",
140
+ desc: "Excludes the given gem(s) from RBI generation"
141
+ option :typed_overrides,
142
+ aliases: ["--typed", "-t"],
143
+ type: :hash,
144
+ banner: "gem:level [gem:level ...]",
145
+ desc: "Overrides for typed sigils for generated gem RBIs"
146
+ def generate(*gems)
147
+ gem_names = if gems.empty?
148
+ "--all"
149
+ else
150
+ gems.join(" ")
151
+ end
152
+ deprecation_message = <<~MSG
153
+ DEPRECATION: The `generate` command will be removed in a future release.
154
+
155
+ Start using `bin/tapioca gem #{gem_names}` instead.
156
+ MSG
157
+
158
+ say(deprecation_message, :red)
159
+ say("")
160
+
161
+ Tapioca.silence_warnings do
162
+ generator.build_gem_rbis(gems)
163
+ end
164
+
165
+ say("")
166
+ say(deprecation_message, :red)
167
+ end
168
+
169
+ desc "sync", "DEPRECATED: sync RBIs to Gemfile"
170
+ option :prerequire,
171
+ aliases: ["--pre", "-b"],
172
+ banner: "file",
173
+ desc: "A file to be required before Bundler.require is called"
174
+ option :postrequire,
175
+ aliases: ["--post", "-a"],
176
+ banner: "file",
177
+ desc: "A file to be required after Bundler.require is called"
178
+ option :exclude,
179
+ aliases: ["-x"],
180
+ type: :array,
181
+ banner: "gem [gem ...]",
182
+ desc: "Excludes the given gem(s) from RBI generation"
183
+ option :typed_overrides,
184
+ aliases: ["--typed", "-t"],
185
+ type: :hash,
186
+ banner: "gem:level [gem:level ...]",
187
+ desc: "Overrides for typed sigils for generated gem RBIs"
188
+ option :verify,
189
+ type: :boolean,
190
+ default: false,
191
+ desc: "Verifies RBIs are up-to-date"
192
+ def sync
193
+ deprecation_message = <<~MSG
194
+ DEPRECATION: The `sync` command will be removed in a future release.
195
+
196
+ Start using `bin/tapioca gem` instead.
197
+ MSG
198
+
199
+ say(deprecation_message, :red)
200
+ say("")
201
+
202
+ Tapioca.silence_warnings do
203
+ generator.sync_rbis_with_gemfile(should_verify: options[:verify])
204
+ end
205
+
206
+ say("")
207
+ say(deprecation_message, :red)
208
+ end
209
+
210
+ desc "--version, -v", "show version"
211
+ def __print_version
212
+ puts "Tapioca v#{Tapioca::VERSION}"
213
+ end
214
+
215
+ private
216
+
217
+ def create_config
218
+ create_file(Config::SORBET_CONFIG, skip: true) do
219
+ <<~CONTENT
220
+ --dir
221
+ .
222
+ CONTENT
223
+ end
224
+ end
225
+
226
+ def create_post_require
227
+ create_file(Config::DEFAULT_POSTREQUIRE, skip: true) do
228
+ <<~CONTENT
229
+ # typed: true
230
+ # frozen_string_literal: true
231
+
232
+ # Add your extra requires here (`tapioca require` can be used to boostrap this list)
233
+ CONTENT
234
+ end
235
+ end
236
+
237
+ def generate_binstub
238
+ bin_stub_exists = File.exist?("bin/tapioca")
239
+ installer = Bundler::Installer.new(Bundler.root, Bundler.definition)
240
+ spec = Bundler.definition.specs.find { |s| s.name == "tapioca" }
241
+ installer.generate_bundler_executable_stubs(spec, { force: true })
242
+ if bin_stub_exists
243
+ shell.say_status(:force, "bin/tapioca", :yellow)
244
+ else
245
+ shell.say_status(:create, "bin/tapioca", :green)
246
+ end
247
+ end
248
+
249
+ no_commands do
250
+ def self.exit_on_failure?
251
+ true
252
+ end
253
+
254
+ def generator
255
+ current_command = T.must(current_command_chain.first)
256
+ @generator ||= Generator.new(
257
+ ConfigBuilder.from_options(current_command, options)
258
+ )
259
+ end
260
+ end
261
+ end
8
262
  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