tapioca 0.10.5 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/tapioca/cli.rb +5 -1
- data/lib/tapioca/commands/annotations.rb +2 -0
- data/lib/tapioca/commands/configure.rb +1 -0
- data/lib/tapioca/commands/dsl.rb +17 -3
- data/lib/tapioca/dsl/compilers/aasm.rb +67 -15
- data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_record_columns.rb +3 -3
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +117 -66
- data/lib/tapioca/dsl/compilers/active_record_scope.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_record_secure_token.rb +74 -0
- data/lib/tapioca/dsl/compilers/graphql_input_object.rb +21 -1
- data/lib/tapioca/dsl/compilers/kredis.rb +130 -0
- data/lib/tapioca/dsl/extensions/active_record.rb +9 -0
- data/lib/tapioca/dsl/extensions/kredis.rb +114 -0
- data/lib/tapioca/dsl/helpers/active_record_constants_helper.rb +1 -0
- data/lib/tapioca/dsl/pipeline.rb +12 -5
- data/lib/tapioca/gem/listeners/sorbet_enums.rb +1 -1
- data/lib/tapioca/gem/pipeline.rb +14 -0
- data/lib/tapioca/loaders/loader.rb +93 -32
- data/lib/tapioca/rbi_ext/model.rb +1 -1
- data/lib/tapioca/runtime/attached_class_of_32.rb +20 -0
- data/lib/tapioca/runtime/attached_class_of_legacy.rb +27 -0
- data/lib/tapioca/runtime/reflection.rb +11 -10
- data/lib/tapioca/static/symbol_loader.rb +14 -14
- data/lib/tapioca/version.rb +1 -1
- metadata +7 -2
@@ -164,16 +164,10 @@ module Tapioca
|
|
164
164
|
|
165
165
|
sig { override.void }
|
166
166
|
def decorate
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
create_classes_and_includes(model)
|
173
|
-
create_common_methods(common_relation_methods_module)
|
174
|
-
create_relation_methods(relation_methods_module, association_relation_methods_module)
|
175
|
-
create_association_relation_methods(association_relation_methods_module)
|
176
|
-
end
|
167
|
+
create_classes_and_includes
|
168
|
+
create_common_methods
|
169
|
+
create_relation_methods
|
170
|
+
create_association_relation_methods
|
177
171
|
end
|
178
172
|
|
179
173
|
class << self
|
@@ -181,7 +175,7 @@ module Tapioca
|
|
181
175
|
|
182
176
|
sig { override.returns(T::Enumerable[Module]) }
|
183
177
|
def gather_constants
|
184
|
-
ActiveRecord::Base.
|
178
|
+
descendants_of(ActiveRecord::Base).reject(&:abstract_class?)
|
185
179
|
end
|
186
180
|
end
|
187
181
|
|
@@ -224,6 +218,7 @@ module Tapioca
|
|
224
218
|
defined?(ActiveRecord::SignedId) ? ActiveRecord::SignedId::ClassMethods.instance_methods(false) : [],
|
225
219
|
T::Array[Symbol],
|
226
220
|
)
|
221
|
+
BATCHES_METHODS = T.let(ActiveRecord::Batches.instance_methods(false), T::Array[Symbol])
|
227
222
|
CALCULATION_METHODS = T.let(ActiveRecord::Calculations.instance_methods(false), T::Array[Symbol])
|
228
223
|
ENUMERABLE_QUERY_METHODS = T.let([:any?, :many?, :none?, :one?], T::Array[Symbol])
|
229
224
|
FIND_OR_CREATE_METHODS = T.let(
|
@@ -234,6 +229,38 @@ module Tapioca
|
|
234
229
|
|
235
230
|
private
|
236
231
|
|
232
|
+
sig { returns(RBI::Scope) }
|
233
|
+
def model
|
234
|
+
@model ||= T.let(
|
235
|
+
root.create_path(constant),
|
236
|
+
T.nilable(RBI::Scope),
|
237
|
+
)
|
238
|
+
end
|
239
|
+
|
240
|
+
sig { returns(RBI::Scope) }
|
241
|
+
def relation_methods_module
|
242
|
+
@relation_methods_module ||= T.let(
|
243
|
+
model.create_module(RelationMethodsModuleName),
|
244
|
+
T.nilable(RBI::Scope),
|
245
|
+
)
|
246
|
+
end
|
247
|
+
|
248
|
+
sig { returns(RBI::Scope) }
|
249
|
+
def association_relation_methods_module
|
250
|
+
@association_relation_methods_module ||= T.let(
|
251
|
+
model.create_module(AssociationRelationMethodsModuleName),
|
252
|
+
T.nilable(RBI::Scope),
|
253
|
+
)
|
254
|
+
end
|
255
|
+
|
256
|
+
sig { returns(RBI::Scope) }
|
257
|
+
def common_relation_methods_module
|
258
|
+
@common_relation_methods_module ||= T.let(
|
259
|
+
model.create_module(CommonRelationMethodsModuleName),
|
260
|
+
T.nilable(RBI::Scope),
|
261
|
+
)
|
262
|
+
end
|
263
|
+
|
237
264
|
sig { returns(String) }
|
238
265
|
def constant_name
|
239
266
|
@constant_name ||= T.let(T.must(qualified_name_of(constant)), T.nilable(String))
|
@@ -244,8 +271,8 @@ module Tapioca
|
|
244
271
|
method_name.to_s.end_with?("!")
|
245
272
|
end
|
246
273
|
|
247
|
-
sig {
|
248
|
-
def create_classes_and_includes
|
274
|
+
sig { void }
|
275
|
+
def create_classes_and_includes
|
249
276
|
model.create_extend(CommonRelationMethodsModuleName)
|
250
277
|
# The model always extends the generated relation module
|
251
278
|
model.create_extend(RelationMethodsModuleName)
|
@@ -254,13 +281,13 @@ module Tapioca
|
|
254
281
|
# See https://github.com/sorbet/sorbet/pull/4706 for details
|
255
282
|
model.create_method("to_ary", return_type: "NilClass", visibility: RBI::Private.new)
|
256
283
|
|
257
|
-
create_relation_class
|
258
|
-
create_association_relation_class
|
259
|
-
create_collection_proxy_class
|
284
|
+
create_relation_class
|
285
|
+
create_association_relation_class
|
286
|
+
create_collection_proxy_class
|
260
287
|
end
|
261
288
|
|
262
|
-
sig {
|
263
|
-
def create_relation_class
|
289
|
+
sig { void }
|
290
|
+
def create_relation_class
|
264
291
|
superclass = "::ActiveRecord::Relation"
|
265
292
|
|
266
293
|
# The relation subclass includes the generated relation module
|
@@ -272,11 +299,11 @@ module Tapioca
|
|
272
299
|
klass.create_method("to_ary", return_type: "T::Array[#{constant_name}]")
|
273
300
|
end
|
274
301
|
|
275
|
-
create_relation_where_chain_class
|
302
|
+
create_relation_where_chain_class
|
276
303
|
end
|
277
304
|
|
278
|
-
sig {
|
279
|
-
def create_association_relation_class
|
305
|
+
sig { void }
|
306
|
+
def create_association_relation_class
|
280
307
|
superclass = "::ActiveRecord::AssociationRelation"
|
281
308
|
|
282
309
|
# Association subclasses include the generated association relation module
|
@@ -288,19 +315,19 @@ module Tapioca
|
|
288
315
|
klass.create_method("to_ary", return_type: "T::Array[#{constant_name}]")
|
289
316
|
end
|
290
317
|
|
291
|
-
create_association_relation_where_chain_class
|
318
|
+
create_association_relation_where_chain_class
|
292
319
|
end
|
293
320
|
|
294
|
-
sig {
|
295
|
-
def create_relation_where_chain_class
|
321
|
+
sig { void }
|
322
|
+
def create_relation_where_chain_class
|
296
323
|
model.create_class(RelationWhereChainClassName, superclass_name: RelationClassName) do |klass|
|
297
324
|
create_where_chain_methods(klass, RelationClassName)
|
298
325
|
klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
|
299
326
|
end
|
300
327
|
end
|
301
328
|
|
302
|
-
sig {
|
303
|
-
def create_association_relation_where_chain_class
|
329
|
+
sig { void }
|
330
|
+
def create_association_relation_where_chain_class
|
304
331
|
model.create_class(
|
305
332
|
AssociationRelationWhereChainClassName,
|
306
333
|
superclass_name: AssociationRelationClassName,
|
@@ -335,8 +362,8 @@ module Tapioca
|
|
335
362
|
end
|
336
363
|
end
|
337
364
|
|
338
|
-
sig {
|
339
|
-
def create_collection_proxy_class
|
365
|
+
sig { void }
|
366
|
+
def create_collection_proxy_class
|
340
367
|
superclass = "::ActiveRecord::Associations::CollectionProxy"
|
341
368
|
|
342
369
|
# The relation subclass includes the generated association relation module
|
@@ -429,13 +456,11 @@ module Tapioca
|
|
429
456
|
end
|
430
457
|
end
|
431
458
|
|
432
|
-
sig {
|
433
|
-
def create_relation_methods
|
434
|
-
create_relation_method("all"
|
459
|
+
sig { void }
|
460
|
+
def create_relation_methods
|
461
|
+
create_relation_method("all")
|
435
462
|
create_relation_method(
|
436
463
|
"where",
|
437
|
-
relation_methods_module,
|
438
|
-
association_relation_methods_module,
|
439
464
|
parameters: [
|
440
465
|
create_rest_param("args", type: "T.untyped"),
|
441
466
|
create_block_param("blk", type: "T.untyped"),
|
@@ -447,8 +472,6 @@ module Tapioca
|
|
447
472
|
QUERY_METHODS.each do |method_name|
|
448
473
|
create_relation_method(
|
449
474
|
method_name,
|
450
|
-
relation_methods_module,
|
451
|
-
association_relation_methods_module,
|
452
475
|
parameters: [
|
453
476
|
create_rest_param("args", type: "T.untyped"),
|
454
477
|
create_block_param("blk", type: "T.untyped"),
|
@@ -457,8 +480,8 @@ module Tapioca
|
|
457
480
|
end
|
458
481
|
end
|
459
482
|
|
460
|
-
sig {
|
461
|
-
def create_association_relation_methods
|
483
|
+
sig { void }
|
484
|
+
def create_association_relation_methods
|
462
485
|
returning_type = "T.nilable(T.any(T::Array[Symbol], FalseClass))"
|
463
486
|
unique_by_type = "T.nilable(T.any(T::Array[Symbol], Symbol))"
|
464
487
|
|
@@ -502,11 +525,10 @@ module Tapioca
|
|
502
525
|
end
|
503
526
|
end
|
504
527
|
|
505
|
-
sig {
|
506
|
-
def create_common_methods
|
528
|
+
sig { void }
|
529
|
+
def create_common_methods
|
507
530
|
create_common_method(
|
508
531
|
"destroy_all",
|
509
|
-
common_relation_methods_module,
|
510
532
|
return_type: "T::Array[#{constant_name}]",
|
511
533
|
)
|
512
534
|
|
@@ -515,7 +537,6 @@ module Tapioca
|
|
515
537
|
when :exists?
|
516
538
|
create_common_method(
|
517
539
|
"exists?",
|
518
|
-
common_relation_methods_module,
|
519
540
|
parameters: [
|
520
541
|
create_opt_param("conditions", type: "T.untyped", default: ":none"),
|
521
542
|
],
|
@@ -524,7 +545,6 @@ module Tapioca
|
|
524
545
|
when :include?, :member?
|
525
546
|
create_common_method(
|
526
547
|
method_name,
|
527
|
-
common_relation_methods_module,
|
528
548
|
parameters: [
|
529
549
|
create_param("record", type: "T.untyped"),
|
530
550
|
],
|
@@ -533,7 +553,6 @@ module Tapioca
|
|
533
553
|
when :find
|
534
554
|
create_common_method(
|
535
555
|
"find",
|
536
|
-
common_relation_methods_module,
|
537
556
|
parameters: [
|
538
557
|
create_rest_param("args", type: "T.untyped"),
|
539
558
|
],
|
@@ -542,7 +561,6 @@ module Tapioca
|
|
542
561
|
when :find_by
|
543
562
|
create_common_method(
|
544
563
|
"find_by",
|
545
|
-
common_relation_methods_module,
|
546
564
|
parameters: [
|
547
565
|
create_rest_param("args", type: "T.untyped"),
|
548
566
|
],
|
@@ -551,7 +569,6 @@ module Tapioca
|
|
551
569
|
when :find_by!
|
552
570
|
create_common_method(
|
553
571
|
"find_by!",
|
554
|
-
common_relation_methods_module,
|
555
572
|
parameters: [
|
556
573
|
create_rest_param("args", type: "T.untyped"),
|
557
574
|
],
|
@@ -560,7 +577,6 @@ module Tapioca
|
|
560
577
|
when :find_sole_by
|
561
578
|
create_common_method(
|
562
579
|
"find_sole_by",
|
563
|
-
common_relation_methods_module,
|
564
580
|
parameters: [
|
565
581
|
create_param("arg", type: "T.untyped"),
|
566
582
|
create_rest_param("args", type: "T.untyped"),
|
@@ -570,14 +586,12 @@ module Tapioca
|
|
570
586
|
when :sole
|
571
587
|
create_common_method(
|
572
588
|
"sole",
|
573
|
-
common_relation_methods_module,
|
574
589
|
parameters: [],
|
575
590
|
return_type: constant_name,
|
576
591
|
)
|
577
592
|
when :first, :last, :take
|
578
593
|
create_common_method(
|
579
594
|
method_name,
|
580
|
-
common_relation_methods_module,
|
581
595
|
parameters: [
|
582
596
|
create_opt_param("limit", type: "T.untyped", default: "nil"),
|
583
597
|
],
|
@@ -594,7 +608,6 @@ module Tapioca
|
|
594
608
|
|
595
609
|
create_common_method(
|
596
610
|
method_name,
|
597
|
-
common_relation_methods_module,
|
598
611
|
return_type: return_type,
|
599
612
|
)
|
600
613
|
end
|
@@ -605,7 +618,6 @@ module Tapioca
|
|
605
618
|
when :find_signed
|
606
619
|
create_common_method(
|
607
620
|
"find_signed",
|
608
|
-
common_relation_methods_module,
|
609
621
|
parameters: [
|
610
622
|
create_param("signed_id", type: "T.untyped"),
|
611
623
|
create_kw_opt_param("purpose", type: "T.untyped", default: "nil"),
|
@@ -615,7 +627,6 @@ module Tapioca
|
|
615
627
|
when :find_signed!
|
616
628
|
create_common_method(
|
617
629
|
"find_signed!",
|
618
|
-
common_relation_methods_module,
|
619
630
|
parameters: [
|
620
631
|
create_param("signed_id", type: "T.untyped"),
|
621
632
|
create_kw_opt_param("purpose", type: "T.untyped", default: "nil"),
|
@@ -630,7 +641,6 @@ module Tapioca
|
|
630
641
|
when :average, :maximum, :minimum
|
631
642
|
create_common_method(
|
632
643
|
method_name,
|
633
|
-
common_relation_methods_module,
|
634
644
|
parameters: [
|
635
645
|
create_param("column_name", type: "T.any(String, Symbol)"),
|
636
646
|
],
|
@@ -639,7 +649,6 @@ module Tapioca
|
|
639
649
|
when :calculate
|
640
650
|
create_common_method(
|
641
651
|
"calculate",
|
642
|
-
common_relation_methods_module,
|
643
652
|
parameters: [
|
644
653
|
create_param("operation", type: "Symbol"),
|
645
654
|
create_param("column_name", type: "T.any(String, Symbol)"),
|
@@ -649,18 +658,16 @@ module Tapioca
|
|
649
658
|
when :count
|
650
659
|
create_common_method(
|
651
660
|
"count",
|
652
|
-
common_relation_methods_module,
|
653
661
|
parameters: [
|
654
662
|
create_opt_param("column_name", type: "T.untyped", default: "nil"),
|
655
663
|
],
|
656
664
|
return_type: "T.untyped",
|
657
665
|
)
|
658
666
|
when :ids
|
659
|
-
create_common_method("ids",
|
667
|
+
create_common_method("ids", return_type: "Array")
|
660
668
|
when :pick, :pluck
|
661
669
|
create_common_method(
|
662
670
|
method_name,
|
663
|
-
common_relation_methods_module,
|
664
671
|
parameters: [
|
665
672
|
create_rest_param("column_names", type: "T.untyped"),
|
666
673
|
],
|
@@ -669,7 +676,6 @@ module Tapioca
|
|
669
676
|
when :sum
|
670
677
|
create_common_method(
|
671
678
|
"sum",
|
672
|
-
common_relation_methods_module,
|
673
679
|
parameters: [
|
674
680
|
create_opt_param("column_name", type: "T.nilable(T.any(String, Symbol))", default: "nil"),
|
675
681
|
create_block_param("block", type: "T.nilable(T.proc.params(record: T.untyped).returns(T.untyped))"),
|
@@ -679,11 +685,63 @@ module Tapioca
|
|
679
685
|
end
|
680
686
|
end
|
681
687
|
|
688
|
+
BATCHES_METHODS.each do |method_name|
|
689
|
+
case method_name
|
690
|
+
when :find_each
|
691
|
+
order = ActiveRecord::Batches.instance_method(:find_each).parameters.include?([:key, :order])
|
692
|
+
create_common_method(
|
693
|
+
"find_each",
|
694
|
+
parameters: [
|
695
|
+
create_kw_opt_param("start", type: "T.untyped", default: "nil"),
|
696
|
+
create_kw_opt_param("finish", type: "T.untyped", default: "nil"),
|
697
|
+
create_kw_opt_param("batch_size", type: "Integer", default: "1000"),
|
698
|
+
create_kw_opt_param("error_on_ignore", type: "T.untyped", default: "nil"),
|
699
|
+
*(create_kw_opt_param("order", type: "Symbol", default: ":asc") if order),
|
700
|
+
create_block_param("block", type: "T.nilable(T.proc.params(object: #{constant_name}).void)"),
|
701
|
+
],
|
702
|
+
return_type: "T.nilable(T::Enumerator[#{constant_name}])",
|
703
|
+
)
|
704
|
+
when :find_in_batches
|
705
|
+
order = ActiveRecord::Batches.instance_method(:find_in_batches).parameters.include?([:key, :order])
|
706
|
+
create_common_method(
|
707
|
+
"find_in_batches",
|
708
|
+
parameters: [
|
709
|
+
create_kw_opt_param("start", type: "T.untyped", default: "nil"),
|
710
|
+
create_kw_opt_param("finish", type: "T.untyped", default: "nil"),
|
711
|
+
create_kw_opt_param("batch_size", type: "Integer", default: "1000"),
|
712
|
+
create_kw_opt_param("error_on_ignore", type: "T.untyped", default: "nil"),
|
713
|
+
*(create_kw_opt_param("order", type: "Symbol", default: ":asc") if order),
|
714
|
+
create_block_param(
|
715
|
+
"block",
|
716
|
+
type: "T.nilable(T.proc.params(object: T::Array[#{constant_name}]).void)",
|
717
|
+
),
|
718
|
+
],
|
719
|
+
return_type: "T.nilable(T::Enumerator[T::Enumerator[#{constant_name}]])",
|
720
|
+
)
|
721
|
+
when :in_batches
|
722
|
+
order = ActiveRecord::Batches.instance_method(:in_batches).parameters.include?([:key, :order])
|
723
|
+
use_ranges = ActiveRecord::Batches.instance_method(:in_batches).parameters.include?([:key, :use_ranges])
|
724
|
+
create_common_method(
|
725
|
+
"in_batches",
|
726
|
+
parameters: [
|
727
|
+
create_kw_opt_param("of", type: "Integer", default: "1000"),
|
728
|
+
create_kw_opt_param("start", type: "T.untyped", default: "nil"),
|
729
|
+
create_kw_opt_param("finish", type: "T.untyped", default: "nil"),
|
730
|
+
create_kw_opt_param("load", type: "T.untyped", default: "false"),
|
731
|
+
create_kw_opt_param("error_on_ignore", type: "T.untyped", default: "nil"),
|
732
|
+
*(create_kw_opt_param("order", type: "Symbol", default: ":asc") if order),
|
733
|
+
*(create_kw_opt_param("use_ranges", type: "T.untyped", default: "nil") if use_ranges),
|
734
|
+
create_block_param("block", type: "T.nilable(T.proc.params(object: #{RelationClassName}).void)"),
|
735
|
+
],
|
736
|
+
return_type: "T.nilable(::ActiveRecord::Batches::BatchEnumerator)",
|
737
|
+
)
|
738
|
+
end
|
739
|
+
end
|
740
|
+
|
682
741
|
ENUMERABLE_QUERY_METHODS.each do |method_name|
|
683
742
|
block_type = "T.nilable(T.proc.params(record: #{constant_name}).returns(T.untyped))"
|
684
743
|
create_common_method(
|
685
744
|
method_name,
|
686
|
-
common_relation_methods_module,
|
687
745
|
parameters: [
|
688
746
|
create_block_param("block", type: block_type),
|
689
747
|
],
|
@@ -695,7 +753,6 @@ module Tapioca
|
|
695
753
|
block_type = "T.nilable(T.proc.params(object: #{constant_name}).void)"
|
696
754
|
create_common_method(
|
697
755
|
method_name,
|
698
|
-
common_relation_methods_module,
|
699
756
|
parameters: [
|
700
757
|
create_param("attributes", type: "T.untyped"),
|
701
758
|
create_block_param("block", type: block_type),
|
@@ -707,7 +764,6 @@ module Tapioca
|
|
707
764
|
BUILDER_METHODS.each do |method_name|
|
708
765
|
create_common_method(
|
709
766
|
method_name,
|
710
|
-
common_relation_methods_module,
|
711
767
|
parameters: [
|
712
768
|
create_opt_param("attributes", type: "T.untyped", default: "nil"),
|
713
769
|
create_block_param("block", type: "T.nilable(T.proc.params(object: #{constant_name}).void)"),
|
@@ -720,12 +776,11 @@ module Tapioca
|
|
720
776
|
sig do
|
721
777
|
params(
|
722
778
|
name: T.any(Symbol, String),
|
723
|
-
common_relation_methods_module: RBI::Scope,
|
724
779
|
parameters: T::Array[RBI::TypedParam],
|
725
780
|
return_type: T.nilable(String),
|
726
781
|
).void
|
727
782
|
end
|
728
|
-
def create_common_method(name,
|
783
|
+
def create_common_method(name, parameters: [], return_type: nil)
|
729
784
|
common_relation_methods_module.create_method(
|
730
785
|
name.to_s,
|
731
786
|
parameters: parameters,
|
@@ -736,8 +791,6 @@ module Tapioca
|
|
736
791
|
sig do
|
737
792
|
params(
|
738
793
|
name: T.any(Symbol, String),
|
739
|
-
relation_methods_module: RBI::Scope,
|
740
|
-
association_relation_methods_module: RBI::Scope,
|
741
794
|
parameters: T::Array[RBI::TypedParam],
|
742
795
|
relation_return_type: String,
|
743
796
|
association_return_type: String,
|
@@ -745,8 +798,6 @@ module Tapioca
|
|
745
798
|
end
|
746
799
|
def create_relation_method(
|
747
800
|
name,
|
748
|
-
relation_methods_module,
|
749
|
-
association_relation_methods_module,
|
750
801
|
parameters: [],
|
751
802
|
relation_return_type: RelationClassName,
|
752
803
|
association_return_type: AssociationRelationClassName
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "active_record"
|
6
|
+
rescue LoadError
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
require "tapioca/dsl/helpers/active_record_constants_helper"
|
11
|
+
|
12
|
+
module Tapioca
|
13
|
+
module Dsl
|
14
|
+
module Compilers
|
15
|
+
# `Tapioca::Dsl::Compilers::ActiveModelSecurePassword` decorates RBI files for all
|
16
|
+
# classes that use [`ActiveRecord::SecureToken`](https://api.rubyonrails.org/classes/ActiveRecord/SecureToken/ClassMethods.html).
|
17
|
+
#
|
18
|
+
# For example, with the following class:
|
19
|
+
#
|
20
|
+
# ~~~rb
|
21
|
+
# class User < ActiveRecord::Base
|
22
|
+
# has_secure_token
|
23
|
+
# has_secure_token :auth_token, length: 36
|
24
|
+
# end
|
25
|
+
# ~~~
|
26
|
+
#
|
27
|
+
# this compiler will produce an RBI file with the following content:
|
28
|
+
# ~~~rbi
|
29
|
+
# # typed: true
|
30
|
+
#
|
31
|
+
# class User
|
32
|
+
# sig { returns(T::Boolean) }
|
33
|
+
# def regenerate_token; end
|
34
|
+
#
|
35
|
+
# sig { returns(T::Boolean) }
|
36
|
+
# def regenerate_auth_token; end
|
37
|
+
# end
|
38
|
+
# ~~~
|
39
|
+
class ActiveRecordSecureToken < Compiler
|
40
|
+
extend T::Sig
|
41
|
+
include Helpers::ActiveRecordConstantsHelper
|
42
|
+
|
43
|
+
ConstantType = type_member { { fixed: T.all(T.class_of(ActiveRecord::Base), Extensions::ActiveRecord) } }
|
44
|
+
|
45
|
+
sig { override.void }
|
46
|
+
def decorate
|
47
|
+
return if constant.__tapioca_secure_tokens.nil?
|
48
|
+
|
49
|
+
root.create_path(constant) do |model|
|
50
|
+
model.create_module(SecureTokensModuleName) do |mod|
|
51
|
+
constant.__tapioca_secure_tokens.each do |attribute|
|
52
|
+
mod.create_method(
|
53
|
+
"regenerate_#{attribute}",
|
54
|
+
return_type: "T::Boolean",
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
model.create_include(SecureTokensModuleName)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class << self
|
64
|
+
extend T::Sig
|
65
|
+
|
66
|
+
sig { override.returns(T::Enumerable[Module]) }
|
67
|
+
def gather_constants
|
68
|
+
descendants_of(::ActiveRecord::Base).reject(&:abstract_class?)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -45,7 +45,11 @@ module Tapioca
|
|
45
45
|
|
46
46
|
sig { override.void }
|
47
47
|
def decorate
|
48
|
-
|
48
|
+
# Skip methods explicitly defined in code
|
49
|
+
arguments = constant.all_argument_definitions.select do |argument|
|
50
|
+
method_defined_by_graphql?(argument.keyword.to_s)
|
51
|
+
end
|
52
|
+
|
49
53
|
return if arguments.empty?
|
50
54
|
|
51
55
|
root.create_path(constant) do |input_object|
|
@@ -56,6 +60,22 @@ module Tapioca
|
|
56
60
|
end
|
57
61
|
end
|
58
62
|
|
63
|
+
private
|
64
|
+
|
65
|
+
sig { returns(T.nilable(String)) }
|
66
|
+
def graphql_input_object_argument_source_file
|
67
|
+
@graphql_input_object_argument_source_file ||= T.let(
|
68
|
+
GraphQL::Schema::InputObject.method(:argument).source_location&.first,
|
69
|
+
T.nilable(String),
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
sig { params(method_name: String).returns(T::Boolean) }
|
74
|
+
def method_defined_by_graphql?(method_name)
|
75
|
+
method_file = constant.instance_method(method_name).source_location&.first
|
76
|
+
!!(method_file && graphql_input_object_argument_source_file == method_file)
|
77
|
+
end
|
78
|
+
|
59
79
|
class << self
|
60
80
|
extend T::Sig
|
61
81
|
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "kredis"
|
6
|
+
rescue LoadError
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
module Tapioca
|
11
|
+
module Dsl
|
12
|
+
module Compilers
|
13
|
+
# `Tapioca::Dsl::Compilers::Kredis` decorates RBI files for all
|
14
|
+
# classes that include [`Kredis::Attributes`](https://github.com/rails/kredis/blob/main/lib/kredis/attributes.rb).
|
15
|
+
#
|
16
|
+
# For example, with the following class:
|
17
|
+
#
|
18
|
+
# ~~~rb
|
19
|
+
# class Person < ApplicationRecord
|
20
|
+
# kredis_list :names
|
21
|
+
# kredis_flag :awesome
|
22
|
+
# kredis_counter :steps, expires_in: 1.hour
|
23
|
+
# kredis_enum :morning, values: %w[ bright blue black ], default: "bright"
|
24
|
+
# end
|
25
|
+
# ~~~
|
26
|
+
#
|
27
|
+
# this compiler will produce an RBI file with the following content:
|
28
|
+
# ~~~rbi
|
29
|
+
# # typed: true
|
30
|
+
#
|
31
|
+
# class Person
|
32
|
+
# module GeneratedKredisAttributeMethods
|
33
|
+
# sig { returns(Kredis::Types::Flag) }
|
34
|
+
# def awesome; end
|
35
|
+
#
|
36
|
+
# sig { returns(T::Boolean) }
|
37
|
+
# def awesome?; end
|
38
|
+
#
|
39
|
+
# sig { returns(PrivateEnumMorning) }
|
40
|
+
# def morning; end
|
41
|
+
#
|
42
|
+
# sig { returns(Kredis::Types::List) }
|
43
|
+
# def names; end
|
44
|
+
#
|
45
|
+
# sig { returns(Kredis::Types::Counter) }
|
46
|
+
# def steps; end
|
47
|
+
#
|
48
|
+
# class PrivateEnumMorning < Kredis::Types::Enum
|
49
|
+
# sig { void }
|
50
|
+
# def black!; end
|
51
|
+
#
|
52
|
+
# sig { returns(T::Boolean) }
|
53
|
+
# def black?; end
|
54
|
+
#
|
55
|
+
# sig { void }
|
56
|
+
# def blue!; end
|
57
|
+
#
|
58
|
+
# sig { returns(T::Boolean) }
|
59
|
+
# def blue?; end
|
60
|
+
#
|
61
|
+
# sig { void }
|
62
|
+
# def bright!; end
|
63
|
+
#
|
64
|
+
# sig { returns(T::Boolean) }
|
65
|
+
# def bright?; end
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
# ~~~
|
70
|
+
class Kredis < Compiler
|
71
|
+
extend T::Sig
|
72
|
+
|
73
|
+
ConstantType = type_member { { fixed: T.all(Class, ::Kredis::Attributes::ClassMethods, Extensions::Kredis) } }
|
74
|
+
|
75
|
+
sig { override.void }
|
76
|
+
def decorate
|
77
|
+
return if constant.__tapioca_kredis_types.nil?
|
78
|
+
|
79
|
+
module_name = "GeneratedKredisAttributeMethods"
|
80
|
+
|
81
|
+
root.create_path(constant) do |model|
|
82
|
+
model.create_module(module_name) do |mod|
|
83
|
+
constant.__tapioca_kredis_types.each do |method, data|
|
84
|
+
generate_methods(mod, method, data)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
model.create_include(module_name)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class << self
|
92
|
+
extend T::Sig
|
93
|
+
|
94
|
+
sig { override.returns(T::Enumerable[Module]) }
|
95
|
+
def gather_constants
|
96
|
+
all_classes
|
97
|
+
.grep(::Kredis::Attributes::ClassMethods)
|
98
|
+
.reject { |klass| klass.to_s == "ActiveRecord::Base" || klass.try(:abstract_class?) }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
sig { params(mod: RBI::Scope, method: String, data: T::Hash[Symbol, T.untyped]).void }
|
105
|
+
def generate_methods(mod, method, data)
|
106
|
+
return_type = data.fetch(:type)
|
107
|
+
case return_type
|
108
|
+
when "Kredis::Types::Enum"
|
109
|
+
klass_name = "PrivateEnum#{method.split("_").map(&:capitalize).join}"
|
110
|
+
create_enum_class(mod, klass_name, data.fetch(:values))
|
111
|
+
return_type = klass_name
|
112
|
+
when "Kredis::Types::Flag"
|
113
|
+
mod.create_method("#{method}?", return_type: "T::Boolean")
|
114
|
+
end
|
115
|
+
|
116
|
+
mod.create_method(method, return_type: return_type)
|
117
|
+
end
|
118
|
+
|
119
|
+
sig { params(mod: RBI::Scope, klass_name: String, values: T::Array[T.untyped]).void }
|
120
|
+
def create_enum_class(mod, klass_name, values)
|
121
|
+
klass = mod.create_class(klass_name, superclass_name: "Kredis::Types::Enum")
|
122
|
+
values.each do |value|
|
123
|
+
klass.create_method("#{value}!", return_type: "void")
|
124
|
+
klass.create_method("#{value}?", return_type: "T::Boolean")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|