tapioca 0.10.5 → 0.11.0
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/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
|