tapioca 0.5.6 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +114 -23
  3. data/lib/tapioca/cli.rb +188 -64
  4. data/lib/tapioca/compilers/dsl/active_record_associations.rb +94 -8
  5. data/lib/tapioca/compilers/dsl/active_record_columns.rb +5 -4
  6. data/lib/tapioca/compilers/dsl/active_record_relations.rb +703 -0
  7. data/lib/tapioca/compilers/dsl/active_record_scope.rb +43 -13
  8. data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +2 -4
  9. data/lib/tapioca/compilers/dsl/base.rb +25 -42
  10. data/lib/tapioca/compilers/dsl/extensions/frozen_record.rb +29 -0
  11. data/lib/tapioca/compilers/dsl/frozen_record.rb +37 -0
  12. data/lib/tapioca/compilers/dsl/helper/active_record_constants.rb +27 -0
  13. data/lib/tapioca/compilers/dsl/param_helper.rb +52 -0
  14. data/lib/tapioca/compilers/dsl/rails_generators.rb +120 -0
  15. data/lib/tapioca/compilers/dsl_compiler.rb +32 -6
  16. data/lib/tapioca/compilers/sorbet.rb +2 -0
  17. data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +47 -46
  18. data/lib/tapioca/executor.rb +79 -0
  19. data/lib/tapioca/gemfile.rb +23 -0
  20. data/lib/tapioca/generators/base.rb +11 -18
  21. data/lib/tapioca/generators/dsl.rb +33 -38
  22. data/lib/tapioca/generators/gem.rb +50 -29
  23. data/lib/tapioca/generators/init.rb +41 -16
  24. data/lib/tapioca/generators/todo.rb +6 -6
  25. data/lib/tapioca/helpers/cli_helper.rb +26 -0
  26. data/lib/tapioca/helpers/config_helper.rb +84 -0
  27. data/lib/tapioca/helpers/test/content.rb +51 -0
  28. data/lib/tapioca/helpers/test/isolation.rb +125 -0
  29. data/lib/tapioca/helpers/test/template.rb +34 -0
  30. data/lib/tapioca/internal.rb +3 -2
  31. data/lib/tapioca/rbi_ext/model.rb +12 -9
  32. data/lib/tapioca/reflection.rb +13 -0
  33. data/lib/tapioca/trackers/autoload.rb +70 -0
  34. data/lib/tapioca/trackers/constant_definition.rb +42 -0
  35. data/lib/tapioca/trackers/mixin.rb +78 -0
  36. data/lib/tapioca/trackers.rb +14 -0
  37. data/lib/tapioca/version.rb +1 -1
  38. data/lib/tapioca.rb +28 -2
  39. metadata +19 -7
  40. data/lib/tapioca/config.rb +0 -45
  41. data/lib/tapioca/config_builder.rb +0 -73
  42. data/lib/tapioca/constant_locator.rb +0 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 700c54640e9ef8478e5f06732407c6ea33bbaa98def51be92be7952235915dab
4
- data.tar.gz: 391a4ca32fba379e0131b8990150f2f4e2229367aa5f49261ebd8dcbea997936
3
+ metadata.gz: a99e7a4475e2991e305c461774e45e128d430632e96581fc541680b61275e4e1
4
+ data.tar.gz: 8ee7b9b225dd752edf606a98aee1b8490687f351dae642b24060549740d2ab5a
5
5
  SHA512:
