sorbet-rails 0.6.2 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sorbet-rails/active_record_rbi_formatter.rb +295 -0
- data/lib/sorbet-rails/config.rb +0 -1
- data/lib/sorbet-rails/custom_types/boolean_string.rb +10 -0
- data/lib/sorbet-rails/custom_types/integer_string.rb +10 -0
- data/lib/sorbet-rails/dependent_gem_rbis/activerecord.rbi +11 -0
- data/lib/sorbet-rails/deprecation.rb +5 -0
- data/lib/sorbet-rails/model_plugins/active_record_assoc.rb +27 -6
- data/lib/sorbet-rails/model_plugins/active_record_attribute.rb +20 -8
- data/lib/sorbet-rails/model_plugins/base.rb +9 -0
- data/lib/sorbet-rails/model_plugins/enumerable_collections.rb +0 -50
- data/lib/sorbet-rails/model_plugins/plugins.rb +0 -3
- data/lib/sorbet-rails/model_rbi_formatter.rb +2 -2
- data/lib/sorbet-rails/model_utils.rb +15 -6
- data/lib/sorbet-rails/rails_mixins/custom_params_methods.rb +11 -0
- data/lib/sorbet-rails/tasks/rails_rbi.rake +20 -4
- data/sorbet-rails.gemspec +2 -2
- data/spec/active_record_rbi_formatter_spec.rb +24 -0
- data/spec/generators/rails-template.rb +88 -1
- data/spec/generators/sorbet_test_cases.rb +146 -42
- data/spec/model_rbi_formatter_spec.rb +1 -1
- data/spec/rails_helper.rb +14 -1
- data/spec/rake_rails_rbi_active_record_spec.rb +21 -0
- data/spec/rake_rails_rbi_models_spec.rb +7 -0
- data/spec/sorbet_spec.rb +12 -1
- data/spec/support/v5.0/Gemfile.lock +8 -8
- data/spec/support/v5.0/app/models/headmaster.rb +8 -0
- data/spec/support/v5.0/app/models/school.rb +2 -0
- data/spec/support/v5.0/app/models/spell.rb +5 -0
- data/spec/support/v5.0/app/models/spell_book.rb +3 -0
- data/spec/support/v5.0/app/models/subject.rb +5 -0
- data/spec/support/v5.0/app/models/wizard.rb +6 -1
- data/spec/support/v5.0/db/migrate/20190620000010_add_subject.rb +8 -0
- data/spec/support/v5.0/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
- data/spec/support/v5.0/db/migrate/20190620000012_add_spell.rb +8 -0
- data/spec/support/v5.0/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
- data/spec/support/v5.0/db/migrate/20190620000014_create_headmasters.rb +9 -0
- data/spec/support/v5.0/db/schema.rb +28 -1
- data/spec/support/v5.0/lib/mythical_rbi_plugin.rb +1 -1
- data/spec/support/v5.0/sorbet_test_cases.rb +146 -42
- data/spec/support/v5.1/Gemfile.lock +8 -8
- data/spec/support/v5.1/app/models/headmaster.rb +8 -0
- data/spec/support/v5.1/app/models/school.rb +2 -0
- data/spec/support/v5.1/app/models/spell.rb +5 -0
- data/spec/support/v5.1/app/models/spell_book.rb +3 -0
- data/spec/support/v5.1/app/models/subject.rb +5 -0
- data/spec/support/v5.1/app/models/wizard.rb +6 -1
- data/spec/support/v5.1/db/migrate/20190620000010_add_subject.rb +8 -0
- data/spec/support/v5.1/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
- data/spec/support/v5.1/db/migrate/20190620000012_add_spell.rb +8 -0
- data/spec/support/v5.1/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
- data/spec/support/v5.1/db/migrate/20190620000014_create_headmasters.rb +9 -0
- data/spec/support/v5.1/db/schema.rb +28 -1
- data/spec/support/v5.1/lib/mythical_rbi_plugin.rb +1 -1
- data/spec/support/v5.1/sorbet_test_cases.rb +146 -42
- data/spec/support/v5.2/Gemfile +1 -1
- data/spec/support/v5.2/Gemfile.lock +9 -9
- data/spec/support/v5.2/app/models/headmaster.rb +8 -0
- data/spec/support/v5.2/app/models/school.rb +2 -0
- data/spec/support/v5.2/app/models/spell.rb +5 -0
- data/spec/support/v5.2/app/models/spell_book.rb +3 -0
- data/spec/support/v5.2/app/models/subject.rb +5 -0
- data/spec/support/v5.2/app/models/wizard.rb +5 -0
- data/spec/support/v5.2/config/puma.rb +3 -0
- data/spec/support/v5.2/db/migrate/20190620000010_add_subject.rb +8 -0
- data/spec/support/v5.2/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
- data/spec/support/v5.2/db/migrate/20190620000012_add_spell.rb +8 -0
- data/spec/support/v5.2/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
- data/spec/support/v5.2/db/migrate/20190620000014_create_headmasters.rb +9 -0
- data/spec/support/v5.2/db/schema.rb +28 -1
- data/spec/support/v5.2/lib/mythical_rbi_plugin.rb +1 -1
- data/spec/support/v5.2/sorbet_test_cases.rb +146 -42
- data/spec/support/v6.0/Gemfile.lock +8 -8
- data/spec/support/v6.0/app/models/headmaster.rb +8 -0
- data/spec/support/v6.0/app/models/school.rb +2 -0
- data/spec/support/v6.0/app/models/spell.rb +5 -0
- data/spec/support/v6.0/app/models/spell_book.rb +3 -0
- data/spec/support/v6.0/app/models/subject.rb +5 -0
- data/spec/support/v6.0/app/models/wizard.rb +6 -1
- data/spec/support/v6.0/db/migrate/20190620000010_add_subject.rb +8 -0
- data/spec/support/v6.0/db/migrate/20190620000011_add_subjects_wizards.rb +8 -0
- data/spec/support/v6.0/db/migrate/20190620000012_add_spell.rb +8 -0
- data/spec/support/v6.0/db/migrate/20190620000013_add_spells_spell_books.rb +8 -0
- data/spec/support/v6.0/db/migrate/20190620000014_create_headmasters.rb +9 -0
- data/spec/support/v6.0/db/schema.rb +28 -1
- data/spec/support/v6.0/lib/mythical_rbi_plugin.rb +1 -1
- data/spec/support/v6.0/sorbet_test_cases.rb +146 -42
- data/spec/test_data/v5.0/expected_active_record_base.rbi +113 -0
- data/spec/test_data/v5.0/expected_active_record_relation.rbi +199 -0
- data/spec/test_data/v5.0/expected_habtm_subjects.rbi +660 -0
- data/spec/test_data/v5.0/expected_habtm_wizards.rbi +660 -0
- data/spec/test_data/v5.0/expected_headmaster.rbi +452 -0
- data/spec/test_data/v5.0/expected_internal_metadata.rbi +0 -217
- data/spec/test_data/v5.0/expected_potion.rbi +0 -217
- data/spec/test_data/v5.0/expected_robe.rbi +0 -217
- data/spec/test_data/v5.0/expected_schema_migration.rbi +0 -217
- data/spec/test_data/v5.0/expected_school.rbi +11 -217
- data/spec/test_data/v5.0/expected_spell.rbi +440 -0
- data/spec/test_data/v5.0/expected_spell/habtm_spell_books.rbi +443 -0
- data/spec/test_data/v5.0/expected_spell_book.rbi +14 -222
- data/spec/test_data/v5.0/expected_spell_book/habtm_spell_books.rbi +637 -0
- data/spec/test_data/v5.0/expected_spell_book/habtm_spells.rbi +443 -0
- data/spec/test_data/v5.0/expected_squib.rbi +14 -219
- data/spec/test_data/v5.0/expected_subject.rbi +440 -0
- data/spec/test_data/v5.0/expected_subject/habtm_wizards.rbi +443 -0
- data/spec/test_data/v5.0/expected_wand.rbi +4 -221
- data/spec/test_data/v5.0/expected_wizard.rbi +36 -240
- data/spec/test_data/v5.0/expected_wizard/habtm_subjects.rbi +443 -0
- data/spec/test_data/v5.0/expected_wizard_wo_spellbook.rbi +30 -240
- data/spec/test_data/v5.1/expected_active_record_base.rbi +113 -0
- data/spec/test_data/v5.1/expected_active_record_relation.rbi +178 -0
- data/spec/test_data/v5.1/expected_habtm_subjects.rbi +672 -0
- data/spec/test_data/v5.1/expected_habtm_wizards.rbi +672 -0
- data/spec/test_data/v5.1/expected_headmaster.rbi +464 -0
- data/spec/test_data/v5.1/expected_internal_metadata.rbi +0 -217
- data/spec/test_data/v5.1/expected_potion.rbi +0 -217
- data/spec/test_data/v5.1/expected_robe.rbi +0 -217
- data/spec/test_data/v5.1/expected_schema_migration.rbi +0 -217
- data/spec/test_data/v5.1/expected_school.rbi +11 -217
- data/spec/test_data/v5.1/expected_spell.rbi +452 -0
- data/spec/test_data/v5.1/expected_spell/habtm_spell_books.rbi +455 -0
- data/spec/test_data/v5.1/expected_spell_book.rbi +14 -222
- data/spec/test_data/v5.1/expected_spell_book/habtm_spell_books.rbi +649 -0
- data/spec/test_data/v5.1/expected_spell_book/habtm_spells.rbi +455 -0
- data/spec/test_data/v5.1/expected_squib.rbi +14 -219
- data/spec/test_data/v5.1/expected_subject.rbi +452 -0
- data/spec/test_data/v5.1/expected_subject/habtm_wizards.rbi +455 -0
- data/spec/test_data/v5.1/expected_wand.rbi +4 -221
- data/spec/test_data/v5.1/expected_wizard.rbi +36 -240
- data/spec/test_data/v5.1/expected_wizard/habtm_subjects.rbi +455 -0
- data/spec/test_data/v5.1/expected_wizard_wo_spellbook.rbi +30 -240
- data/spec/test_data/v5.2/expected_active_record_base.rbi +113 -0
- data/spec/test_data/v5.2/expected_active_record_relation.rbi +175 -0
- data/spec/test_data/v5.2/expected_attachment.rbi +0 -217
- data/spec/test_data/v5.2/expected_blob.rbi +3 -217
- data/spec/test_data/v5.2/expected_habtm_subjects.rbi +672 -0
- data/spec/test_data/v5.2/expected_habtm_wizards.rbi +672 -0
- data/spec/test_data/v5.2/expected_headmaster.rbi +464 -0
- data/spec/test_data/v5.2/expected_internal_metadata.rbi +0 -217
- data/spec/test_data/v5.2/expected_potion.rbi +0 -217
- data/spec/test_data/v5.2/expected_robe.rbi +0 -217
- data/spec/test_data/v5.2/expected_schema_migration.rbi +0 -217
- data/spec/test_data/v5.2/expected_school.rbi +11 -217
- data/spec/test_data/v5.2/expected_spell.rbi +452 -0
- data/spec/test_data/v5.2/expected_spell/habtm_spell_books.rbi +455 -0
- data/spec/test_data/v5.2/expected_spell_book.rbi +14 -222
- data/spec/test_data/v5.2/expected_spell_book/habtm_spell_books.rbi +649 -0
- data/spec/test_data/v5.2/expected_spell_book/habtm_spells.rbi +455 -0
- data/spec/test_data/v5.2/expected_squib.rbi +20 -219
- data/spec/test_data/v5.2/expected_subject.rbi +452 -0
- data/spec/test_data/v5.2/expected_subject/habtm_wizards.rbi +455 -0
- data/spec/test_data/v5.2/expected_wand.rbi +4 -221
- data/spec/test_data/v5.2/expected_wizard.rbi +42 -240
- data/spec/test_data/v5.2/expected_wizard/habtm_subjects.rbi +455 -0
- data/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi +36 -240
- data/spec/test_data/v6.0/expected_active_record_base.rbi +113 -0
- data/spec/test_data/v6.0/expected_active_record_relation.rbi +175 -0
- data/spec/test_data/v6.0/expected_attachment.rbi +0 -217
- data/spec/test_data/v6.0/expected_blob.rbi +3 -217
- data/spec/test_data/v6.0/expected_habtm_subjects.rbi +720 -0
- data/spec/test_data/v6.0/expected_habtm_wizards.rbi +720 -0
- data/spec/test_data/v6.0/expected_headmaster.rbi +512 -0
- data/spec/test_data/v6.0/expected_internal_metadata.rbi +0 -217
- data/spec/test_data/v6.0/expected_potion.rbi +0 -217
- data/spec/test_data/v6.0/expected_robe.rbi +0 -217
- data/spec/test_data/v6.0/expected_schema_migration.rbi +0 -217
- data/spec/test_data/v6.0/expected_school.rbi +11 -217
- data/spec/test_data/v6.0/expected_spell.rbi +500 -0
- data/spec/test_data/v6.0/expected_spell/habtm_spell_books.rbi +503 -0
- data/spec/test_data/v6.0/expected_spell_book.rbi +14 -222
- data/spec/test_data/v6.0/expected_spell_book/habtm_spell_books.rbi +697 -0
- data/spec/test_data/v6.0/expected_spell_book/habtm_spells.rbi +503 -0
- data/spec/test_data/v6.0/expected_squib.rbi +20 -219
- data/spec/test_data/v6.0/expected_subject.rbi +500 -0
- data/spec/test_data/v6.0/expected_subject/habtm_wizards.rbi +503 -0
- data/spec/test_data/v6.0/expected_wand.rbi +4 -221
- data/spec/test_data/v6.0/expected_wizard.rbi +42 -240
- data/spec/test_data/v6.0/expected_wizard/habtm_subjects.rbi +503 -0
- data/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi +36 -240
- metadata +169 -14
- data/lib/bundled_rbi/active_record_base.rbi +0 -83
- data/lib/bundled_rbi/active_record_relation.rbi +0 -122
- data/lib/sorbet-rails/model_plugins/active_record_finder_methods.rb +0 -131
- data/spec/support/v5.0/typed-override.yaml +0 -2
- data/spec/support/v5.1/typed-override.yaml +0 -2
- data/spec/support/v5.2/typed-override.yaml +0 -2
- data/spec/support/v6.0/typed-override.yaml +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ade7fadcb2cc5890f8cd5716247f14d7d9b0324029fb13de4f8b902e205a516
|
4
|
+
data.tar.gz: 766dfdd66acea268fe696345ae871bf4b88cd67e2b845dffeb9f218d9a38586d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 91ce6f173680ed297198333b0780c4f4257a7b95d56f33d6f464f67f122c37a6483b87f00392792219ce51724ad5379fea9b7cbf91fc100d439396f828f210be
|
7
|
+
data.tar.gz: ba26ebc1b34724a1eee5cc667add0b843c3ef77994606938e31b2f3fc0a0a88d8a0b7ad39f65194350045166c1eb130cd94951f54c763d82a7efd19dd65ed7a0
|
@@ -0,0 +1,295 @@
|
|
1
|
+
# typed: strict
|
2
|
+
require('parlour')
|
3
|
+
|
4
|
+
class SorbetRails::ActiveRecordRbiFormatter
|
5
|
+
extend T::Sig
|
6
|
+
|
7
|
+
Parameter = ::Parlour::RbiGenerator::Parameter
|
8
|
+
|
9
|
+
sig {returns(String)}
|
10
|
+
def generate_active_record_base_rbi
|
11
|
+
puts "-- Generate sigs for ActiveRecord::Base --"
|
12
|
+
|
13
|
+
parlour = T.let(Parlour::RbiGenerator.new, Parlour::RbiGenerator)
|
14
|
+
|
15
|
+
parlour.root.add_comments([
|
16
|
+
'This is an autogenerated file for Rails\' ActiveRecord.',
|
17
|
+
'Please rerun bundle exec rake rails_rbi:active_record to regenerate.'
|
18
|
+
])
|
19
|
+
|
20
|
+
parlour.root.create_class('ActiveRecord::Base') do |class_rbi|
|
21
|
+
create_elem_specific_query_methods(class_rbi, type: 'T.attached_class', class_method: true)
|
22
|
+
create_general_query_methods(class_rbi, class_method: true)
|
23
|
+
end
|
24
|
+
|
25
|
+
parlour.rbi
|
26
|
+
end
|
27
|
+
|
28
|
+
sig {returns(String)}
|
29
|
+
def generate_active_record_relation_rbi
|
30
|
+
puts "-- Generate sigs for ActiveRecord::Relation --"
|
31
|
+
|
32
|
+
parlour = T.let(Parlour::RbiGenerator.new, Parlour::RbiGenerator)
|
33
|
+
|
34
|
+
parlour.root.add_comments([
|
35
|
+
'This is an autogenerated file for Rails\' ActiveRecord.',
|
36
|
+
'Please rerun bundle exec rake rails_rbi:active_record to regenerate.'
|
37
|
+
])
|
38
|
+
|
39
|
+
parlour.root.create_class('ActiveRecord::Relation') do |class_rbi|
|
40
|
+
class_rbi.create_include("Enumerable")
|
41
|
+
class_rbi.create_constant(
|
42
|
+
"Elem",
|
43
|
+
value: "type_member(fixed: T.untyped)",
|
44
|
+
)
|
45
|
+
|
46
|
+
create_elem_specific_query_methods(class_rbi, type: 'Elem', class_method: false)
|
47
|
+
create_general_query_methods(class_rbi, class_method: false)
|
48
|
+
|
49
|
+
# Many methods that exist on the relation classes also exist on the model class
|
50
|
+
# by delegating to `:all` (e.g. `Model.any?` is really `Model.all.any?`). These
|
51
|
+
# methods (e.g. each, empty?) only exist on the relation classes.
|
52
|
+
class_rbi.create_method(
|
53
|
+
"each",
|
54
|
+
parameters: [
|
55
|
+
Parameter.new("&block", type: "T.proc.params(e: Elem).void")
|
56
|
+
],
|
57
|
+
return_type: "T::Array[Elem]",
|
58
|
+
implementation: true,
|
59
|
+
)
|
60
|
+
class_rbi.create_method(
|
61
|
+
"flatten",
|
62
|
+
parameters: [ Parameter.new("level", type: "T.nilable(Integer)") ],
|
63
|
+
return_type: "T::Array[Elem]",
|
64
|
+
)
|
65
|
+
class_rbi.create_method("to_a", return_type: "T::Array[Elem]")
|
66
|
+
class_rbi.create_method(
|
67
|
+
"map",
|
68
|
+
type_parameters: [:U],
|
69
|
+
parameters: [ Parameter.new("&blk", type: "T.proc.params(arg0: Elem).returns(T.type_parameter(:U))") ],
|
70
|
+
return_type: "T::Array[T.type_parameter(:U)]",
|
71
|
+
)
|
72
|
+
class_rbi.create_method('empty?', return_type: "T::Boolean")
|
73
|
+
end
|
74
|
+
|
75
|
+
parlour.root.create_class("ActiveRecord::AssociationRelation", superclass: "ActiveRecord::Relation") do |class_rbi|
|
76
|
+
class_rbi.create_constant(
|
77
|
+
"Elem",
|
78
|
+
value: "type_member(fixed: T.untyped)",
|
79
|
+
)
|
80
|
+
|
81
|
+
# Ideally we shouldn't need to define these since this class inherits from
|
82
|
+
# ActiveRecord::Relation but the activerecord.rbi that sorbet generates
|
83
|
+
# defines some methods which sorbet finds instead of the methods inherited
|
84
|
+
# by ActiveRecord::Relation. Some of these methods have different arity or
|
85
|
+
# parameters than the ones defined by `create_elem_specific_query_methods` so
|
86
|
+
# we need to match the signatures in that conflicting rbi.
|
87
|
+
build_methods = %w(new build create create!)
|
88
|
+
build_methods.each do |build_method|
|
89
|
+
class_rbi.create_method(
|
90
|
+
build_method,
|
91
|
+
parameters: [
|
92
|
+
Parameter.new("*args", type: "T.untyped"),
|
93
|
+
Parameter.new(
|
94
|
+
"&block",
|
95
|
+
type: "T.nilable(T.proc.params(object: Elem).void)",
|
96
|
+
),
|
97
|
+
],
|
98
|
+
return_type: "Elem",
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
parlour.root.create_class("ActiveRecord::Associations::CollectionProxy", superclass: "ActiveRecord::Relation") do |class_rbi|
|
104
|
+
class_rbi.create_constant(
|
105
|
+
"Elem",
|
106
|
+
value: "type_member(fixed: T.untyped)",
|
107
|
+
)
|
108
|
+
|
109
|
+
# This _should_ work which would let us remove it from the enumerable_collections
|
110
|
+
# plugin but sorbet has a bug with T.any and generics.
|
111
|
+
# See: https://github.com/sorbet/sorbet/issues/2938
|
112
|
+
# push_methods = %w(<< append push concat)
|
113
|
+
# push_methods.each do |push_method|
|
114
|
+
# class_rbi.create_method(
|
115
|
+
# push_method,
|
116
|
+
# parameters: [
|
117
|
+
# Parameter.new("*records", type: "T.any(Elem, T::Array[Elem])"),
|
118
|
+
# ],
|
119
|
+
# return_type: "T.self_type",
|
120
|
+
# )
|
121
|
+
# end
|
122
|
+
|
123
|
+
# Ideally we shouldn't need to define these since this class inherits from
|
124
|
+
# ActiveRecord::Relation but the activerecord.rbi that sorbet generates
|
125
|
+
# defines some methods which sorbet finds instead of the methods inherited
|
126
|
+
# by ActiveRecord::Relation. Some of these methods have different arity or
|
127
|
+
# parameters than the ones defined by `create_elem_specific_query_methods` so
|
128
|
+
# we need to match the signatures in that conflicting rbi.
|
129
|
+
build_methods = %w(new build create create!)
|
130
|
+
build_methods.each do |build_method|
|
131
|
+
class_rbi.create_method(
|
132
|
+
build_method,
|
133
|
+
parameters: [
|
134
|
+
Parameter.new("attributes", type: "T.untyped", default: 'nil'),
|
135
|
+
Parameter.new(
|
136
|
+
"&block",
|
137
|
+
type: "T.nilable(T.proc.params(object: Elem).void)",
|
138
|
+
),
|
139
|
+
],
|
140
|
+
return_type: "Elem",
|
141
|
+
)
|
142
|
+
end
|
143
|
+
|
144
|
+
class_rbi.create_method(
|
145
|
+
"find",
|
146
|
+
parameters: [Parameter.new("*args", type: "T.untyped")],
|
147
|
+
return_type: "Elem",
|
148
|
+
)
|
149
|
+
|
150
|
+
if Rails.version =~ /^5\.0/
|
151
|
+
item_methods = %w(first second third third_to_last second_to_last last)
|
152
|
+
item_methods.each do |item_method|
|
153
|
+
class_rbi.create_method(
|
154
|
+
item_method,
|
155
|
+
parameters: [Parameter.new("*args", type: "T.untyped")],
|
156
|
+
return_type: "T.nilable(Elem)",
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
160
|
+
boolean_methods = %w(any? many?)
|
161
|
+
boolean_methods.each do |boolean_method|
|
162
|
+
class_rbi.create_method(boolean_method, return_type: "T::Boolean")
|
163
|
+
end
|
164
|
+
else
|
165
|
+
class_rbi.create_method(
|
166
|
+
"last",
|
167
|
+
parameters: [Parameter.new("limit", type: "T.untyped", default: "nil")],
|
168
|
+
return_type: "T.nilable(Elem)",
|
169
|
+
)
|
170
|
+
end
|
171
|
+
|
172
|
+
if Rails.version =~ /^5\.(0|1)/
|
173
|
+
class_rbi.create_method("to_a", return_type: "T::Array[Elem]")
|
174
|
+
end
|
175
|
+
|
176
|
+
class_rbi.create_method('empty?', return_type: "T::Boolean")
|
177
|
+
end
|
178
|
+
|
179
|
+
parlour.rbi
|
180
|
+
end
|
181
|
+
|
182
|
+
sig {
|
183
|
+
params(
|
184
|
+
class_rbi: Parlour::RbiGenerator::Namespace,
|
185
|
+
type: String,
|
186
|
+
class_method: T::Boolean,
|
187
|
+
).void
|
188
|
+
}
|
189
|
+
def create_elem_specific_query_methods(class_rbi, type:, class_method:)
|
190
|
+
finder_methods = %w(find find_by find_by!)
|
191
|
+
finder_methods.each do |finder_method|
|
192
|
+
class_rbi.create_method(
|
193
|
+
finder_method,
|
194
|
+
parameters: [ Parameter.new("*args", type: "T.untyped") ],
|
195
|
+
return_type: (finder_method == 'find' || finder_method.ends_with?('!')) ? type : "T.nilable(#{type})",
|
196
|
+
class_method: class_method,
|
197
|
+
)
|
198
|
+
end
|
199
|
+
|
200
|
+
first_or_something_by_methods = %w(find_or_initialize_by find_or_create_by find_or_create_by!)
|
201
|
+
first_or_something_by_methods.each do |first_or_something_by_method|
|
202
|
+
class_rbi.create_method(
|
203
|
+
first_or_something_by_method,
|
204
|
+
parameters: [
|
205
|
+
Parameter.new("attributes", type: "T.untyped"),
|
206
|
+
Parameter.new(
|
207
|
+
"&block",
|
208
|
+
type: "T.nilable(T.proc.params(object: #{type}).void)",
|
209
|
+
),
|
210
|
+
],
|
211
|
+
return_type: type,
|
212
|
+
class_method: class_method
|
213
|
+
)
|
214
|
+
end
|
215
|
+
|
216
|
+
item_methods = %w(first first! second second! third third! third_to_last third_to_last! second_to_last second_to_last! last last!)
|
217
|
+
item_methods.each do |item_method|
|
218
|
+
class_rbi.create_method(
|
219
|
+
item_method,
|
220
|
+
return_type: item_method.ends_with?('!') ? type : "T.nilable(#{type})",
|
221
|
+
class_method: class_method,
|
222
|
+
)
|
223
|
+
end
|
224
|
+
|
225
|
+
build_methods = %w(create create! new build first_or_create first_or_create! first_or_initialize)
|
226
|
+
build_methods.each do |build_method|
|
227
|
+
# `build` method doesn't exist on the model, only on the relations
|
228
|
+
next if build_method == 'build' && class_method
|
229
|
+
|
230
|
+
# This needs to match the generated method signature in activerecord.rbi and
|
231
|
+
# in Rails 5.0 and 5.1 the param is a splat.
|
232
|
+
if Rails.version =~ /^5\.(0|1)/ && %w(new build create create!).include?(build_method)
|
233
|
+
param = Parameter.new("*args", type: "T.untyped")
|
234
|
+
else
|
235
|
+
param = Parameter.new("attributes", type: "T.untyped", default: 'nil')
|
236
|
+
end
|
237
|
+
|
238
|
+
class_rbi.create_method(
|
239
|
+
build_method,
|
240
|
+
parameters: [
|
241
|
+
param,
|
242
|
+
Parameter.new(
|
243
|
+
"&block",
|
244
|
+
type: "T.nilable(T.proc.params(object: #{type}).void)",
|
245
|
+
),
|
246
|
+
],
|
247
|
+
return_type: type,
|
248
|
+
class_method: class_method,
|
249
|
+
)
|
250
|
+
end
|
251
|
+
|
252
|
+
batch_methods = %w(find_each find_in_batches)
|
253
|
+
batch_methods.each do |batch_method|
|
254
|
+
inner_type = batch_method == 'find_each' ? type : "T::Array[#{type}]"
|
255
|
+
|
256
|
+
class_rbi.create_method(
|
257
|
+
batch_method,
|
258
|
+
parameters: [
|
259
|
+
Parameter.new("start:", type: "T.nilable(Integer)", default: "nil"),
|
260
|
+
Parameter.new("finish:", type: "T.nilable(Integer)", default: "nil"),
|
261
|
+
Parameter.new("batch_size:", type: "T.nilable(Integer)", default: "1000"),
|
262
|
+
Parameter.new("error_on_ignore:", type: "T.nilable(T::Boolean)", default: "nil"),
|
263
|
+
Parameter.new("&block", type: "T.nilable(T.proc.params(e: #{inner_type}).void)"),
|
264
|
+
],
|
265
|
+
return_type: "T::Enumerator[#{inner_type}]",
|
266
|
+
class_method: class_method,
|
267
|
+
override: true,
|
268
|
+
)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
sig {
|
273
|
+
params(
|
274
|
+
class_rbi: Parlour::RbiGenerator::Namespace,
|
275
|
+
class_method: T::Boolean,
|
276
|
+
).void
|
277
|
+
}
|
278
|
+
def create_general_query_methods(class_rbi, class_method:)
|
279
|
+
class_rbi.create_method(
|
280
|
+
"exists?",
|
281
|
+
parameters: [ Parameter.new("conditions", type: "T.untyped", default: "nil") ],
|
282
|
+
return_type: "T::Boolean",
|
283
|
+
class_method: class_method,
|
284
|
+
)
|
285
|
+
|
286
|
+
boolean_methods = %w(any? many? none? one?)
|
287
|
+
boolean_methods.each do |boolean_method|
|
288
|
+
class_rbi.create_method(
|
289
|
+
boolean_method,
|
290
|
+
return_type: "T::Boolean",
|
291
|
+
class_method: class_method,
|
292
|
+
)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
data/lib/sorbet-rails/config.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# typed: false
|
2
|
+
require('sorbet-rails/deprecation.rb')
|
3
|
+
|
2
4
|
module BooleanStringImpl
|
3
5
|
def is_a?(type)
|
4
6
|
return super unless type == BooleanString
|
@@ -17,6 +19,10 @@ module BooleanStringImpl
|
|
17
19
|
|
18
20
|
def _is_a_boolean_string?
|
19
21
|
return @cached_is_a unless @cached_is_a.nil?
|
22
|
+
SorbetRails::TypeAssertDeprecation.deprecation_warning(
|
23
|
+
:BooleanString,
|
24
|
+
'Use TypedParam with T::Boolean type instead.'
|
25
|
+
)
|
20
26
|
@cached_is_a = (self =~ /^(true|false)$/i) == 0
|
21
27
|
end
|
22
28
|
end
|
@@ -27,6 +33,10 @@ end
|
|
27
33
|
|
28
34
|
class BooleanString < String
|
29
35
|
def self.===(other)
|
36
|
+
SorbetRails::TypeAssertDeprecation.deprecation_warning(
|
37
|
+
:BooleanString,
|
38
|
+
'Use TypedParam with T::Boolean type instead.'
|
39
|
+
)
|
30
40
|
other.is_a?(BooleanString)
|
31
41
|
end
|
32
42
|
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# typed: false
|
2
|
+
require('sorbet-rails/deprecation.rb')
|
3
|
+
|
2
4
|
module IntegerStringImpl
|
3
5
|
def is_a?(type)
|
4
6
|
return super unless type == IntegerString
|
@@ -17,6 +19,10 @@ module IntegerStringImpl
|
|
17
19
|
|
18
20
|
def _is_a_integer_string?
|
19
21
|
return @cached_is_a unless @cached_is_a.nil?
|
22
|
+
SorbetRails::TypeAssertDeprecation.deprecation_warning(
|
23
|
+
:IntegerString,
|
24
|
+
'Use TypedParams with Integer type instead.'
|
25
|
+
)
|
20
26
|
Integer(self, 10)
|
21
27
|
@cached_is_a = true
|
22
28
|
rescue ArgumentError => err
|
@@ -30,6 +36,10 @@ end
|
|
30
36
|
|
31
37
|
class IntegerString < String
|
32
38
|
def self.===(other)
|
39
|
+
SorbetRails::TypeAssertDeprecation.deprecation_warning(
|
40
|
+
:IntegerString,
|
41
|
+
'Use TypedParams with Integer type instead.'
|
42
|
+
)
|
33
43
|
other.is_a?(IntegerString)
|
34
44
|
end
|
35
45
|
end
|
@@ -28,3 +28,14 @@ end
|
|
28
28
|
class ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter;
|
29
29
|
def klass; end
|
30
30
|
end
|
31
|
+
|
32
|
+
class ActiveModel::Validations::PresenceValidator
|
33
|
+
sig { returns(T::Hash[T.untyped, T.untyped]) }
|
34
|
+
attr_reader :options
|
35
|
+
end
|
36
|
+
|
37
|
+
module ActiveModel::Validations
|
38
|
+
module ClassMethods
|
39
|
+
def validators_on(*attributes); end
|
40
|
+
end
|
41
|
+
end
|
@@ -35,7 +35,7 @@ class SorbetRails::ModelPlugins::ActiveRecordAssoc < SorbetRails::ModelPlugins::
|
|
35
35
|
def populate_single_assoc_getter_setter(assoc_module_rbi, assoc_name, reflection)
|
36
36
|
# TODO allow people to specify the possible values of polymorphic associations
|
37
37
|
assoc_class = assoc_should_be_untyped?(reflection) ? "T.untyped" : "::#{reflection.klass.name}"
|
38
|
-
assoc_type = belongs_to_and_required?(reflection) ? assoc_class : "T.nilable(#{assoc_class})"
|
38
|
+
assoc_type = (belongs_to_and_required?(reflection) || has_one_and_required?(reflection)) ? assoc_class : "T.nilable(#{assoc_class})"
|
39
39
|
|
40
40
|
assoc_module_rbi.create_method(
|
41
41
|
assoc_name.to_s,
|
@@ -56,6 +56,9 @@ class SorbetRails::ModelPlugins::ActiveRecordAssoc < SorbetRails::ModelPlugins::
|
|
56
56
|
# optional (via `optional` or `!required` or `!belongs_to_required_by_default`)
|
57
57
|
return false if !reflection.belongs_to?
|
58
58
|
|
59
|
+
column_def = @columns_hash[reflection.foreign_key.to_s]
|
60
|
+
db_required_config = column_def.present? && !column_def.null
|
61
|
+
|
59
62
|
rails_required_config =
|
60
63
|
if reflection.options.key?(:required)
|
61
64
|
!!reflection.options[:required]
|
@@ -65,22 +68,34 @@ class SorbetRails::ModelPlugins::ActiveRecordAssoc < SorbetRails::ModelPlugins::
|
|
65
68
|
!!reflection.active_record.belongs_to_required_by_default
|
66
69
|
end
|
67
70
|
|
68
|
-
|
69
|
-
|
71
|
+
# We check for validations on both the column name (e.g. wizard_id) and
|
72
|
+
# association name (e.g. wizard).
|
73
|
+
rails_required_config ||= [column_def&.name, reflection.name].compact.any? { |n| attribute_has_unconditional_presence_validation?(n) }
|
70
74
|
|
71
75
|
if rails_required_config && !db_required_config
|
72
76
|
puts "Warning: belongs_to association #{reflection.name} is required at the application
|
73
77
|
level but **nullable** at the DB level.\n Add a constraint at the DB level
|
74
78
|
(using `null: false` and foreign key constraint) to ensure it is enforced.".squish!
|
75
79
|
elsif !rails_required_config && db_required_config
|
76
|
-
|
77
|
-
|
78
|
-
|
80
|
+
if habtm_class?
|
81
|
+
puts "Note: belongs_to association #{reflection.name} is specified as not-null at the
|
82
|
+
DB level but will always be **optional** at the application level since it's part of a
|
83
|
+
has_and_belongs_to_many association.\n To resolve move to a 'has_many through:' association.".squish!
|
84
|
+
else
|
85
|
+
puts "Note: belongs_to association #{reflection.name} is specified as not-null at the
|
86
|
+
DB level but **optional** at the application level.\n Add a constraint at the app level
|
87
|
+
(using `optional: false`) as a validation hint to Rails.".squish!
|
88
|
+
end
|
79
89
|
end
|
80
90
|
|
81
91
|
rails_required_config || db_required_config
|
82
92
|
end
|
83
93
|
|
94
|
+
sig { params(reflection: T.untyped).returns(T::Boolean) }
|
95
|
+
private def has_one_and_required?(reflection)
|
96
|
+
!!(reflection.has_one? && attribute_has_unconditional_presence_validation?(reflection.name))
|
97
|
+
end
|
98
|
+
|
84
99
|
sig do
|
85
100
|
params(
|
86
101
|
assoc_module_rbi: T.untyped,
|
@@ -99,6 +114,12 @@ class SorbetRails::ModelPlugins::ActiveRecordAssoc < SorbetRails::ModelPlugins::
|
|
99
114
|
assoc_name.to_s,
|
100
115
|
return_type: relation_class,
|
101
116
|
)
|
117
|
+
unless assoc_should_be_untyped?(reflection)
|
118
|
+
assoc_module_rbi.create_method(
|
119
|
+
"#{assoc_name.singularize}_ids",
|
120
|
+
return_type: "T::Array[Integer]",
|
121
|
+
)
|
122
|
+
end
|
102
123
|
assoc_module_rbi.create_method(
|
103
124
|
"#{assoc_name}=",
|
104
125
|
parameters: [
|