tapioca 0.15.1 → 0.16.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/dsl/compiler.rb +2 -2
- data/lib/tapioca/dsl/compilers/active_model_validations_confirmation.rb +1 -3
- data/lib/tapioca/dsl/compilers/active_record_associations.rb +13 -0
- data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +219 -207
- data/lib/tapioca/dsl/compilers/active_support_concern.rb +7 -8
- data/lib/tapioca/dsl/compilers/active_support_time_ext.rb +68 -0
- data/lib/tapioca/dsl/compilers/graphql_input_object.rb +1 -1
- data/lib/tapioca/dsl/compilers/graphql_mutation.rb +1 -1
- data/lib/tapioca/dsl/compilers/identity_cache.rb +1 -1
- data/lib/tapioca/dsl/compilers/json_api_client_resource.rb +1 -1
- data/lib/tapioca/dsl/compilers/protobuf.rb +1 -3
- data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +1 -1
- data/lib/tapioca/dsl/compilers/smart_properties.rb +3 -2
- data/lib/tapioca/dsl/compilers/state_machines.rb +3 -3
- data/lib/tapioca/dsl/compilers/url_helpers.rb +25 -13
- data/lib/tapioca/helpers/test/dsl_compiler.rb +1 -0
- data/lib/tapioca/loaders/dsl.rb +7 -0
- data/lib/tapioca/loaders/loader.rb +15 -4
- data/lib/tapioca/rbi_ext/model.rb +15 -42
- data/lib/tapioca/runtime/reflection.rb +1 -1
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +1 -0
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a448cd511151879e4eef761b28cc8f5b1904f0d57e560a38af09bdda9689f98
|
4
|
+
data.tar.gz: 563c5e68f866444da629a4b206fed22b8a27531c36c0378d669886aa2a704eaf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c847afeb5c173ad8b0c46a0f2fd214336150124fd96f0c729029ce492a5f4aea4bf5d26adfd64cf386486f22342b21f502cdbc52c68ca544a65c4bf6777dacee
|
7
|
+
data.tar.gz: e25a62343cc4522d37e9508b4215f6efb9115b93e1e9ba38c71edf26da025126732b4762b834304d0e439c741d581f238e29e22dded9fcbf0415256041f8f849
|
data/lib/tapioca/dsl/compiler.rb
CHANGED
@@ -49,7 +49,7 @@ module Tapioca
|
|
49
49
|
sig { returns(T::Enumerable[T::Class[T.anything]]) }
|
50
50
|
def all_classes
|
51
51
|
@all_classes ||= T.let(
|
52
|
-
|
52
|
+
ObjectSpace.each_object(Class),
|
53
53
|
T.nilable(T::Enumerable[T::Class[T.anything]]),
|
54
54
|
)
|
55
55
|
end
|
@@ -57,7 +57,7 @@ module Tapioca
|
|
57
57
|
sig { returns(T::Enumerable[Module]) }
|
58
58
|
def all_modules
|
59
59
|
@all_modules ||= T.let(
|
60
|
-
|
60
|
+
ObjectSpace.each_object(Module),
|
61
61
|
T.nilable(T::Enumerable[Module]),
|
62
62
|
)
|
63
63
|
end
|
@@ -57,9 +57,7 @@ module Tapioca
|
|
57
57
|
sig { override.returns(T::Enumerable[Module]) }
|
58
58
|
def gather_constants
|
59
59
|
# Collect all the classes that include ActiveModel::Validations
|
60
|
-
all_classes.select
|
61
|
-
c < ActiveModel::Validations
|
62
|
-
end
|
60
|
+
all_classes.select { |c| ActiveModel::Validations > c }
|
63
61
|
end
|
64
62
|
end
|
65
63
|
|
@@ -188,6 +188,7 @@ module Tapioca
|
|
188
188
|
def populate_single_assoc_getter_setter(klass, association_name, reflection)
|
189
189
|
association_class = type_for(reflection)
|
190
190
|
association_type = as_nilable_type(association_class)
|
191
|
+
association_methods_module = constant.generated_association_methods
|
191
192
|
|
192
193
|
klass.create_method(
|
193
194
|
association_name.to_s,
|
@@ -206,6 +207,18 @@ module Tapioca
|
|
206
207
|
"reset_#{association_name}",
|
207
208
|
return_type: "void",
|
208
209
|
)
|
210
|
+
if association_methods_module.method_defined?("#{association_name}_changed?")
|
211
|
+
klass.create_method(
|
212
|
+
"#{association_name}_changed?",
|
213
|
+
return_type: "T::Boolean",
|
214
|
+
)
|
215
|
+
end
|
216
|
+
if association_methods_module.method_defined?("#{association_name}_previously_changed?")
|
217
|
+
klass.create_method(
|
218
|
+
"#{association_name}_previously_changed?",
|
219
|
+
return_type: "T::Boolean",
|
220
|
+
)
|
221
|
+
end
|
209
222
|
unless reflection.polymorphic?
|
210
223
|
klass.create_method(
|
211
224
|
"build_#{association_name}",
|
@@ -111,7 +111,7 @@ module Tapioca
|
|
111
111
|
sig { params(mod: RBI::Scope, name: String).void }
|
112
112
|
def create_fixture_method(mod, name)
|
113
113
|
return_type = return_type_for_fixture(name)
|
114
|
-
mod
|
114
|
+
mod.create_method(name) do |node|
|
115
115
|
node.add_opt_param("fixture_name", "nil")
|
116
116
|
node.add_rest_param("other_fixtures")
|
117
117
|
|
@@ -155,6 +155,25 @@ module Tapioca
|
|
155
155
|
|
156
156
|
ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
|
157
157
|
|
158
|
+
# From ActiveRecord::ConnectionAdapter::Quoting#quote, minus nil
|
159
|
+
ID_TYPES = T.let(
|
160
|
+
[
|
161
|
+
"String",
|
162
|
+
"Symbol",
|
163
|
+
"::ActiveSupport::Multibyte::Chars",
|
164
|
+
"T::Boolean",
|
165
|
+
"BigDecimal",
|
166
|
+
"Numeric",
|
167
|
+
"::ActiveRecord::Type::Binary::Data",
|
168
|
+
"::ActiveRecord::Type::Time::Value",
|
169
|
+
"Date",
|
170
|
+
"Time",
|
171
|
+
"::ActiveSupport::Duration",
|
172
|
+
"T::Class[T.anything]",
|
173
|
+
].to_set.freeze,
|
174
|
+
T::Set[String],
|
175
|
+
)
|
176
|
+
|
158
177
|
sig { override.void }
|
159
178
|
def decorate
|
160
179
|
create_classes_and_includes
|
@@ -220,7 +239,7 @@ module Tapioca
|
|
220
239
|
[:find_or_create_by, :find_or_create_by!, :find_or_initialize_by, :create_or_find_by, :create_or_find_by!],
|
221
240
|
T::Array[Symbol],
|
222
241
|
)
|
223
|
-
BUILDER_METHODS = T.let([:new, :
|
242
|
+
BUILDER_METHODS = T.let([:new, :create, :create!, :build], T::Array[Symbol])
|
224
243
|
TO_ARRAY_METHODS = T.let([:to_ary, :to_a], T::Array[Symbol])
|
225
244
|
|
226
245
|
private
|
@@ -663,58 +682,43 @@ module Tapioca
|
|
663
682
|
return_type: "T::Boolean",
|
664
683
|
)
|
665
684
|
when :find
|
666
|
-
|
667
|
-
id_types = [
|
668
|
-
"String",
|
669
|
-
"Symbol",
|
670
|
-
"::ActiveSupport::Multibyte::Chars",
|
671
|
-
"T::Boolean",
|
672
|
-
"BigDecimal",
|
673
|
-
"Numeric",
|
674
|
-
"::ActiveRecord::Type::Binary::Data",
|
675
|
-
"::ActiveRecord::Type::Time::Value",
|
676
|
-
"Date",
|
677
|
-
"Time",
|
678
|
-
"::ActiveSupport::Duration",
|
679
|
-
"T::Class[T.anything]",
|
680
|
-
].to_set
|
685
|
+
id_types = ID_TYPES
|
681
686
|
|
682
687
|
if constant.table_exists?
|
683
688
|
primary_key_type = constant.type_for_attribute(constant.primary_key)
|
684
689
|
type = Tapioca::Dsl::Helpers::ActiveModelTypeHelper.type_for(primary_key_type)
|
685
690
|
type = RBIHelper.as_non_nilable_type(type)
|
686
|
-
|
691
|
+
|
692
|
+
id_types = ID_TYPES.union([type]) if type != "T.untyped"
|
687
693
|
end
|
688
694
|
|
689
695
|
id_types = "T.any(#{id_types.to_a.join(", ")})"
|
696
|
+
if constant.try(:composite_primary_key?)
|
697
|
+
id_types = "T::Array[#{id_types}]"
|
698
|
+
end
|
690
699
|
|
691
|
-
array_type =
|
692
|
-
|
693
|
-
|
694
|
-
"
|
700
|
+
array_type = "T::Array[#{id_types}]"
|
701
|
+
|
702
|
+
common_relation_methods_module.create_method("find") do |method|
|
703
|
+
method.add_opt_param("args", "nil")
|
704
|
+
method.add_block_param("block")
|
705
|
+
|
706
|
+
method.add_sig do |sig|
|
707
|
+
sig.add_param("args", id_types)
|
708
|
+
sig.return_type = constant_name
|
709
|
+
end
|
710
|
+
|
711
|
+
method.add_sig do |sig|
|
712
|
+
sig.add_param("args", array_type)
|
713
|
+
sig.return_type = "T::Enumerable[#{constant_name}]"
|
714
|
+
end
|
715
|
+
|
716
|
+
method.add_sig do |sig|
|
717
|
+
sig.add_param("args", "NilClass")
|
718
|
+
sig.add_param("block", "T.proc.params(object: #{constant_name}).void")
|
719
|
+
sig.return_type = as_nilable_type(constant_name)
|
720
|
+
end
|
695
721
|
end
|
696
|
-
sigs = [
|
697
|
-
common_relation_methods_module.create_sig(
|
698
|
-
parameters: { args: id_types },
|
699
|
-
return_type: constant_name,
|
700
|
-
),
|
701
|
-
common_relation_methods_module.create_sig(
|
702
|
-
parameters: { args: array_type },
|
703
|
-
return_type: "T::Enumerable[#{constant_name}]",
|
704
|
-
),
|
705
|
-
common_relation_methods_module.create_sig(
|
706
|
-
parameters: {
|
707
|
-
args: "NilClass",
|
708
|
-
block: "T.proc.params(object: #{constant_name}).void",
|
709
|
-
},
|
710
|
-
return_type: as_nilable_type(constant_name),
|
711
|
-
),
|
712
|
-
]
|
713
|
-
common_relation_methods_module.create_method_with_sigs(
|
714
|
-
"find",
|
715
|
-
sigs: sigs,
|
716
|
-
parameters: [RBI::OptParam.new("args", "nil"), RBI::BlockParam.new("block")],
|
717
|
-
)
|
718
722
|
when :find_by
|
719
723
|
create_common_method(
|
720
724
|
"find_by",
|
@@ -747,21 +751,18 @@ module Tapioca
|
|
747
751
|
return_type: constant_name,
|
748
752
|
)
|
749
753
|
when :first, :last, :take
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
sigs: sigs,
|
763
|
-
parameters: [RBI::OptParam.new("limit", "nil")],
|
764
|
-
)
|
754
|
+
common_relation_methods_module.create_method(method_name.to_s) do |method|
|
755
|
+
method.add_opt_param("limit", "nil")
|
756
|
+
|
757
|
+
method.add_sig do |sig|
|
758
|
+
sig.return_type = as_nilable_type(constant_name)
|
759
|
+
end
|
760
|
+
|
761
|
+
method.add_sig do |sig|
|
762
|
+
sig.add_param("limit", "Integer")
|
763
|
+
sig.return_type = "T::Array[#{constant_name}]"
|
764
|
+
end
|
765
|
+
end
|
765
766
|
when :raise_record_not_found_exception!
|
766
767
|
# skip
|
767
768
|
else
|
@@ -821,24 +822,21 @@ module Tapioca
|
|
821
822
|
return_type: "T.any(Integer, Float, BigDecimal)",
|
822
823
|
)
|
823
824
|
when :count
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
RBI::BlockParam.new("block"),
|
840
|
-
],
|
841
|
-
)
|
825
|
+
common_relation_methods_module.create_method(method_name.to_s) do |method|
|
826
|
+
method.add_opt_param("column_name", "nil")
|
827
|
+
method.add_block_param("block")
|
828
|
+
|
829
|
+
method.add_sig do |sig|
|
830
|
+
sig.add_param("column_name", "T.nilable(T.any(String, Symbol))")
|
831
|
+
sig.return_type = "Integer"
|
832
|
+
end
|
833
|
+
|
834
|
+
method.add_sig do |sig|
|
835
|
+
sig.add_param("column_name", "NilClass")
|
836
|
+
sig.add_param("block", "T.proc.params(object: #{constant_name}).void")
|
837
|
+
sig.return_type = "Integer"
|
838
|
+
end
|
839
|
+
end
|
842
840
|
when :ids
|
843
841
|
create_common_method("ids", return_type: "Array")
|
844
842
|
when :pick, :pluck
|
@@ -850,29 +848,21 @@ module Tapioca
|
|
850
848
|
return_type: "T.untyped",
|
851
849
|
)
|
852
850
|
when :sum
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
}
|
865
|
-
return_type
|
866
|
-
|
867
|
-
|
868
|
-
common_relation_methods_module.create_method_with_sigs(
|
869
|
-
method_name.to_s,
|
870
|
-
sigs: sigs,
|
871
|
-
parameters: [
|
872
|
-
RBI::OptParam.new("initial_value_or_column", "nil"),
|
873
|
-
RBI::BlockParam.new("block"),
|
874
|
-
],
|
875
|
-
)
|
851
|
+
common_relation_methods_module.create_method(method_name.to_s) do |method|
|
852
|
+
method.add_opt_param("initial_value_or_column", "nil")
|
853
|
+
method.add_block_param("block")
|
854
|
+
|
855
|
+
method.add_sig do |sig|
|
856
|
+
sig.add_param("initial_value_or_column", "T.untyped")
|
857
|
+
sig.return_type = "T.any(Integer, Float, BigDecimal)"
|
858
|
+
end
|
859
|
+
|
860
|
+
method.add_sig(type_params: ["U"]) do |sig|
|
861
|
+
sig.add_param("initial_value_or_column", "T.nilable(T.type_parameter(:U))")
|
862
|
+
sig.add_param("block", "T.proc.params(object: #{constant_name}).returns(T.type_parameter(:U))")
|
863
|
+
sig.return_type = "T.type_parameter(:U)"
|
864
|
+
end
|
865
|
+
end
|
876
866
|
end
|
877
867
|
end
|
878
868
|
|
@@ -880,102 +870,100 @@ module Tapioca
|
|
880
870
|
case method_name
|
881
871
|
when :find_each
|
882
872
|
order = ActiveRecord::Batches.instance_method(:find_each).parameters.include?([:key, :order])
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
)
|
873
|
+
|
874
|
+
common_relation_methods_module.create_method("find_each") do |method|
|
875
|
+
method.add_kw_opt_param("start", "nil")
|
876
|
+
method.add_kw_opt_param("finish", "nil")
|
877
|
+
method.add_kw_opt_param("batch_size", "1000")
|
878
|
+
method.add_kw_opt_param("error_on_ignore", "nil")
|
879
|
+
method.add_kw_opt_param("order", ":asc") if order
|
880
|
+
method.add_block_param("block")
|
881
|
+
|
882
|
+
method.add_sig do |sig|
|
883
|
+
sig.add_param("start", "T.untyped")
|
884
|
+
sig.add_param("finish", "T.untyped")
|
885
|
+
sig.add_param("batch_size", "Integer")
|
886
|
+
sig.add_param("error_on_ignore", "T.untyped")
|
887
|
+
sig.add_param("order", "Symbol") if order
|
888
|
+
sig.add_param("block", "T.proc.params(object: #{constant_name}).void")
|
889
|
+
sig.return_type = "void"
|
890
|
+
end
|
891
|
+
|
892
|
+
method.add_sig do |sig|
|
893
|
+
sig.add_param("start", "T.untyped")
|
894
|
+
sig.add_param("finish", "T.untyped")
|
895
|
+
sig.add_param("batch_size", "Integer")
|
896
|
+
sig.add_param("error_on_ignore", "T.untyped")
|
897
|
+
sig.add_param("order", "Symbol") if order
|
898
|
+
sig.return_type = "T::Enumerator[#{constant_name}]"
|
899
|
+
end
|
900
|
+
end
|
912
901
|
when :find_in_batches
|
913
902
|
order = ActiveRecord::Batches.instance_method(:find_in_batches).parameters.include?([:key, :order])
|
914
|
-
|
915
|
-
start
|
916
|
-
finish
|
917
|
-
batch_size
|
918
|
-
error_on_ignore
|
919
|
-
order
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
],
|
942
|
-
)
|
903
|
+
common_relation_methods_module.create_method("find_in_batches") do |method|
|
904
|
+
method.add_kw_opt_param("start", "nil")
|
905
|
+
method.add_kw_opt_param("finish", "nil")
|
906
|
+
method.add_kw_opt_param("batch_size", "1000")
|
907
|
+
method.add_kw_opt_param("error_on_ignore", "nil")
|
908
|
+
method.add_kw_opt_param("order", ":asc") if order
|
909
|
+
method.add_block_param("block")
|
910
|
+
|
911
|
+
method.add_sig do |sig|
|
912
|
+
sig.add_param("start", "T.untyped")
|
913
|
+
sig.add_param("finish", "T.untyped")
|
914
|
+
sig.add_param("batch_size", "Integer")
|
915
|
+
sig.add_param("error_on_ignore", "T.untyped")
|
916
|
+
sig.add_param("order", "Symbol") if order
|
917
|
+
sig.add_param("block", "T.proc.params(object: T::Array[#{constant_name}]).void")
|
918
|
+
sig.return_type = "void"
|
919
|
+
end
|
920
|
+
|
921
|
+
method.add_sig do |sig|
|
922
|
+
sig.add_param("start", "T.untyped")
|
923
|
+
sig.add_param("finish", "T.untyped")
|
924
|
+
sig.add_param("batch_size", "Integer")
|
925
|
+
sig.add_param("error_on_ignore", "T.untyped")
|
926
|
+
sig.add_param("order", "Symbol") if order
|
927
|
+
sig.return_type = "T::Enumerator[T::Enumerator[#{constant_name}]]"
|
928
|
+
end
|
929
|
+
end
|
943
930
|
when :in_batches
|
944
931
|
order = ActiveRecord::Batches.instance_method(:in_batches).parameters.include?([:key, :order])
|
945
932
|
use_ranges = ActiveRecord::Batches.instance_method(:in_batches).parameters.include?([:key, :use_ranges])
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
933
|
+
|
934
|
+
common_relation_methods_module.create_method("in_batches") do |method|
|
935
|
+
method.add_kw_opt_param("of", "1000")
|
936
|
+
method.add_kw_opt_param("start", "nil")
|
937
|
+
method.add_kw_opt_param("finish", "nil")
|
938
|
+
method.add_kw_opt_param("load", "false")
|
939
|
+
method.add_kw_opt_param("error_on_ignore", "nil")
|
940
|
+
method.add_kw_opt_param("order", ":asc") if order
|
941
|
+
method.add_kw_opt_param("use_ranges", "nil") if use_ranges
|
942
|
+
method.add_block_param("block")
|
943
|
+
|
944
|
+
method.add_sig do |sig|
|
945
|
+
sig.add_param("of", "Integer")
|
946
|
+
sig.add_param("start", "T.untyped")
|
947
|
+
sig.add_param("finish", "T.untyped")
|
948
|
+
sig.add_param("load", "T.untyped")
|
949
|
+
sig.add_param("error_on_ignore", "T.untyped")
|
950
|
+
sig.add_param("order", "Symbol") if order
|
951
|
+
sig.add_param("use_ranges", "T.untyped") if use_ranges
|
952
|
+
sig.add_param("block", "T.proc.params(object: #{RelationClassName}).void")
|
953
|
+
sig.return_type = "void"
|
954
|
+
end
|
955
|
+
|
956
|
+
method.add_sig do |sig|
|
957
|
+
sig.add_param("of", "Integer")
|
958
|
+
sig.add_param("start", "T.untyped")
|
959
|
+
sig.add_param("finish", "T.untyped")
|
960
|
+
sig.add_param("load", "T.untyped")
|
961
|
+
sig.add_param("error_on_ignore", "T.untyped")
|
962
|
+
sig.add_param("order", "Symbol") if order
|
963
|
+
sig.add_param("use_ranges", "T.untyped") if use_ranges
|
964
|
+
sig.return_type = "::ActiveRecord::Batches::BatchEnumerator"
|
965
|
+
end
|
966
|
+
end
|
979
967
|
end
|
980
968
|
end
|
981
969
|
|
@@ -991,26 +979,50 @@ module Tapioca
|
|
991
979
|
end
|
992
980
|
|
993
981
|
FIND_OR_CREATE_METHODS.each do |method_name|
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
982
|
+
common_relation_methods_module.create_method(method_name.to_s) do |method|
|
983
|
+
method.add_param("attributes")
|
984
|
+
method.add_block_param("block")
|
985
|
+
|
986
|
+
# `T.untyped` matches `T::Array[T.untyped]` so the array signature
|
987
|
+
# must be defined first for Sorbet to pick it, if valid.
|
988
|
+
method.add_sig do |sig|
|
989
|
+
sig.add_param("attributes", "T::Array[T.untyped]")
|
990
|
+
sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
|
991
|
+
sig.return_type = "T::Array[#{constant_name}]"
|
992
|
+
end
|
993
|
+
|
994
|
+
method.add_sig do |sig|
|
995
|
+
sig.add_param("attributes", "T.untyped")
|
996
|
+
sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
|
997
|
+
sig.return_type = constant_name
|
998
|
+
end
|
999
|
+
end
|
1003
1000
|
end
|
1004
1001
|
|
1005
1002
|
BUILDER_METHODS.each do |method_name|
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1003
|
+
common_relation_methods_module.create_method(method_name.to_s) do |method|
|
1004
|
+
method.add_opt_param("attributes", "nil")
|
1005
|
+
method.add_block_param("block")
|
1006
|
+
|
1007
|
+
method.add_sig do |sig|
|
1008
|
+
sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
|
1009
|
+
sig.return_type = constant_name
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
# `T.untyped` matches `T::Array[T.untyped]` so the array signature
|
1013
|
+
# must be defined first for Sorbet to pick it, if valid.
|
1014
|
+
method.add_sig do |sig|
|
1015
|
+
sig.add_param("attributes", "T::Array[T.untyped]")
|
1016
|
+
sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
|
1017
|
+
sig.return_type = "T::Array[#{constant_name}]"
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
method.add_sig do |sig|
|
1021
|
+
sig.add_param("attributes", "T.untyped")
|
1022
|
+
sig.add_param("block", "T.nilable(T.proc.params(object: #{constant_name}).void)")
|
1023
|
+
sig.return_type = constant_name
|
1024
|
+
end
|
1025
|
+
end
|
1014
1026
|
end
|
1015
1027
|
end
|
1016
1028
|
|
@@ -66,19 +66,18 @@ module Tapioca
|
|
66
66
|
|
67
67
|
sig { override.returns(T::Enumerable[Module]) }
|
68
68
|
def gather_constants
|
69
|
-
# Find all Modules that are:
|
70
69
|
all_modules.select do |mod|
|
71
|
-
#
|
72
|
-
name_of(mod) &&
|
73
|
-
# not singleton classes
|
70
|
+
name_of(mod) && # i.e. not anonymous
|
74
71
|
!mod.singleton_class? &&
|
75
|
-
|
76
|
-
mod
|
77
|
-
# have dependencies (i.e. include another concern)
|
78
|
-
!dependencies_of(mod).empty?
|
72
|
+
ActiveSupport::Concern > mod.singleton_class &&
|
73
|
+
has_dependencies?(mod)
|
79
74
|
end
|
80
75
|
end
|
81
76
|
|
77
|
+
# Returns true when `mod` includes other concerns
|
78
|
+
sig { params(mod: Module).returns(T::Boolean) }
|
79
|
+
def has_dependencies?(mod) = dependencies_of(mod).any?
|
80
|
+
|
82
81
|
sig { params(concern: Module).returns(T::Array[Module]) }
|
83
82
|
def dependencies_of(concern)
|
84
83
|
concern.instance_variable_get(:@_dependencies) || []
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
return unless defined?(Time.current) && defined?(ActiveSupport::TimeWithZone)
|
5
|
+
|
6
|
+
module Tapioca
|
7
|
+
module Dsl
|
8
|
+
module Compilers
|
9
|
+
# `Tapioca::Dsl::Compilers::ActiveSupportTimeExt` generates an RBI file for the `Time#current` method
|
10
|
+
# defined by [Active Support's Time extensions](https://api.rubyonrails.org/classes/Time.html).
|
11
|
+
#
|
12
|
+
# If `Time.zone` or `config.time_zone` are set, then the `Time.current` method will be defined as returning
|
13
|
+
# an instance of `ActiveSupport::TimeWithZone`, otherwise it will return an instance of `Time`.
|
14
|
+
#
|
15
|
+
# For an application that is configured with:
|
16
|
+
# ```ruby
|
17
|
+
# config.time_zone = "UTC"
|
18
|
+
# ```
|
19
|
+
# this compiler will produce the following RBI file:
|
20
|
+
# ```rbi
|
21
|
+
# class Time
|
22
|
+
# class << self
|
23
|
+
# sig { returns(::ActiveSupport::TimeWithZone) }
|
24
|
+
# def current; end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
# ```
|
28
|
+
# whereas if `Time.zone` and `config.time_zone` are not set, it will produce:
|
29
|
+
# ```rbi
|
30
|
+
# class Time
|
31
|
+
# class << self
|
32
|
+
# sig { returns(::Time) }
|
33
|
+
# def current; end
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
# ```
|
37
|
+
class ActiveSupportTimeExt < Compiler
|
38
|
+
extend T::Sig
|
39
|
+
|
40
|
+
ConstantType = type_member { { fixed: T.class_of(::Time) } }
|
41
|
+
|
42
|
+
sig { override.void }
|
43
|
+
def decorate
|
44
|
+
return unless constant.respond_to?(:zone)
|
45
|
+
|
46
|
+
root.create_path(constant) do |mod|
|
47
|
+
return_type = if ::Time.zone
|
48
|
+
"::ActiveSupport::TimeWithZone"
|
49
|
+
else
|
50
|
+
"::Time"
|
51
|
+
end
|
52
|
+
|
53
|
+
mod.create_method("current", return_type: return_type, class_method: true)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class << self
|
58
|
+
extend T::Sig
|
59
|
+
|
60
|
+
sig { override.returns(T::Enumerable[Module]) }
|
61
|
+
def gather_constants
|
62
|
+
[::Time]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -80,7 +80,7 @@ module Tapioca
|
|
80
80
|
|
81
81
|
sig { override.returns(T::Enumerable[Module]) }
|
82
82
|
def gather_constants
|
83
|
-
all_classes.select { |c|
|
83
|
+
all_classes.select { |c| GraphQL::Schema::Mutation > c && GraphQL::Schema::RelayClassicMutation != c }
|
84
84
|
end
|
85
85
|
end
|
86
86
|
end
|
@@ -100,7 +100,7 @@ module Tapioca
|
|
100
100
|
sig { override.returns(T::Enumerable[Module]) }
|
101
101
|
def gather_constants
|
102
102
|
descendants_of(::ActiveRecord::Base).select do |klass|
|
103
|
-
|
103
|
+
::IdentityCache::WithoutPrimaryIndex > klass
|
104
104
|
end
|
105
105
|
end
|
106
106
|
end
|
@@ -159,9 +159,7 @@ module Tapioca
|
|
159
159
|
def gather_constants
|
160
160
|
marker = Google::Protobuf::MessageExts::ClassMethods
|
161
161
|
|
162
|
-
enum_modules = ObjectSpace.each_object(Google::Protobuf::EnumDescriptor).map
|
163
|
-
T.cast(desc, Google::Protobuf::EnumDescriptor).enummodule
|
164
|
-
end
|
162
|
+
enum_modules = ObjectSpace.each_object(Google::Protobuf::EnumDescriptor).map(&:enummodule)
|
165
163
|
|
166
164
|
results = if Google::Protobuf.const_defined?(:AbstractMessage)
|
167
165
|
abstract_message_const = ::Google::Protobuf.const_get(:AbstractMessage)
|
@@ -86,8 +86,9 @@ module Tapioca
|
|
86
86
|
def gather_constants
|
87
87
|
all_modules.select do |c|
|
88
88
|
name_of(c) &&
|
89
|
-
|
90
|
-
|
89
|
+
::SmartProperties > c &&
|
90
|
+
::SmartProperties::Validations::Ancestor != c &&
|
91
|
+
::SmartProperties::ClassMethods === c
|
91
92
|
end
|
92
93
|
end
|
93
94
|
end
|
@@ -159,7 +159,7 @@ module Tapioca
|
|
159
159
|
|
160
160
|
sig { override.returns(T::Enumerable[Module]) }
|
161
161
|
def gather_constants
|
162
|
-
all_classes.select { |mod|
|
162
|
+
all_classes.select { |mod| ::StateMachines::InstanceMethods > mod }
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
@@ -231,12 +231,12 @@ module Tapioca
|
|
231
231
|
instance_module.create_method(
|
232
232
|
attribute,
|
233
233
|
return_type: state_type,
|
234
|
-
)
|
234
|
+
) if ::StateMachines::HelperModule === machine.owner_class.instance_method(attribute).owner
|
235
235
|
instance_module.create_method(
|
236
236
|
"#{attribute}=",
|
237
237
|
parameters: [create_param("value", type: state_type)],
|
238
238
|
return_type: state_type,
|
239
|
-
)
|
239
|
+
) if ::StateMachines::HelperModule === machine.owner_class.instance_method("#{attribute}=").owner
|
240
240
|
end
|
241
241
|
|
242
242
|
sig { params(instance_module: RBI::Module, machine: ::StateMachines::Machine).void }
|
@@ -106,19 +106,28 @@ module Tapioca
|
|
106
106
|
routes_reloader = Rails.application.routes_reloader
|
107
107
|
routes_reloader.execute_unless_loaded if routes_reloader&.respond_to?(:execute_unless_loaded)
|
108
108
|
|
109
|
-
|
110
|
-
|
109
|
+
url_helpers_module = Rails.application.routes.named_routes.url_helpers_module
|
110
|
+
path_helpers_module = Rails.application.routes.named_routes.path_helpers_module
|
111
|
+
|
112
|
+
Object.const_set(:GeneratedUrlHelpersModule, url_helpers_module)
|
113
|
+
Object.const_set(:GeneratedPathHelpersModule, path_helpers_module)
|
111
114
|
|
112
115
|
constants = all_modules.select do |mod|
|
113
116
|
next unless name_of(mod)
|
114
117
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
118
|
+
# Fast-path to quickly disqualify most cases
|
119
|
+
next false unless url_helpers_module > mod || # rubocop:disable Style/InvertibleUnlessCondition
|
120
|
+
path_helpers_module > mod ||
|
121
|
+
url_helpers_module > mod.singleton_class ||
|
122
|
+
path_helpers_module > mod.singleton_class
|
123
|
+
|
124
|
+
includes_helper?(mod, url_helpers_module) ||
|
125
|
+
includes_helper?(mod, path_helpers_module) ||
|
126
|
+
includes_helper?(mod.singleton_class, url_helpers_module) ||
|
127
|
+
includes_helper?(mod.singleton_class, path_helpers_module)
|
119
128
|
end
|
120
129
|
|
121
|
-
constants.concat(NON_DISCOVERABLE_INCLUDERS)
|
130
|
+
constants.concat(NON_DISCOVERABLE_INCLUDERS).push(GeneratedUrlHelpersModule, GeneratedPathHelpersModule)
|
122
131
|
end
|
123
132
|
|
124
133
|
sig { returns(T::Array[Module]) }
|
@@ -134,17 +143,20 @@ module Tapioca
|
|
134
143
|
end.freeze
|
135
144
|
end
|
136
145
|
|
146
|
+
# Returns `true` if `mod` "directly" includes `helper`.
|
147
|
+
# For classes, this method will return false if the `helper` is included only by a superclass
|
137
148
|
sig { params(mod: Module, helper: Module).returns(T::Boolean) }
|
138
149
|
private def includes_helper?(mod, helper)
|
139
|
-
|
150
|
+
ancestors = ancestors_of(mod)
|
140
151
|
|
141
|
-
if Class === mod
|
142
|
-
|
143
|
-
|
152
|
+
own_ancestors = if Class === mod && (superclass = superclass_of(mod))
|
153
|
+
# These ancestors are unique to `mod`, and exclude those in common with `superclass`.
|
154
|
+
ancestors.take(ancestors.count - ancestors_of(superclass).size)
|
155
|
+
else
|
156
|
+
ancestors
|
144
157
|
end
|
145
158
|
|
146
|
-
|
147
|
-
ancestors.any? { |ancestor| helper == ancestor }
|
159
|
+
own_ancestors.include?(helper)
|
148
160
|
end
|
149
161
|
end
|
150
162
|
|
data/lib/tapioca/loaders/dsl.rb
CHANGED
@@ -63,10 +63,17 @@ module Tapioca
|
|
63
63
|
def load_dsl_compilers
|
64
64
|
say("Loading DSL compiler classes... ")
|
65
65
|
|
66
|
+
# Load all built-in compilers
|
67
|
+
Dir.glob("#{Tapioca::LIB_ROOT_DIR}/tapioca/dsl/compilers/*.rb").each do |compiler|
|
68
|
+
require File.expand_path(compiler)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Load all custom compilers exported from gems
|
66
72
|
::Gem.find_files("tapioca/dsl/compilers/*.rb").each do |compiler|
|
67
73
|
require File.expand_path(compiler)
|
68
74
|
end
|
69
75
|
|
76
|
+
# Load all custom compilers from the project
|
70
77
|
Dir.glob([
|
71
78
|
"#{@tapioca_path}/generators/**/*.rb", # TODO: Here for backcompat, remove later
|
72
79
|
"#{@tapioca_path}/compilers/**/*.rb",
|
@@ -47,12 +47,23 @@ module Tapioca
|
|
47
47
|
).void
|
48
48
|
end
|
49
49
|
def load_rails_application(environment_load: false, eager_load: false, app_root: ".", halt_upon_load_error: true)
|
50
|
-
return unless File.exist?("
|
50
|
+
return unless File.exist?(File.expand_path("config/application.rb", app_root))
|
51
51
|
|
52
|
-
if environment_load
|
53
|
-
|
52
|
+
load_path = if environment_load
|
53
|
+
"config/environment"
|
54
54
|
else
|
55
|
-
|
55
|
+
"config/application"
|
56
|
+
end
|
57
|
+
|
58
|
+
require File.expand_path(load_path, app_root)
|
59
|
+
|
60
|
+
unless defined?(Rails)
|
61
|
+
say(
|
62
|
+
"\nTried to load the app from `#{load_path}` as a Rails application " \
|
63
|
+
"but the `Rails` constant wasn't defined after loading the file.",
|
64
|
+
:yellow,
|
65
|
+
)
|
66
|
+
return
|
56
67
|
end
|
57
68
|
|
58
69
|
eager_load_rails_app if eager_load
|
@@ -80,65 +80,38 @@ module RBI
|
|
80
80
|
params(
|
81
81
|
name: String,
|
82
82
|
parameters: T::Array[TypedParam],
|
83
|
-
return_type: String,
|
83
|
+
return_type: T.nilable(String),
|
84
84
|
class_method: T::Boolean,
|
85
85
|
visibility: RBI::Visibility,
|
86
86
|
comments: T::Array[RBI::Comment],
|
87
|
+
block: T.nilable(T.proc.params(node: RBI::Method).void),
|
87
88
|
).void
|
88
89
|
end
|
89
|
-
def create_method(name, parameters: [], return_type:
|
90
|
-
comments: [])
|
91
|
-
sig_params = parameters.to_h { |param| [param.param.name, param.type] }
|
92
|
-
sig = create_sig(parameters: sig_params, return_type: return_type)
|
93
|
-
create_method_with_sigs(
|
94
|
-
name,
|
95
|
-
sigs: [sig],
|
96
|
-
parameters: parameters.map(&:param),
|
97
|
-
class_method: class_method,
|
98
|
-
visibility: visibility,
|
99
|
-
comments: comments,
|
100
|
-
)
|
101
|
-
end
|
102
|
-
|
103
|
-
sig do
|
104
|
-
params(
|
105
|
-
name: String,
|
106
|
-
sigs: T::Array[RBI::Sig],
|
107
|
-
parameters: T::Array[RBI::Param],
|
108
|
-
class_method: T::Boolean,
|
109
|
-
visibility: RBI::Visibility,
|
110
|
-
comments: T::Array[RBI::Comment],
|
111
|
-
).void
|
112
|
-
end
|
113
|
-
def create_method_with_sigs(name, sigs:, parameters: [], class_method: false, visibility: RBI::Public.new,
|
114
|
-
comments: [])
|
90
|
+
def create_method(name, parameters: [], return_type: nil, class_method: false, visibility: RBI::Public.new,
|
91
|
+
comments: [], &block)
|
115
92
|
return unless Tapioca::RBIHelper.valid_method_name?(name)
|
116
93
|
|
94
|
+
sigs = []
|
95
|
+
|
96
|
+
if !block || !parameters.empty? || return_type
|
97
|
+
# If there is no block, and the params and return type have not been supplied, then
|
98
|
+
# we create a single signature with the given parameters and return type
|
99
|
+
params = parameters.map { |param| RBI::SigParam.new(param.param.name.to_s, param.type) }
|
100
|
+
sigs << RBI::Sig.new(params: params, return_type: return_type || "T.untyped")
|
101
|
+
end
|
102
|
+
|
117
103
|
method = RBI::Method.new(
|
118
104
|
name,
|
119
105
|
sigs: sigs,
|
120
|
-
params: parameters,
|
106
|
+
params: parameters.map(&:param),
|
121
107
|
is_singleton: class_method,
|
122
108
|
visibility: visibility,
|
123
109
|
comments: comments,
|
110
|
+
&block
|
124
111
|
)
|
125
112
|
self << method
|
126
113
|
end
|
127
114
|
|
128
|
-
sig do
|
129
|
-
params(
|
130
|
-
parameters: T::Hash[T.any(String, Symbol), String],
|
131
|
-
type_parameters: T::Array[String],
|
132
|
-
return_type: String,
|
133
|
-
).returns(RBI::Sig)
|
134
|
-
end
|
135
|
-
def create_sig(parameters:, type_parameters: [], return_type: "T.untyped")
|
136
|
-
params = parameters.map do |name, type|
|
137
|
-
RBI::SigParam.new(name.to_s, type)
|
138
|
-
end
|
139
|
-
RBI::Sig.new(type_params: type_parameters, params: params, return_type: return_type)
|
140
|
-
end
|
141
|
-
|
142
115
|
private
|
143
116
|
|
144
117
|
sig { returns(T::Hash[String, RBI::Node]) }
|
@@ -166,7 +166,7 @@ module Tapioca
|
|
166
166
|
end
|
167
167
|
def descendants_of(klass)
|
168
168
|
result = ObjectSpace.each_object(klass.singleton_class).reject do |k|
|
169
|
-
|
169
|
+
k.singleton_class? || k == klass
|
170
170
|
end
|
171
171
|
|
172
172
|
T.unsafe(result)
|
data/lib/tapioca/version.rb
CHANGED
data/lib/tapioca.rb
CHANGED
@@ -30,6 +30,7 @@ module Tapioca
|
|
30
30
|
|
31
31
|
class Error < StandardError; end
|
32
32
|
|
33
|
+
LIB_ROOT_DIR = T.let(T.must(__dir__), String)
|
33
34
|
SORBET_DIR = T.let("sorbet", String)
|
34
35
|
SORBET_CONFIG_FILE = T.let("#{SORBET_DIR}/config", String)
|
35
36
|
TAPIOCA_DIR = T.let("#{SORBET_DIR}/tapioca", String)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tapioca
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ufuk Kayserilioglu
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date: 2024-
|
14
|
+
date: 2024-08-06 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -61,7 +61,7 @@ dependencies:
|
|
61
61
|
requirements:
|
62
62
|
- - ">="
|
63
63
|
- !ruby/object:Gem::Version
|
64
|
-
version: 0.1.
|
64
|
+
version: 0.1.14
|
65
65
|
- - "<"
|
66
66
|
- !ruby/object:Gem::Version
|
67
67
|
version: '0.2'
|
@@ -71,7 +71,7 @@ dependencies:
|
|
71
71
|
requirements:
|
72
72
|
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: 0.1.
|
74
|
+
version: 0.1.14
|
75
75
|
- - "<"
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0.2'
|
@@ -186,6 +186,7 @@ files:
|
|
186
186
|
- lib/tapioca/dsl/compilers/active_storage.rb
|
187
187
|
- lib/tapioca/dsl/compilers/active_support_concern.rb
|
188
188
|
- lib/tapioca/dsl/compilers/active_support_current_attributes.rb
|
189
|
+
- lib/tapioca/dsl/compilers/active_support_time_ext.rb
|
189
190
|
- lib/tapioca/dsl/compilers/config.rb
|
190
191
|
- lib/tapioca/dsl/compilers/frozen_record.rb
|
191
192
|
- lib/tapioca/dsl/compilers/graphql_input_object.rb
|
@@ -289,7 +290,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
289
290
|
- !ruby/object:Gem::Version
|
290
291
|
version: '0'
|
291
292
|
requirements: []
|
292
|
-
rubygems_version: 3.5.
|
293
|
+
rubygems_version: 3.5.16
|
293
294
|
signing_key:
|
294
295
|
specification_version: 4
|
295
296
|
summary: A Ruby Interface file generator for gems, core types and the Ruby standard
|