6
- metadata.gz: a3f626991d59d0f6813ee75f72787d657b86c334ac047457049d56e3f5ba86bf71258f060e3714ba3dba0dc70a5e0ce93fcc36a96c1b07d85fa9b6ab98782675
7
- data.tar.gz: b93d8431e3486f2681cd388c69fb68016a470bf67571ecca77fe493567b0fcf49ad2d68250881cd9bf4f6700e7ccb3c33d756c5c2ee03785d58c3618f617f48c
6
+ metadata.gz: 3ab85b1422fba3aa79de02fad9e164b2013cef3a388ad196e4c11f0c2c6dc142b6a540a430f4a4ace9f3ebe92da2f29fbe733e13ceb481277e7d7e2691db9f0c
7
+ data.tar.gz: b9f2c2cca77916e08fcbb1ca021818b51bc5edd8d899b2f5e89dae3bfddd38dd8e403b16bacd8c8db37dc630448458d7d6f52e6445cb9ecb96c6bba16c4c20e7
data/README.md CHANGED
@@ -8,7 +8,7 @@ Tapioca is a library used to generate RBI (Ruby interface) files for use with [S
8
8
 
9
9
  As yet, no gem exports type information in a consumable format and it would be a huge effort to manually maintain such an interface file for all the gems that your codebase depends on. Thus, there is a need for an automated way to generate the appropriate RBI file for a given gem. The `tapioca` gem, developed at Shopify, is able to do exactly that to almost 99% accuracy. It can generate the definitions for all statically defined types and most of the runtime defined types exported from Ruby gems (non-Ruby gems are not handled yet).
10
10
 
11
- When you run `tapioca sync` in a project, `tapioca` loads all the gems that are in your dependency list from the Gemfile into memory. It then performs runtime introspection on the loaded types to understand their structure and generates an appropriate RBI file for each gem with a versioned filename.
11
+ When you run `tapioca gem` in a project, `tapioca` loads all the gems that are in your dependency list from the Gemfile into memory. It then performs runtime introspection on the loaded types to understand their structure and generates an appropriate RBI file for each gem with a versioned filename.
12
12
 
13
13
  ## Manual gem requires
14
14
 
@@ -33,7 +33,7 @@ from (pry):3:in `__pry__`
33
33
 
34
34
  In order to make sure that `tapioca` can reflect on that type, we need to add the line `require "better_html/parser"` to the `sorbet/tapioca/require.rb` file. This will make sure `BetterHtml::Parser` is loaded into memory and a type annotation is generated for it in the `better_html.rbi` file. If this extra `require` line is not added to `sorbet/tapioca/require.rb` file, then the definition for that type will be missing from the RBI file.
35
35
 
36
- If you ever run into a case, where you add a gem or update the version of a gem and run `tapioca sync` but don't have some types you expect in the generated gem RBI files, you will need to make sure you have added the necessary requires to the `sorbet/tapioca/require.rb` file.
36
+ If you ever run into a case, where you add a gem or update the version of a gem and run `tapioca gem` but don't have some types you expect in the generated gem RBI files, you will need to make sure you have added the necessary requires to the `sorbet/tapioca/require.rb` file.
37
37
 
38
38
  You can use the command `tapioca require` to auto-populate the `sorbet/tapioca/require.rb` file with all the requires found
39
39
  in your application. Once the file generated, you should review it, remove all unnecessary requires and commit it.
@@ -55,24 +55,21 @@ end
55
55
  and do not forget to execute `tapioca` using `bundler`:
56
56
 
57
57
  ```shell
58
- $ bundle exec tapioca
58
+ $ bundle exec tapioca help
59
59
  Commands:
60
60
  tapioca --version, -v # show version
61
+ tapioca clean-shims # clean duplicated definitions in shim RBIs
61
62
  tapioca dsl [constant...] # generate RBIs for dynamic methods
62
- tapioca generate [gem...] # generate RBIs from gems
63
+ tapioca gem [gem...] # generate RBIs from gems
63
64
  tapioca help [COMMAND] # Describe available commands or one specific command
64
65
  tapioca init # initializes folder structure
65
66
  tapioca require # generate the list of files to be required by tapioca
66
- tapioca sync # sync RBIs to Gemfile
67
67
  tapioca todo # generate the list of unresolved constants
68
68
 
69
69
  Options:
70
- --pre, -b, [--prerequire=file] # A file to be required before Bundler.require is called
71
- --post, -a, [--postrequire=file] # A file to be required after Bundler.require is called
72
- --out, -o, [--outdir=directory] # The output directory for generated RBI files
73
- --cmd, -c, [--generate-command=command] # The command to run to regenerate RBI files
74
- -x, [--exclude=gem [gem ...]] # Excludes the given gem(s) from RBI generation
75
- --typed, -t, [--typed-overrides=gem:level [gem:level ...]] # Overrides for typed sigils for generated gem RBIs
70
+ -c, [--config=<config file path>] # Path to the Tapioca configuration file
71
+ # Default: sorbet/tapioca/config.yml
72
+ -V, [--verbose], [--no-verbose] # Verbose output for debugging purposes
76
73
  ```
77
74
 
78
75
  ## Usage
@@ -83,17 +80,54 @@ Command: `tapioca init`
83
80
 
84
81
  This will create the `sorbet/config` and `sorbet/tapioca/require.rb` files for you, if they don't exist. If any of the files already exist, they will not be changed.
85
82
 
86
- ### Generate for gems
83
+ ```shell
84
+ $ bundle exec tapioca help init
85
+ Usage:
86
+ tapioca init
87
87
 
88
- Command: `tapioca generate [gems...]`
88
+ Options:
89
+ -c, [--config=<config file path>] # Path to the Tapioca configuration file
90
+ # Default: sorbet/tapioca/config.yml
91
+ -V, [--verbose], [--no-verbose] # Verbose output for debugging purposes
89
92
 
90
- This will generate RBIs for the specified gems and place them in the RBI directory.
93
+ initializes folder structure
94
+ ```
91
95
 
92
- ### Generate for all gems in Gemfile
96
+ ### Generate RBI files for gems
93
97
 
94
- Command: `tapioca sync`
98
+ Command: `tapioca gem [gems...]`
95
99
 
96
- This will sync the RBIs with the gems in the Gemfile and will add, update, and remove RBIs as necessary.
100
+ This will generate RBIs for the specified gems and place them in the RBI directory.
101
+
102
+ ```shell
103
+ $ bundle exec tapioca help gem
104
+ Usage:
105
+ tapioca gem [gem...]
106
+
107
+ Options:
108
+ --out, -o, [--outdir=directory] # The output directory for generated RBI files
109
+ # Default: sorbet/rbi/gems
110
+ [--file-header], [--no-file-header] # Add a "This file is generated" header on top of each generated RBI file
111
+ # Default: true
112
+ [--all], [--no-all] # Regenerate RBI files for all gems
113
+ --pre, -b, [--prerequire=file] # A file to be required before Bundler.require is called
114
+ --post, -a, [--postrequire=file] # A file to be required after Bundler.require is called
115
+ # Default: sorbet/tapioca/require.rb
116
+ -x, [--exclude=gem [gem ...]] # Excludes the given gem(s) from RBI generation
117
+ --typed, -t, [--typed-overrides=gem:level [gem:level ...]] # Overrides for typed sigils for generated gem RBIs
118
+ # Default: {"activesupport"=>"false"}
119
+ [--verify], [--no-verify] # Verifies RBIs are up-to-date
120
+ [--doc], [--no-doc] # Include YARD documentation from sources when generating RBIs. Warning: this might be slow
121
+ [--exported-gem-rbis], [--no-exported-gem-rbis] # Include RBIs found in the `rbi/` directory of the gem
122
+ # Default: true
123
+ -w, [--workers=N] # EXPERIMENTAL: Number of parallel workers to use when generating RBIs
124
+ # Default: 1
125
+ -c, [--config=<config file path>] # Path to the Tapioca configuration file
126
+ # Default: sorbet/tapioca/config.yml
127
+ -V, [--verbose], [--no-verbose] # Verbose output for debugging purposes
128
+
129
+ generate RBIs from gems
130
+ ```
97
131
 
98
132
  ### Generate the list of all unresolved constants
99
133
 
@@ -101,19 +135,76 @@ Command: `tapioca todo`
101
135
 
102
136
  This will generate the file `sorbet/rbi/todo.rbi` defining all unresolved constants as empty modules.
103
137
 
138
+ ```shell
139
+ $ bundle exec tapioca help todo
140
+ Usage:
141
+ tapioca todo
142
+
143
+ Options:
144
+ [--todo-file=TODO_FILE]
145
+ # Default: sorbet/rbi/todo.rbi
146
+ [--file-header], [--no-file-header] # Add a "This file is generated" header on top of each generated RBI file
147
+ # Default: true
148
+ -c, [--config=<config file path>] # Path to the Tapioca configuration file
149
+ # Default: sorbet/tapioca/config.yml
150
+ -V, [--verbose], [--no-verbose] # Verbose output for debugging purposes
151
+
152
+ generate the list of unresolved constants
153
+ ```
154
+
104
155
  ### Generate DSL RBI files
105
156
 
106
157
  Command: `tapioca dsl [constant...]`
107
158
 
108
159
  This will generate DSL RBIs for specified constants (or for all handled constants, if a constant name is not supplied). You can read about DSL RBI generators supplied by `tapioca` in [the manual](manual/generators.md).
109
160
 
110
- ### Flags
161
+ ```shell
162
+ $ bundle exec tapioca help dsl
163
+ Usage:
164
+ tapioca dsl [constant...]
165
+
166
+ Options:
167
+ --out, -o, [--outdir=directory] # The output directory for generated RBI files
168
+ # Default: sorbet/rbi/dsl
169
+ [--file-header], [--no-file-header] # Add a "This file is generated" header on top of each generated RBI file
170
+ # Default: true
171
+ [--only=generator [generator ...]] # Only run supplied DSL generators
172
+ [--exclude=generator [generator ...]] # Exclude supplied DSL generators
173
+ [--verify], [--no-verify] # Verifies RBIs are up-to-date
174
+ -q, [--quiet], [--no-quiet] # Supresses file creation output
175
+ -w, [--workers=N] # EXPERIMENTAL: Number of parallel workers to use when generating RBIs
176
+ # Default: 1
177
+ -c, [--config=<config file path>] # Path to the Tapioca configuration file
178
+ # Default: sorbet/tapioca/config.yml
179
+ -V, [--verbose], [--no-verbose] # Verbose output for debugging purposes
180
+
181
+ generate RBIs for dynamic methods
182
+ ```
183
+ ## Configuration
184
+
185
+ Tapioca supports loading command defaults from a configuration file. The default configuration
186
+ file location is `sorbet/tapioca/config.yml` but this default can be changed using the `--config` flag
187
+ and supplying an alternative configuration file path.
188
+
189
+ A configuration file must be a well-formed YAML file with top-level keys for the various Tapioca commands. Keys under each such top-level command should be the underscore version of a long option name for that command and the value for that key should be the value of the option.
190
+
191
+ For example, if you always want to generate gem RBIs with inline documentation, then you would create the file `sorbet/tapioca/config.yml` as:
111
192
 
112
- - `--prerequire [file]`: A file to be required before `Bundler.require` is called.
113
- - `--postrequire [file]`: A file to be required after `Bundler.require` is called.
114
- - `--out [directory]`: The output directory for generated RBI files, default to `sorbet/rbi/gems`.
115
- - `--generate-command [command]`: **[DEPRECATED]** The command to run to regenerate RBI files (used in header comment of the RBI files), defaults to the current command.
116
- - `--typed-overrides [gem:level]`: Overrides typed sigils for generated gem RBIs for gem `gem` to level `level` (`level` can be one of `ignore`, `false`, `true`, `strict`, or `strong`, see [the Sorbet docs](https://sorbet.org/docs/static#file-level-granularity-strictness-levels) for more details).
193
+ ```yaml
194
+ gem:
195
+ docs: true
196
+ ```
197
+
198
+ Additionally, if you always want to exclude the `AASM` and `ActiveRecordFixtures` DSL compilers in your DSL RBI generation runs, your config file would then look like this:
199
+
200
+ ```yaml
201
+ gem:
202
+ docs: true
203
+ dsl:
204
+ exclude:
205
+ - UrlHelpers
206
+ - ActiveRecordFixtures
207
+ ```
117
208
 
118
209
  ## Contributing
119
210
 
data/lib/tapioca/cli.rb CHANGED
@@ -1,46 +1,43 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- require "thor"
5
-
6
4
  module Tapioca
7
5
  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"
6
+ include CliHelper
7
+ include ConfigHelper
8
+
9
+ FILE_HEADER_OPTION_DESC = "Add a \"This file is generated\" header on top of each generated RBI file"
10
+
11
+ class_option :config,
12
+ aliases: ["-c"],
13
+ banner: "<config file path>",
14
+ type: :string,
15
+ desc: "Path to the Tapioca configuration file",
16
+ default: TAPIOCA_CONFIG_FILE
20
17
  class_option :verbose,
21
18
  aliases: ["-V"],
22
19
  type: :boolean,
23
- default: false,
24
- desc: "Verbose output for debugging purposes"
25
-
26
- map T.unsafe(["--version", "-v"] => :__print_version)
20
+ desc: "Verbose output for debugging purposes",
21
+ default: false
27
22
 
28
23
  desc "init", "initializes folder structure"
29
24
  def init
30
25
  generator = Generators::Init.new(
31
- sorbet_config: Config::SORBET_CONFIG,
32
- default_postrequire: Config::DEFAULT_POSTREQUIRE,
33
- default_command: Config::DEFAULT_COMMAND
26
+ sorbet_config: SORBET_CONFIG_FILE,
27
+ tapioca_config: TAPIOCA_CONFIG_FILE,
28
+ default_postrequire: DEFAULT_POSTREQUIRE_FILE,
29
+ default_command: DEFAULT_COMMAND
34
30
  )
35
31
  generator.generate
36
32
  end
37
33
 
38
34
  desc "require", "generate the list of files to be required by tapioca"
35
+ option :postrequire, type: :string, default: DEFAULT_POSTREQUIRE_FILE
39
36
  def require
40
37
  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
38
+ requires_path: options[:postrequire],
39
+ sorbet_config_path: SORBET_CONFIG_FILE,
40
+ default_command: DEFAULT_COMMAND
44
41
  )
45
42
  Tapioca.silence_warnings do
46
43
  generator.generate
@@ -48,13 +45,18 @@ module Tapioca
48
45
  end
49
46
 
50
47
  desc "todo", "generate the list of unresolved constants"
48
+ option :todo_file,
49
+ type: :string,
50
+ default: DEFAULT_TODO_FILE
51
+ option :file_header,
52
+ type: :boolean,
53
+ desc: FILE_HEADER_OPTION_DESC,
54
+ default: true
51
55
  def todo
52
- current_command = T.must(current_command_chain.first)
53
- config = ConfigBuilder.from_options(current_command, options)
54
56
  generator = Generators::Todo.new(
55
- todos_path: config.todos_path,
56
- file_header: config.file_header,
57
- default_command: Config::DEFAULT_COMMAND
57
+ todo_file: options[:todo_file],
58
+ file_header: options[:file_header],
59
+ default_command: DEFAULT_COMMAND
58
60
  )
59
61
  Tapioca.silence_warnings do
60
62
  generator.generate
@@ -62,15 +64,25 @@ module Tapioca
62
64
  end
63
65
 
64
66
  desc "dsl [constant...]", "generate RBIs for dynamic methods"
65
- option :generators,
67
+ option :outdir,
68
+ aliases: ["--out", "-o"],
69
+ banner: "directory",
70
+ desc: "The output directory for generated DSL RBI files",
71
+ default: DEFAULT_DSL_DIR
72
+ option :file_header,
73
+ type: :boolean,
74
+ desc: FILE_HEADER_OPTION_DESC,
75
+ default: true
76
+ option :only,
66
77
  type: :array,
67
- aliases: ["--gen", "-g"],
68
78
  banner: "generator [generator ...]",
69
- desc: "Only run supplied DSL generators"
70
- option :exclude_generators,
79
+ desc: "Only run supplied DSL generator(s)",
80
+ default: []
81
+ option :exclude,
71
82
  type: :array,
72
83
  banner: "generator [generator ...]",
73
- desc: "Exclude supplied DSL generators"
84
+ desc: "Exclude supplied DSL generator(s)",
85
+ default: []
74
86
  option :verify,
75
87
  type: :boolean,
76
88
  default: false,
@@ -78,74 +90,111 @@ module Tapioca
78
90
  option :quiet,
79
91
  aliases: ["-q"],
80
92
  type: :boolean,
81
- desc: "Supresses file creation output"
93
+ desc: "Supresses file creation output",
94
+ default: false
95
+ option :workers,
96
+ aliases: ["-w"],
97
+ type: :numeric,
98
+ desc: "EXPERIMENTAL: Number of parallel workers to use when generating RBIs",
99
+ default: 1
82
100
  def dsl(*constants)
83
- current_command = T.must(current_command_chain.first)
84
- config = ConfigBuilder.from_options(current_command, options)
85
101
  generator = Generators::Dsl.new(
86
102
  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,
103
+ outpath: Pathname.new(options[:outdir]),
104
+ only: options[:only],
105
+ exclude: options[:exclude],
106
+ file_header: options[:file_header],
107
+ compiler_path: Tapioca::Compilers::Dsl::DSL_COMPILERS_DIR,
108
+ tapioca_path: TAPIOCA_DIR,
109
+ default_command: DEFAULT_COMMAND,
94
110
  should_verify: options[:verify],
95
111
  quiet: options[:quiet],
96
- verbose: options[:verbose]
112
+ verbose: options[:verbose],
113
+ number_of_workers: options[:workers]
97
114
  )
115
+
116
+ if options[:workers] != 1
117
+ say(
118
+ "Using more than one worker is experimental and might produce results that are not deterministic",
119
+ :red
120
+ )
121
+ end
122
+
98
123
  Tapioca.silence_warnings do
99
124
  generator.generate
100
125
  end
101
126
  end
102
127
 
103
128
  desc "gem [gem...]", "generate RBIs from gems"
129
+ option :outdir,
130
+ aliases: ["--out", "-o"],
131
+ banner: "directory",
132
+ desc: "The output directory for generated gem RBI files",
133
+ default: DEFAULT_GEM_DIR
134
+ option :file_header,
135
+ type: :boolean,
136
+ desc: FILE_HEADER_OPTION_DESC,
137
+ default: true
104
138
  option :all,
105
139
  type: :boolean,
106
- default: false,
107
- desc: "Regenerate RBI files for all gems"
140
+ desc: "Regenerate RBI files for all gems",
141
+ default: false
108
142
  option :prerequire,
109
143
  aliases: ["--pre", "-b"],
110
144
  banner: "file",
111
- desc: "A file to be required before Bundler.require is called"
145
+ desc: "A file to be required before Bundler.require is called",
146
+ default: nil
112
147
  option :postrequire,
113
148
  aliases: ["--post", "-a"],
114
149
  banner: "file",
115
- desc: "A file to be required after Bundler.require is called"
150
+ desc: "A file to be required after Bundler.require is called",
151
+ default: DEFAULT_POSTREQUIRE_FILE
116
152
  option :exclude,
117
153
  aliases: ["-x"],
118
154
  type: :array,
119
155
  banner: "gem [gem ...]",
120
- desc: "Excludes the given gem(s) from RBI generation"
156
+ desc: "Exclude the given gem(s) from RBI generation",
157
+ default: []
121
158
  option :typed_overrides,
122
159
  aliases: ["--typed", "-t"],
123
160
  type: :hash,
124
161
  banner: "gem:level [gem:level ...]",
125
- desc: "Overrides for typed sigils for generated gem RBIs"
162
+ desc: "Override for typed sigils for generated gem RBIs",
163
+ default: DEFAULT_OVERRIDES
126
164
  option :verify,
127
165
  type: :boolean,
128
- default: false,
129
- desc: "Verifies RBIs are up-to-date"
166
+ desc: "Verify RBIs are up-to-date",
167
+ default: false
130
168
  option :doc,
131
169
  type: :boolean,
132
- desc: "Include YARD documentation from sources when generating RBIs. Warning: this might be slow"
170
+ desc: "Include YARD documentation from sources when generating RBIs. Warning: this might be slow",
171
+ default: false
172
+ option :exported_gem_rbis,
173
+ type: :boolean,
174
+ desc: "Include RBIs found in the `rbi/` directory of the gem",
175
+ default: true
176
+ option :workers,
177
+ aliases: ["-w"],
178
+ type: :numeric,
179
+ desc: "EXPERIMENTAL: Number of parallel workers to use when generating RBIs",
180
+ default: 1
133
181
  def gem(*gems)
134
182
  Tapioca.silence_warnings do
135
183
  all = options[:all]
136
184
  verify = options[:verify]
137
- current_command = T.must(current_command_chain.first)
138
- config = ConfigBuilder.from_options(current_command, options)
185
+
139
186
  generator = Generators::Gem.new(
140
187
  gem_names: all ? [] : gems,
141
- gem_excludes: config.exclude,
142
- prerequire: config.prerequire,
143
- postrequire: config.postrequire,
144
- typed_overrides: config.typed_overrides,
145
- default_command: Config::DEFAULT_COMMAND,
146
- outpath: config.outpath,
147
- file_header: config.file_header,
148
- doc: config.doc
188
+ exclude: options[:exclude],
189
+ prerequire: options[:prerequire],
190
+ postrequire: options[:postrequire],
191
+ typed_overrides: options[:typed_overrides],
192
+ default_command: DEFAULT_COMMAND,
193
+ outpath: Pathname.new(options[:outdir]),
194
+ file_header: options[:file_header],
195
+ doc: options[:doc],
196
+ include_exported_rbis: options[:exported_gem_rbis],
197
+ number_of_workers: options[:workers]
149
198
  )
150
199
 
151
200
  raise MalformattedArgumentError, "Options '--all' and '--verify' are mutually exclusive" if all && verify
@@ -155,6 +204,13 @@ module Tapioca
155
204
  raise MalformattedArgumentError, "Option '--verify' must be provided without any other arguments" if verify
156
205
  end
157
206
 
207
+ if options[:workers] != 1
208
+ say(
209
+ "Using more than one worker is experimental and might produce results that are not deterministic",
210
+ :red
211
+ )
212
+ end
213
+
158
214
  if gems.empty? && !all
159
215
  generator.sync(should_verify: verify)
160
216
  else
@@ -163,6 +219,74 @@ module Tapioca
163
219
  end
164
220
  end
165
221
 
222
+ desc "clean-shims", "clean duplicated definitions in shim RBIs"
223
+ option :gem_rbi_dir, type: :string, desc: "Path to gem RBIs", default: DEFAULT_GEM_DIR
224
+ option :dsl_rbi_dir, type: :string, desc: "Path to DSL RBIs", default: DEFAULT_DSL_DIR
225
+ option :shim_rbi_dir, type: :string, desc: "Path to shim RBIs", default: DEFAULT_SHIM_DIR
226
+ def clean_shims(*files_to_clean)
227
+ index = RBI::Index.new
228
+
229
+ # Index gem RBIs
230
+ gem_rbi_dir = options[:gem_rbi_dir]
231
+ say("Loading gem RBIs from #{gem_rbi_dir}... ")
232
+ gem_rbis_files = Dir.glob("#{gem_rbi_dir}/**/*.rbi").sort
233
+ gem_rbis_trees = RBI::Parser.parse_files(gem_rbis_files)
234
+ index.visit_all(gem_rbis_trees)
235
+ say(" Done", :green)
236
+
237
+ # Index dsl RBIs
238
+ dsl_rbi_dir = options[:dsl_rbi_dir]
239
+ say("Loading dsl RBIs from #{dsl_rbi_dir}... ")
240
+ dsl_rbis_files = Dir.glob("#{dsl_rbi_dir}/**/*.rbi").sort
241
+ dsl_rbis_trees = RBI::Parser.parse_files(dsl_rbis_files)
242
+ index.visit_all(dsl_rbis_trees)
243
+ say(" Done", :green)
244
+
245
+ # Clean shim RBIs
246
+ if files_to_clean.empty?
247
+ shim_rbi_dir = options[:shim_rbi_dir]
248
+ print("Cleaning shim RBIs from #{shim_rbi_dir}...")
249
+ files_to_clean = Dir.glob("#{shim_rbi_dir}/*.rbi")
250
+ else
251
+ print("Cleaning shim RBIs...")
252
+ end
253
+
254
+ done_something = T.let(false, T::Boolean)
255
+ files_to_clean.sort.each do |path|
256
+ original = RBI::Parser.parse_file(path)
257
+ cleaned, operations = RBI::Rewriters::RemoveKnownDefinitions.remove(original, index)
258
+
259
+ next if operations.empty?
260
+ done_something = true
261
+
262
+ operations.each do |operation|
263
+ print("\n #{operation}")
264
+ end
265
+
266
+ if cleaned.empty?
267
+ print("\n Deleted empty file #{path}")
268
+ FileUtils.rm(path)
269
+ else
270
+ File.write(path, cleaned.string)
271
+ end
272
+ end
273
+
274
+ if done_something
275
+ say("\nDone", :green)
276
+ else
277
+ say(" Done ", :green)
278
+ say("(nothing to do)", :yellow)
279
+ end
280
+ rescue Errno::ENOENT => e
281
+ say_error("\nCan't read RBI: #{e}")
282
+ exit(1)
283
+ rescue RBI::ParseError => e
284
+ say_error("\nCan't parse RBI: #{e} (#{e.location})")
285
+ exit(1)
286
+ end
287
+
288
+ map T.unsafe(["--version", "-v"] => :__print_version)
289
+
166
290
  desc "--version, -v", "show version"
167
291
  def __print_version
168
292
  puts "Tapioca v#{Tapioca::VERSION}"