tapioca 0.5.1 → 0.5.5
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 +1 -1
- data/lib/tapioca/cli.rb +54 -139
- data/lib/tapioca/compilers/dsl/active_model_secure_password.rb +101 -0
- data/lib/tapioca/compilers/dsl/active_record_enum.rb +1 -1
- data/lib/tapioca/compilers/dsl/active_record_fixtures.rb +86 -0
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +41 -33
- data/lib/tapioca/compilers/dsl/active_support_concern.rb +0 -2
- data/lib/tapioca/compilers/dsl/base.rb +12 -0
- data/lib/tapioca/compilers/dsl/identity_cache.rb +0 -1
- data/lib/tapioca/compilers/dsl/mixed_in_class_attributes.rb +74 -0
- data/lib/tapioca/compilers/dsl/smart_properties.rb +4 -4
- data/lib/tapioca/compilers/dsl_compiler.rb +7 -6
- data/lib/tapioca/compilers/dynamic_mixin_compiler.rb +198 -0
- data/lib/tapioca/compilers/sorbet.rb +0 -1
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +84 -153
- data/lib/tapioca/compilers/symbol_table_compiler.rb +5 -11
- data/lib/tapioca/config.rb +1 -0
- data/lib/tapioca/config_builder.rb +1 -0
- data/lib/tapioca/constant_locator.rb +7 -1
- data/lib/tapioca/gemfile.rb +11 -5
- 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/internal.rb +1 -2
- data/lib/tapioca/loader.rb +2 -2
- data/lib/tapioca/rbi_ext/model.rb +44 -0
- data/lib/tapioca/reflection.rb +8 -1
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +2 -0
- metadata +34 -12
- data/lib/tapioca/generator.rb +0 -717
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6051054b5414fe5f3383fa6fefc8fabdfd426380c026f55fdf87ecee8e10d964
|
4
|
+
data.tar.gz: 5054dacc20c7a8881c957540d0fa624d7ec406d57f8486a9dab9e088e2d270d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e67122acb9f97bef99088a6dd2cded0c29a73bde763ab8acaad0fae6470ba0b1fc4d2a9139e781ca9ba569595560a743eba69dc701b0632712b31104e41ce2cf
|
7
|
+
data.tar.gz: 3ebf64268dc86b2740e68d3a508fdc67d458f976028781a4a9bce95eba883d2852840560fec32d3792d7193cdd224898bdfe913ffe800ddf3d5ad7be8a914ca6
|
data/Gemfile
CHANGED
@@ -11,7 +11,6 @@ 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")
|
@@ -35,4 +34,5 @@ group(:development, :test) do
|
|
35
34
|
gem("nokogiri", require: false)
|
36
35
|
gem("config", require: false)
|
37
36
|
gem("aasm", require: false)
|
37
|
+
gem("bcrypt", require: false)
|
38
38
|
end
|
data/lib/tapioca/cli.rb
CHANGED
@@ -5,8 +5,6 @@ require "thor"
|
|
5
5
|
|
6
6
|
module Tapioca
|
7
7
|
class Cli < Thor
|
8
|
-
include(Thor::Actions)
|
9
|
-
|
10
8
|
class_option :outdir,
|
11
9
|
aliases: ["--out", "-o"],
|
12
10
|
banner: "directory",
|
@@ -29,22 +27,37 @@ module Tapioca
|
|
29
27
|
|
30
28
|
desc "init", "initializes folder structure"
|
31
29
|
def init
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
35
36
|
end
|
36
37
|
|
37
38
|
desc "require", "generate the list of files to be required by tapioca"
|
38
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
|
+
)
|
39
45
|
Tapioca.silence_warnings do
|
40
|
-
generator.
|
46
|
+
generator.generate
|
41
47
|
end
|
42
48
|
end
|
43
49
|
|
44
50
|
desc "todo", "generate the list of unresolved constants"
|
45
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
|
+
)
|
46
59
|
Tapioca.silence_warnings do
|
47
|
-
generator.
|
60
|
+
generator.generate
|
48
61
|
end
|
49
62
|
end
|
50
63
|
|
@@ -67,13 +80,23 @@ module Tapioca
|
|
67
80
|
type: :boolean,
|
68
81
|
desc: "Supresses file creation output"
|
69
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
|
+
)
|
70
98
|
Tapioca.silence_warnings do
|
71
|
-
generator.
|
72
|
-
constants,
|
73
|
-
should_verify: options[:verify],
|
74
|
-
quiet: options[:quiet],
|
75
|
-
verbose: options[:verbose]
|
76
|
-
)
|
99
|
+
generator.generate
|
77
100
|
end
|
78
101
|
end
|
79
102
|
|
@@ -104,10 +127,26 @@ module Tapioca
|
|
104
127
|
type: :boolean,
|
105
128
|
default: false,
|
106
129
|
desc: "Verifies RBIs are up-to-date"
|
130
|
+
option :doc,
|
131
|
+
type: :boolean,
|
132
|
+
desc: "Include YARD documentation from sources when generating RBIs. Warning: this might be slow"
|
107
133
|
def gem(*gems)
|
108
134
|
Tapioca.silence_warnings do
|
109
135
|
all = options[:all]
|
110
136
|
verify = options[:verify]
|
137
|
+
current_command = T.must(current_command_chain.first)
|
138
|
+
config = ConfigBuilder.from_options(current_command, options)
|
139
|
+
generator = Generators::Gem.new(
|
140
|
+
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
|
149
|
+
)
|
111
150
|
|
112
151
|
raise MalformattedArgumentError, "Options '--all' and '--verify' are mutually exclusive" if all && verify
|
113
152
|
|
@@ -117,146 +156,22 @@ module Tapioca
|
|
117
156
|
end
|
118
157
|
|
119
158
|
if gems.empty? && !all
|
120
|
-
generator.
|
159
|
+
generator.sync(should_verify: verify)
|
121
160
|
else
|
122
|
-
generator.
|
161
|
+
generator.generate
|
123
162
|
end
|
124
163
|
end
|
125
164
|
end
|
126
165
|
|
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
166
|
desc "--version, -v", "show version"
|
211
167
|
def __print_version
|
212
168
|
puts "Tapioca v#{Tapioca::VERSION}"
|
213
169
|
end
|
214
170
|
|
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
171
|
no_commands do
|
250
172
|
def self.exit_on_failure?
|
251
173
|
true
|
252
174
|
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
175
|
end
|
261
176
|
end
|
262
177
|
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "active_model"
|
6
|
+
rescue LoadError
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
module Tapioca
|
11
|
+
module Compilers
|
12
|
+
module Dsl
|
13
|
+
# `Tapioca::Compilers::Dsl::ActiveModelSecurePassword` decorates RBI files for all
|
14
|
+
# classes that use [`ActiveModel::SecurePassword`](http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html).
|
15
|
+
#
|
16
|
+
# For example, with the following class:
|
17
|
+
#
|
18
|
+
# ~~~rb
|
19
|
+
# class User
|
20
|
+
# include ActiveModel::SecurePassword
|
21
|
+
#
|
22
|
+
# has_secure_password
|
23
|
+
# has_secure_password :token
|
24
|
+
# end
|
25
|
+
# ~~~
|
26
|
+
#
|
27
|
+
# this generator will produce an RBI file with the following content:
|
28
|
+
# ~~~rbi
|
29
|
+
# # typed: true
|
30
|
+
#
|
31
|
+
# class User
|
32
|
+
# sig { params(unencrypted_password: T.untyped).returns(T.untyped) }
|
33
|
+
# def authenticate(unencrypted_password); end
|
34
|
+
#
|
35
|
+
# sig { params(unencrypted_password: T.untyped).returns(T.untyped) }
|
36
|
+
# def authenticate_password(unencrypted_password); end
|
37
|
+
#
|
38
|
+
# sig { params(unencrypted_password: T.untyped).returns(T.untyped) }
|
39
|
+
# def authenticate_token(unencrypted_password); end
|
40
|
+
#
|
41
|
+
# sig { returns(T.untyped) }
|
42
|
+
# def password; end
|
43
|
+
#
|
44
|
+
# sig { params(unencrypted_password: T.untyped).returns(T.untyped) }
|
45
|
+
# def password=(unencrypted_password); end
|
46
|
+
#
|
47
|
+
# sig { params(unencrypted_password: T.untyped).returns(T.untyped) }
|
48
|
+
# def password_confirmation=(unencrypted_password); end
|
49
|
+
#
|
50
|
+
# sig { returns(T.untyped) }
|
51
|
+
# def token; end
|
52
|
+
#
|
53
|
+
# sig { params(unencrypted_password: T.untyped).returns(T.untyped) }
|
54
|
+
# def token=(unencrypted_password); end
|
55
|
+
#
|
56
|
+
# sig { params(unencrypted_password: T.untyped).returns(T.untyped) }
|
57
|
+
# def token_confirmation=(unencrypted_password); end
|
58
|
+
# end
|
59
|
+
# ~~~
|
60
|
+
class ActiveModelSecurePassword < Base
|
61
|
+
extend T::Sig
|
62
|
+
|
63
|
+
sig do
|
64
|
+
override
|
65
|
+
.params(root: RBI::Tree, constant: T.all(Class, ::ActiveModel::SecurePassword::ClassMethods))
|
66
|
+
.void
|
67
|
+
end
|
68
|
+
def decorate(root, constant)
|
69
|
+
instance_methods_modules = if constant < ActiveModel::SecurePassword::InstanceMethodsOnActivation
|
70
|
+
# pre Rails 6.0, this used to be a single static module
|
71
|
+
[ActiveModel::SecurePassword::InstanceMethodsOnActivation]
|
72
|
+
else
|
73
|
+
# post Rails 6.0, this is now using a dynmaic module builder pattern
|
74
|
+
# and we can have multiple different ones included into the model
|
75
|
+
constant.ancestors.grep(ActiveModel::SecurePassword::InstanceMethodsOnActivation)
|
76
|
+
end
|
77
|
+
|
78
|
+
return if instance_methods_modules.empty?
|
79
|
+
|
80
|
+
methods = instance_methods_modules.flat_map { |mod| mod.instance_methods(false) }
|
81
|
+
return if methods.empty?
|
82
|
+
|
83
|
+
root.create_path(constant) do |klass|
|
84
|
+
methods.each do |method|
|
85
|
+
create_method_from_def(klass, constant.instance_method(method))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
sig { override.returns(T::Enumerable[Module]) }
|
91
|
+
def gather_constants
|
92
|
+
# This selects all classes that are `ActiveModel::SecurePassword::ClassMethods === klass`.
|
93
|
+
# In other words, we select all classes that have `ActiveModel::SecurePassword::ClassMethods`
|
94
|
+
# as an ancestor of its singleton class, i.e. all classes that have extended the
|
95
|
+
# `ActiveModel::SecurePassword::ClassMethods` module.
|
96
|
+
all_classes.grep(::ActiveModel::SecurePassword::ClassMethods)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "rails"
|
6
|
+
require "active_record"
|
7
|
+
require "active_record/fixtures"
|
8
|
+
require "active_support/test_case"
|
9
|
+
rescue LoadError
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
module Tapioca
|
14
|
+
module Compilers
|
15
|
+
module Dsl
|
16
|
+
# `Tapioca::Compilers::Dsl::ActiveRecordFixtures` decorates RBIs for test fixture methods
|
17
|
+
# that are created dynamically by Rails.
|
18
|
+
#
|
19
|
+
# For example, given an application with a posts table, we can have a fixture file
|
20
|
+
#
|
21
|
+
# ~~~yaml
|
22
|
+
# first_post:
|
23
|
+
# author: John
|
24
|
+
# title: My post
|
25
|
+
# ~~~
|
26
|
+
#
|
27
|
+
# Rails will allow us to invoke `posts(:first_post)` in tests to get the fixture record.
|
28
|
+
# The generated RBI by this generator will produce the following
|
29
|
+
#
|
30
|
+
# ~~~rbi
|
31
|
+
# # test_case.rbi
|
32
|
+
# # typed: true
|
33
|
+
# class ActiveSupport::TestCase
|
34
|
+
# sig { params(fixture_names: Symbol).returns(T.untyped) }
|
35
|
+
# def posts(*fixture_names); end
|
36
|
+
# end
|
37
|
+
# ~~~
|
38
|
+
class ActiveRecordFixtures < Base
|
39
|
+
extend T::Sig
|
40
|
+
|
41
|
+
sig { override.params(root: RBI::Tree, constant: T.class_of(ActiveSupport::TestCase)).void }
|
42
|
+
def decorate(root, constant)
|
43
|
+
method_names = fixture_loader.ancestors # get all ancestors from class that includes AR fixtures
|
44
|
+
.drop(1) # drop the anonymous class itself from the array
|
45
|
+
.reject(&:name) # only collect anonymous ancestors because fixture methods are always on an anonymous module
|
46
|
+
.map! do |mod|
|
47
|
+
[mod.private_instance_methods(false), mod.instance_methods(false)]
|
48
|
+
end
|
49
|
+
.flatten # merge methods into a single list
|
50
|
+
return if method_names.empty?
|
51
|
+
|
52
|
+
root.create_path(constant) do |mod|
|
53
|
+
method_names.each do |name|
|
54
|
+
create_fixture_method(mod, name.to_s)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
sig { override.returns(T::Enumerable[Module]) }
|
60
|
+
def gather_constants
|
61
|
+
[ActiveSupport::TestCase]
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
sig { returns(Class) }
|
67
|
+
def fixture_loader
|
68
|
+
Class.new do
|
69
|
+
T.unsafe(self).include(ActiveRecord::TestFixtures)
|
70
|
+
T.unsafe(self).fixture_path = Rails.root.join("test", "fixtures")
|
71
|
+
T.unsafe(self).fixtures(:all)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
sig { params(mod: RBI::Scope, name: String).void }
|
76
|
+
def create_fixture_method(mod, name)
|
77
|
+
mod.create_method(
|
78
|
+
name,
|
79
|
+
parameters: [create_rest_param("fixture_names", type: "Symbol")],
|
80
|
+
return_type: "T.untyped"
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -34,53 +34,57 @@ module Tapioca
|
|
34
34
|
# # post.rbi
|
35
35
|
# # typed: true
|
36
36
|
# class Post
|
37
|
-
#
|
38
|
-
# def review_date=(review_date); end
|
37
|
+
# include StoreAccessors
|
39
38
|
#
|
40
|
-
#
|
41
|
-
#
|
39
|
+
# module StoreAccessors
|
40
|
+
# sig { params(review_date: T.nilable(Date)).returns(T.nilable(Date)) }
|
41
|
+
# def review_date=(review_date); end
|
42
42
|
#
|
43
|
-
#
|
44
|
-
#
|
43
|
+
# sig { returns(T.nilable(Date)) }
|
44
|
+
# def review_date; end
|
45
45
|
#
|
46
|
-
#
|
47
|
-
#
|
46
|
+
# sig { returns(T.nilable(Date)) }
|
47
|
+
# def review_date_was; end
|
48
48
|
#
|
49
|
-
#
|
50
|
-
#
|
49
|
+
# sig { returns(T::Boolean) }
|
50
|
+
# def review_date_changed?; end
|
51
51
|
#
|
52
|
-
#
|
53
|
-
#
|
52
|
+
# sig { returns(T.nilable(Date)) }
|
53
|
+
# def review_date_before_last_save; end
|
54
54
|
#
|
55
|
-
#
|
56
|
-
#
|
55
|
+
# sig { returns(T::Boolean) }
|
56
|
+
# def saved_change_to_review_date?; end
|
57
57
|
#
|
58
|
-
#
|
59
|
-
#
|
58
|
+
# sig { returns(T.nilable([T.nilable(Date), T.nilable(Date)])) }
|
59
|
+
# def review_date_change; end
|
60
60
|
#
|
61
|
-
#
|
62
|
-
#
|
61
|
+
# sig { returns(T.nilable([T.nilable(Date), T.nilable(Date)])) }
|
62
|
+
# def saved_change_to_review_date; end
|
63
63
|
#
|
64
|
-
#
|
65
|
-
#
|
64
|
+
# sig { params(reviewd: T::Boolean).returns(T::Boolean) }
|
65
|
+
# def reviewed=(reviewed); end
|
66
66
|
#
|
67
|
-
#
|
68
|
-
#
|
67
|
+
# sig { returns(T::Boolean) }
|
68
|
+
# def reviewed; end
|
69
69
|
#
|
70
|
-
#
|
71
|
-
#
|
70
|
+
# sig { returns(T::Boolean) }
|
71
|
+
# def reviewed_was; end
|
72
72
|
#
|
73
|
-
#
|
74
|
-
#
|
73
|
+
# sig { returns(T::Boolean) }
|
74
|
+
# def reviewed_changed?; end
|
75
75
|
#
|
76
|
-
#
|
77
|
-
#
|
76
|
+
# sig { returns(T::Boolean) }
|
77
|
+
# def reviewed_before_last_save; end
|
78
78
|
#
|
79
|
-
#
|
80
|
-
#
|
79
|
+
# sig { returns(T::Boolean) }
|
80
|
+
# def saved_change_to_reviewed?; end
|
81
81
|
#
|
82
|
-
#
|
83
|
-
#
|
82
|
+
# sig { returns(T.nilable([T::Boolean, T::Boolean])) }
|
83
|
+
# def reviewed_change; end
|
84
|
+
#
|
85
|
+
# sig { returns(T.nilable([T::Boolean, T::Boolean])) }
|
86
|
+
# def saved_change_to_reviewed; end
|
87
|
+
# end
|
84
88
|
# end
|
85
89
|
# ~~~
|
86
90
|
class ActiveRecordTypedStore < Base
|
@@ -105,7 +109,11 @@ module Tapioca
|
|
105
109
|
type = type_for(field.type_sym)
|
106
110
|
type = "T.nilable(#{type})" if field.null && type != "T.untyped"
|
107
111
|
|
108
|
-
|
112
|
+
model.create_module("StoreAccessors") do |store_accessors_module|
|
113
|
+
generate_methods(store_accessors_module, field.name.to_s, type)
|
114
|
+
end
|
115
|
+
|
116
|
+
model.create_include("StoreAccessors")
|
109
117
|
end
|
110
118
|
end
|
111
119
|
end
|
@@ -6,6 +6,8 @@ require "tapioca/rbi_ext/model"
|
|
6
6
|
module Tapioca
|
7
7
|
module Compilers
|
8
8
|
module Dsl
|
9
|
+
COMPILERS_PATH = T.let(File.expand_path("..", __FILE__).to_s, String)
|
10
|
+
|
9
11
|
class Base
|
10
12
|
extend T::Sig
|
11
13
|
extend T::Helpers
|
@@ -17,9 +19,13 @@ module Tapioca
|
|
17
19
|
sig { returns(T::Set[Module]) }
|
18
20
|
attr_reader :processable_constants
|
19
21
|
|
22
|
+
sig { returns(T::Array[String]) }
|
23
|
+
attr_reader :errors
|
24
|
+
|
20
25
|
sig { void }
|
21
26
|
def initialize
|
22
27
|
@processable_constants = T.let(Set.new(gather_constants), T::Set[Module])
|
28
|
+
@errors = T.let([], T::Array[String])
|
23
29
|
end
|
24
30
|
|
25
31
|
sig { params(constant: Module).returns(T::Boolean) }
|
@@ -41,6 +47,12 @@ module Tapioca
|
|
41
47
|
sig { abstract.returns(T::Enumerable[Module]) }
|
42
48
|
def gather_constants; end
|
43
49
|
|
50
|
+
# NOTE: This should eventually accept an `Error` object or `Exception` rather than simply a `String`.
|
51
|
+
sig { params(error: String).void }
|
52
|
+
def add_error(error)
|
53
|
+
@errors << error
|
54
|
+
end
|
55
|
+
|
44
56
|
private
|
45
57
|
|
46
58
|
sig { returns(T::Enumerable[Class]) }
|