tapioca 0.3.1 → 0.4.4
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 +25 -1
- data/README.md +23 -2
- data/Rakefile +15 -4
- data/lib/tapioca.rb +8 -2
- data/lib/tapioca/cli.rb +32 -3
- data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +129 -0
- data/lib/tapioca/compilers/dsl/action_mailer.rb +65 -0
- data/lib/tapioca/compilers/dsl/active_record_associations.rb +267 -0
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +393 -0
- data/lib/tapioca/compilers/dsl/active_record_enum.rb +112 -0
- data/lib/tapioca/compilers/dsl/active_record_identity_cache.rb +213 -0
- data/lib/tapioca/compilers/dsl/active_record_scope.rb +100 -0
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +170 -0
- data/lib/tapioca/compilers/dsl/active_resource.rb +140 -0
- data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +126 -0
- data/lib/tapioca/compilers/dsl/base.rb +165 -0
- data/lib/tapioca/compilers/dsl/frozen_record.rb +96 -0
- data/lib/tapioca/compilers/dsl/protobuf.rb +144 -0
- data/lib/tapioca/compilers/dsl/smart_properties.rb +173 -0
- data/lib/tapioca/compilers/dsl/state_machines.rb +378 -0
- data/lib/tapioca/compilers/dsl/url_helpers.rb +92 -0
- data/lib/tapioca/compilers/dsl_compiler.rb +121 -0
- data/lib/tapioca/compilers/requires_compiler.rb +67 -0
- data/lib/tapioca/compilers/sorbet.rb +34 -0
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +171 -26
- data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +1 -20
- data/lib/tapioca/compilers/todos_compiler.rb +32 -0
- data/lib/tapioca/config.rb +14 -6
- data/lib/tapioca/config_builder.rb +22 -9
- data/lib/tapioca/constant_locator.rb +1 -0
- data/lib/tapioca/core_ext/class.rb +23 -0
- data/lib/tapioca/gemfile.rb +32 -9
- data/lib/tapioca/generator.rb +231 -23
- data/lib/tapioca/loader.rb +30 -9
- data/lib/tapioca/version.rb +1 -1
- metadata +32 -39
@@ -0,0 +1,393 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "parlour"
|
5
|
+
|
6
|
+
begin
|
7
|
+
require "active_record"
|
8
|
+
rescue LoadError
|
9
|
+
return
|
10
|
+
end
|
11
|
+
|
12
|
+
module Tapioca
|
13
|
+
module Compilers
|
14
|
+
module Dsl
|
15
|
+
# `Tapioca::Compilers::Dsl::ActiveRecordColumns` refines RBI files for subclasses of `ActiveRecord::Base`
|
16
|
+
# (see https://api.rubyonrails.org/classes/ActiveRecord/Base.html). This generator is only
|
17
|
+
# responsible for defining the attribute methods that would be created for the columns that
|
18
|
+
# are defined in the Active Record model.
|
19
|
+
#
|
20
|
+
# For example, with the following model class:
|
21
|
+
#
|
22
|
+
# ~~~rb
|
23
|
+
# class Post < ActiveRecord::Base
|
24
|
+
# end
|
25
|
+
# ~~~
|
26
|
+
#
|
27
|
+
# and the following database schema:
|
28
|
+
#
|
29
|
+
# ~~~rb
|
30
|
+
# # db/schema.rb
|
31
|
+
# create_table :posts do |t|
|
32
|
+
# t.string :title, null: false
|
33
|
+
# t.string :body
|
34
|
+
# t.boolean :published
|
35
|
+
# t.timestamps
|
36
|
+
# end
|
37
|
+
# ~~~
|
38
|
+
#
|
39
|
+
# this generator will produce the following methods in the RBI file
|
40
|
+
# `post.rbi`:
|
41
|
+
#
|
42
|
+
# ~~~rbi
|
43
|
+
# # post.rbi
|
44
|
+
# # typed: true
|
45
|
+
# class Post
|
46
|
+
# sig { returns(T.nilable(::String)) }
|
47
|
+
# def body; end
|
48
|
+
#
|
49
|
+
# sig { params(value: T.nilable(::String)).returns(T.nilable(::String)) }
|
50
|
+
# def body=; end
|
51
|
+
#
|
52
|
+
# sig { params(args: T.untyped).returns(T::Boolean) }
|
53
|
+
# def body?; end
|
54
|
+
#
|
55
|
+
# sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) }
|
56
|
+
# def created_at; end
|
57
|
+
#
|
58
|
+
# sig { params(value: ::ActiveSupport::TimeWithZone).returns(::ActiveSupport::TimeWithZone) }
|
59
|
+
# def created_at=; end
|
60
|
+
#
|
61
|
+
# sig { params(args: T.untyped).returns(T::Boolean) }
|
62
|
+
# def created_at?; end
|
63
|
+
#
|
64
|
+
# sig { returns(T.nilable(T::Boolean)) }
|
65
|
+
# def published; end
|
66
|
+
#
|
67
|
+
# sig { params(value: T::Boolean).returns(T::Boolean) }
|
68
|
+
# def published=; end
|
69
|
+
#
|
70
|
+
# sig { params(args: T.untyped).returns(T::Boolean) }
|
71
|
+
# def published?; end
|
72
|
+
#
|
73
|
+
# sig { returns(::String) }
|
74
|
+
# def title; end
|
75
|
+
#
|
76
|
+
# sig { params(value: ::String).returns(::String) }
|
77
|
+
# def title=(value); end
|
78
|
+
#
|
79
|
+
# sig { params(args: T.untyped).returns(T::Boolean) }
|
80
|
+
# def title?(*args); end
|
81
|
+
#
|
82
|
+
# sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) }
|
83
|
+
# def updated_at; end
|
84
|
+
#
|
85
|
+
# sig { params(value: ::ActiveSupport::TimeWithZone).returns(::ActiveSupport::TimeWithZone) }
|
86
|
+
# def updated_at=; end
|
87
|
+
#
|
88
|
+
# sig { params(args: T.untyped).returns(T::Boolean) }
|
89
|
+
# def updated_at?; end
|
90
|
+
#
|
91
|
+
# ## Also the methods added by https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Dirty.html
|
92
|
+
# ## Also the methods added by https://api.rubyonrails.org/classes/ActiveModel/Dirty.html
|
93
|
+
# ## Also the methods added by https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/BeforeTypeCast.html
|
94
|
+
# end
|
95
|
+
# ~~~
|
96
|
+
class ActiveRecordColumns < Base
|
97
|
+
extend T::Sig
|
98
|
+
|
99
|
+
sig { override.params(root: Parlour::RbiGenerator::Namespace, constant: T.class_of(ActiveRecord::Base)).void }
|
100
|
+
def decorate(root, constant)
|
101
|
+
return unless constant.table_exists?
|
102
|
+
|
103
|
+
module_name = "#{constant}::GeneratedAttributeMethods"
|
104
|
+
root.create_module(module_name) do |mod|
|
105
|
+
constant.columns_hash.each_key do |column_name|
|
106
|
+
column_name = column_name.to_s
|
107
|
+
add_methods_for_attribute(mod, constant, column_name)
|
108
|
+
end
|
109
|
+
|
110
|
+
constant.attribute_aliases.each do |attribute_name, column_name|
|
111
|
+
attribute_name = attribute_name.to_s
|
112
|
+
column_name = column_name.to_s
|
113
|
+
new_method_names = constant.attribute_method_matchers.map { |m| m.method_name(attribute_name) }
|
114
|
+
old_method_names = constant.attribute_method_matchers.map { |m| m.method_name(column_name) }
|
115
|
+
methods_to_add = new_method_names - old_method_names
|
116
|
+
|
117
|
+
add_methods_for_attribute(mod, constant, column_name, attribute_name, methods_to_add)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
root.path(constant) do |klass|
|
122
|
+
klass.create_include(module_name)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
sig { override.returns(T::Enumerable[Module]) }
|
127
|
+
def gather_constants
|
128
|
+
ActiveRecord::Base.descendants.reject(&:abstract_class?)
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
sig do
|
134
|
+
params(
|
135
|
+
klass: Parlour::RbiGenerator::Namespace,
|
136
|
+
name: String,
|
137
|
+
methods_to_add: T.nilable(T::Array[String]),
|
138
|
+
return_type: T.nilable(String),
|
139
|
+
parameters: T::Array[[String, String]]
|
140
|
+
).void
|
141
|
+
end
|
142
|
+
def add_method(klass, name, methods_to_add, return_type: nil, parameters: [])
|
143
|
+
create_method(
|
144
|
+
klass,
|
145
|
+
name,
|
146
|
+
parameters: parameters.map do |param, type|
|
147
|
+
Parlour::RbiGenerator::Parameter.new(param, type: type)
|
148
|
+
end,
|
149
|
+
return_type: return_type
|
150
|
+
) if methods_to_add.nil? || methods_to_add.include?(name)
|
151
|
+
end
|
152
|
+
|
153
|
+
sig do
|
154
|
+
params(
|
155
|
+
klass: Parlour::RbiGenerator::Namespace,
|
156
|
+
constant: T.class_of(ActiveRecord::Base),
|
157
|
+
column_name: String,
|
158
|
+
attribute_name: String,
|
159
|
+
methods_to_add: T.nilable(T::Array[String])
|
160
|
+
).void
|
161
|
+
end
|
162
|
+
def add_methods_for_attribute(klass, constant, column_name, attribute_name = column_name, methods_to_add = nil)
|
163
|
+
getter_type, setter_type = type_for(constant, column_name)
|
164
|
+
|
165
|
+
# Added by ActiveRecord::AttributeMethods::Read
|
166
|
+
#
|
167
|
+
add_method(
|
168
|
+
klass,
|
169
|
+
attribute_name.to_s,
|
170
|
+
methods_to_add,
|
171
|
+
return_type: getter_type
|
172
|
+
)
|
173
|
+
|
174
|
+
# Added by ActiveRecord::AttributeMethods::Write
|
175
|
+
#
|
176
|
+
add_method(
|
177
|
+
klass,
|
178
|
+
"#{attribute_name}=",
|
179
|
+
methods_to_add,
|
180
|
+
parameters: [["value", setter_type]],
|
181
|
+
return_type: setter_type
|
182
|
+
)
|
183
|
+
|
184
|
+
# Added by ActiveRecord::AttributeMethods::Query
|
185
|
+
#
|
186
|
+
add_method(
|
187
|
+
klass,
|
188
|
+
"#{attribute_name}?",
|
189
|
+
methods_to_add,
|
190
|
+
return_type: "T::Boolean"
|
191
|
+
)
|
192
|
+
|
193
|
+
# Added by ActiveRecord::AttributeMethods::Dirty
|
194
|
+
#
|
195
|
+
add_method(
|
196
|
+
klass,
|
197
|
+
"#{attribute_name}_before_last_save",
|
198
|
+
methods_to_add,
|
199
|
+
return_type: as_nilable_type(getter_type)
|
200
|
+
)
|
201
|
+
add_method(
|
202
|
+
klass,
|
203
|
+
"#{attribute_name}_change_to_be_saved",
|
204
|
+
methods_to_add,
|
205
|
+
return_type: "T.nilable([#{getter_type}, #{getter_type}])"
|
206
|
+
)
|
207
|
+
add_method(
|
208
|
+
klass,
|
209
|
+
"#{attribute_name}_in_database",
|
210
|
+
methods_to_add,
|
211
|
+
return_type: as_nilable_type(getter_type)
|
212
|
+
)
|
213
|
+
add_method(
|
214
|
+
klass,
|
215
|
+
"saved_change_to_#{attribute_name}",
|
216
|
+
methods_to_add,
|
217
|
+
return_type: "T.nilable([#{getter_type}, #{getter_type}])"
|
218
|
+
)
|
219
|
+
add_method(
|
220
|
+
klass,
|
221
|
+
"saved_change_to_#{attribute_name}?",
|
222
|
+
methods_to_add,
|
223
|
+
return_type: "T::Boolean"
|
224
|
+
)
|
225
|
+
add_method(
|
226
|
+
klass,
|
227
|
+
"will_save_change_to_#{attribute_name}?",
|
228
|
+
methods_to_add,
|
229
|
+
return_type: "T::Boolean"
|
230
|
+
)
|
231
|
+
|
232
|
+
# Added by ActiveModel::Dirty
|
233
|
+
#
|
234
|
+
add_method(
|
235
|
+
klass,
|
236
|
+
"#{attribute_name}_change",
|
237
|
+
methods_to_add,
|
238
|
+
return_type: "T.nilable([#{getter_type}, #{getter_type}])"
|
239
|
+
)
|
240
|
+
add_method(
|
241
|
+
klass,
|
242
|
+
"#{attribute_name}_changed?",
|
243
|
+
methods_to_add,
|
244
|
+
return_type: "T::Boolean"
|
245
|
+
)
|
246
|
+
add_method(
|
247
|
+
klass,
|
248
|
+
"#{attribute_name}_will_change!",
|
249
|
+
methods_to_add
|
250
|
+
)
|
251
|
+
add_method(
|
252
|
+
klass,
|
253
|
+
"#{attribute_name}_was",
|
254
|
+
methods_to_add,
|
255
|
+
return_type: as_nilable_type(getter_type)
|
256
|
+
)
|
257
|
+
add_method(
|
258
|
+
klass,
|
259
|
+
"#{attribute_name}_previous_change",
|
260
|
+
methods_to_add,
|
261
|
+
return_type: "T.nilable([#{getter_type}, #{getter_type}])"
|
262
|
+
)
|
263
|
+
add_method(
|
264
|
+
klass,
|
265
|
+
"#{attribute_name}_previously_changed?",
|
266
|
+
methods_to_add,
|
267
|
+
return_type: "T::Boolean"
|
268
|
+
)
|
269
|
+
add_method(
|
270
|
+
klass,
|
271
|
+
"#{attribute_name}_previously_was",
|
272
|
+
methods_to_add,
|
273
|
+
return_type: as_nilable_type(getter_type)
|
274
|
+
)
|
275
|
+
add_method(
|
276
|
+
klass,
|
277
|
+
"restore_#{attribute_name}!",
|
278
|
+
methods_to_add
|
279
|
+
)
|
280
|
+
|
281
|
+
# Added by ActiveRecord::AttributeMethods::BeforeTypeCast
|
282
|
+
#
|
283
|
+
add_method(
|
284
|
+
klass,
|
285
|
+
"#{attribute_name}_before_type_cast",
|
286
|
+
methods_to_add,
|
287
|
+
return_type: "T.untyped"
|
288
|
+
)
|
289
|
+
add_method(
|
290
|
+
klass,
|
291
|
+
"#{attribute_name}_came_from_user?",
|
292
|
+
methods_to_add,
|
293
|
+
return_type: "T::Boolean"
|
294
|
+
)
|
295
|
+
end
|
296
|
+
|
297
|
+
sig do
|
298
|
+
params(
|
299
|
+
constant: T.class_of(ActiveRecord::Base),
|
300
|
+
column_name: String
|
301
|
+
).returns([String, String])
|
302
|
+
end
|
303
|
+
def type_for(constant, column_name)
|
304
|
+
return ["T.untyped", "T.untyped"] if do_not_generate_strong_types?(constant)
|
305
|
+
|
306
|
+
column_type = constant.attribute_types[column_name]
|
307
|
+
|
308
|
+
getter_type =
|
309
|
+
case column_type
|
310
|
+
when ActiveRecord::Type::Integer
|
311
|
+
"::Integer"
|
312
|
+
when ActiveRecord::Type::String
|
313
|
+
"::String"
|
314
|
+
when ActiveRecord::Type::Date
|
315
|
+
"::Date"
|
316
|
+
when ActiveRecord::Type::Decimal
|
317
|
+
"::BigDecimal"
|
318
|
+
when ActiveRecord::Type::Float
|
319
|
+
"::Float"
|
320
|
+
when ActiveRecord::Type::Boolean
|
321
|
+
"T::Boolean"
|
322
|
+
when ActiveRecord::Type::DateTime, ActiveRecord::Type::Time
|
323
|
+
"::DateTime"
|
324
|
+
when ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter
|
325
|
+
"::ActiveSupport::TimeWithZone"
|
326
|
+
else
|
327
|
+
handle_unknown_type(column_type)
|
328
|
+
end
|
329
|
+
|
330
|
+
column = constant.columns_hash[column_name]
|
331
|
+
setter_type = getter_type
|
332
|
+
|
333
|
+
if column&.null
|
334
|
+
return ["T.nilable(#{getter_type})", "T.nilable(#{setter_type})"]
|
335
|
+
end
|
336
|
+
|
337
|
+
if column_name == constant.primary_key ||
|
338
|
+
column_name == "created_at" ||
|
339
|
+
column_name == "updated_at"
|
340
|
+
getter_type = "T.nilable(#{getter_type})"
|
341
|
+
end
|
342
|
+
|
343
|
+
[getter_type, setter_type]
|
344
|
+
end
|
345
|
+
|
346
|
+
sig { params(constant: Module).returns(T::Boolean) }
|
347
|
+
def do_not_generate_strong_types?(constant)
|
348
|
+
Object.const_defined?(:StrongTypeGeneration) &&
|
349
|
+
!(constant.singleton_class < Object.const_get(:StrongTypeGeneration))
|
350
|
+
end
|
351
|
+
|
352
|
+
sig { params(column_type: Object).returns(String) }
|
353
|
+
def handle_unknown_type(column_type)
|
354
|
+
return "T.untyped" unless ActiveModel::Type::Value === column_type
|
355
|
+
|
356
|
+
lookup_return_type_of_method(column_type, :deserialize) ||
|
357
|
+
lookup_return_type_of_method(column_type, :cast) ||
|
358
|
+
lookup_arg_type_of_method(column_type, :serialize) ||
|
359
|
+
"T.untyped"
|
360
|
+
end
|
361
|
+
|
362
|
+
sig { params(column_type: ActiveModel::Type::Value, method: Symbol).returns(T.nilable(String)) }
|
363
|
+
def lookup_return_type_of_method(column_type, method)
|
364
|
+
signature = T::Private::Methods.signature_for_method(column_type.method(method))
|
365
|
+
return unless signature
|
366
|
+
|
367
|
+
return_type = signature.return_type
|
368
|
+
return if T::Types::Simple === return_type && T::Generic === return_type.raw_type
|
369
|
+
return if return_type == T::Private::Types::Void || return_type == T::Private::Types::NotTyped
|
370
|
+
|
371
|
+
return_type.to_s
|
372
|
+
end
|
373
|
+
|
374
|
+
sig { params(column_type: ActiveModel::Type::Value, method: Symbol).returns(T.nilable(String)) }
|
375
|
+
def lookup_arg_type_of_method(column_type, method)
|
376
|
+
signature = T::Private::Methods.signature_for_method(column_type.method(method))
|
377
|
+
return unless signature
|
378
|
+
|
379
|
+
arg_type = signature.arg_types.first.last
|
380
|
+
return if T::Types::Simple === arg_type && T::Generic === arg_type.raw_type
|
381
|
+
|
382
|
+
arg_type.to_s
|
383
|
+
end
|
384
|
+
|
385
|
+
sig { params(type: String).returns(String) }
|
386
|
+
def as_nilable_type(type)
|
387
|
+
return type if type.start_with?("T.nilable(")
|
388
|
+
"T.nilable(#{type})"
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "parlour"
|
5
|
+
|
6
|
+
begin
|
7
|
+
require "active_record"
|
8
|
+
rescue LoadError
|
9
|
+
# means ActiveRecord is not installed,
|
10
|
+
# so let's not even define the generator.
|
11
|
+
return
|
12
|
+
end
|
13
|
+
|
14
|
+
module Tapioca
|
15
|
+
module Compilers
|
16
|
+
module Dsl
|
17
|
+
# `Tapioca::Compilers::Dsl::ActiveRecordEnum` decorates RBI files for subclasses of
|
18
|
+
# `ActiveRecord::Base` which declare `enum` fields
|
19
|
+
# (see https://api.rubyonrails.org/classes/ActiveRecord/Enum.html).
|
20
|
+
#
|
21
|
+
# For example, with the following `ActiveRecord::Base` subclass:
|
22
|
+
#
|
23
|
+
# ~~~rb
|
24
|
+
# class Post < ApplicationRecord
|
25
|
+
# enum title_type: %i(book all web), _suffix: :title
|
26
|
+
# end
|
27
|
+
# ~~~
|
28
|
+
#
|
29
|
+
# this generator will produce the RBI file `post.rbi` with the following content:
|
30
|
+
#
|
31
|
+
# ~~~rbi
|
32
|
+
# # post.rbi
|
33
|
+
# # typed: true
|
34
|
+
# class Post
|
35
|
+
# sig { void }
|
36
|
+
# def all_title!; end
|
37
|
+
#
|
38
|
+
# sig { returns(T::Boolean) }
|
39
|
+
# def all_title?; end
|
40
|
+
#
|
41
|
+
# sig { returns(T::Hash[T.any(String, Symbol), Integer]) }
|
42
|
+
# def self.title_types; end
|
43
|
+
#
|
44
|
+
# sig { void }
|
45
|
+
# def book_title!; end
|
46
|
+
#
|
47
|
+
# sig { returns(T::Boolean) }
|
48
|
+
# def book_title?; end
|
49
|
+
#
|
50
|
+
# sig { void }
|
51
|
+
# def web_title!; end
|
52
|
+
#
|
53
|
+
# sig { returns(T::Boolean) }
|
54
|
+
# def web_title?; end
|
55
|
+
# end
|
56
|
+
# ~~~
|
57
|
+
class ActiveRecordEnum < Base
|
58
|
+
extend T::Sig
|
59
|
+
|
60
|
+
sig { override.params(root: Parlour::RbiGenerator::Namespace, constant: T.class_of(::ActiveRecord::Base)).void }
|
61
|
+
def decorate(root, constant)
|
62
|
+
return if constant.defined_enums.empty?
|
63
|
+
|
64
|
+
module_name = "#{constant}::EnumMethodsModule"
|
65
|
+
root.create_module(module_name) do |mod|
|
66
|
+
generate_instance_methods(constant, mod)
|
67
|
+
end
|
68
|
+
|
69
|
+
root.path(constant) do |k|
|
70
|
+
k.create_include(module_name)
|
71
|
+
|
72
|
+
constant.defined_enums.each do |name, enum_map|
|
73
|
+
type = type_for_enum(enum_map)
|
74
|
+
create_method(k, name.pluralize, class_method: true, return_type: type)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
sig { override.returns(T::Enumerable[Module]) }
|
80
|
+
def gather_constants
|
81
|
+
::ActiveRecord::Base.descendants.reject(&:abstract_class?)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
sig { params(enum_map: T::Hash[T.untyped, T.untyped]).returns(String) }
|
87
|
+
def type_for_enum(enum_map)
|
88
|
+
value_type = enum_map.values.map { |v| v.class.name }.uniq
|
89
|
+
value_type = if value_type.length == 1
|
90
|
+
value_type.first
|
91
|
+
else
|
92
|
+
"T.any(#{value_type.join(', ')})"
|
93
|
+
end
|
94
|
+
|
95
|
+
"T::Hash[T.any(String, Symbol), #{value_type}]"
|
96
|
+
end
|
97
|
+
|
98
|
+
sig { params(constant: T.class_of(::ActiveRecord::Base), klass: Parlour::RbiGenerator::Namespace).void }
|
99
|
+
def generate_instance_methods(constant, klass)
|
100
|
+
methods = constant.send(:_enum_methods_module).instance_methods
|
101
|
+
|
102
|
+
methods.each do |method|
|
103
|
+
method = method.to_s
|
104
|
+
return_type = "T::Boolean" if method.end_with?("?")
|
105
|
+
|
106
|
+
create_method(klass, method, return_type: return_type)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|