tapioca 0.4.23 → 0.5.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/Gemfile +14 -14
- data/README.md +2 -2
- data/Rakefile +5 -7
- data/exe/tapioca +2 -2
- data/lib/tapioca/cli.rb +256 -2
- data/lib/tapioca/compilers/dsl/aasm.rb +122 -0
- data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +52 -12
- data/lib/tapioca/compilers/dsl/action_mailer.rb +6 -9
- data/lib/tapioca/compilers/dsl/active_job.rb +8 -12
- data/lib/tapioca/compilers/dsl/active_model_attributes.rb +131 -0
- data/lib/tapioca/compilers/dsl/active_record_associations.rb +33 -54
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +10 -105
- data/lib/tapioca/compilers/dsl/active_record_enum.rb +8 -10
- data/lib/tapioca/compilers/dsl/active_record_scope.rb +7 -10
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +5 -8
- data/lib/tapioca/compilers/dsl/active_resource.rb +9 -37
- data/lib/tapioca/compilers/dsl/active_storage.rb +98 -0
- data/lib/tapioca/compilers/dsl/active_support_concern.rb +108 -0
- data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +13 -8
- data/lib/tapioca/compilers/dsl/base.rb +96 -82
- data/lib/tapioca/compilers/dsl/config.rb +111 -0
- data/lib/tapioca/compilers/dsl/frozen_record.rb +5 -7
- data/lib/tapioca/compilers/dsl/identity_cache.rb +66 -29
- data/lib/tapioca/compilers/dsl/protobuf.rb +19 -69
- data/lib/tapioca/compilers/dsl/sidekiq_worker.rb +25 -12
- data/lib/tapioca/compilers/dsl/smart_properties.rb +19 -31
- data/lib/tapioca/compilers/dsl/state_machines.rb +56 -78
- data/lib/tapioca/compilers/dsl/url_helpers.rb +7 -10
- data/lib/tapioca/compilers/dsl_compiler.rb +22 -38
- data/lib/tapioca/compilers/requires_compiler.rb +2 -2
- data/lib/tapioca/compilers/sorbet.rb +26 -5
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +139 -154
- data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +4 -4
- data/lib/tapioca/compilers/symbol_table_compiler.rb +1 -1
- data/lib/tapioca/compilers/todos_compiler.rb +1 -1
- data/lib/tapioca/config.rb +2 -0
- data/lib/tapioca/config_builder.rb +4 -2
- data/lib/tapioca/constant_locator.rb +6 -8
- data/lib/tapioca/gemfile.rb +26 -19
- data/lib/tapioca/generator.rb +127 -43
- data/lib/tapioca/generic_type_registry.rb +25 -98
- data/lib/tapioca/helpers/active_record_column_type_helper.rb +98 -0
- data/lib/tapioca/internal.rb +1 -9
- data/lib/tapioca/loader.rb +14 -48
- data/lib/tapioca/rbi_ext/model.rb +122 -0
- data/lib/tapioca/reflection.rb +131 -0
- data/lib/tapioca/sorbet_ext/fixed_hash_patch.rb +1 -1
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +72 -4
- data/lib/tapioca/sorbet_ext/name_patch.rb +1 -1
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +2 -0
- metadata +35 -23
- data/lib/tapioca/cli/main.rb +0 -146
- data/lib/tapioca/core_ext/class.rb +0 -28
- data/lib/tapioca/core_ext/string.rb +0 -18
- data/lib/tapioca/rbi/model.rb +0 -405
- data/lib/tapioca/rbi/printer.rb +0 -410
- data/lib/tapioca/rbi/rewriters/group_nodes.rb +0 -106
- data/lib/tapioca/rbi/rewriters/nest_non_public_methods.rb +0 -65
- data/lib/tapioca/rbi/rewriters/nest_singleton_methods.rb +0 -42
- data/lib/tapioca/rbi/rewriters/sort_nodes.rb +0 -82
- data/lib/tapioca/rbi/visitor.rb +0 -21
@@ -1,8 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "parlour"
|
5
|
-
|
6
4
|
begin
|
7
5
|
require "action_controller"
|
8
6
|
rescue LoadError
|
@@ -72,38 +70,54 @@ module Tapioca
|
|
72
70
|
|
73
71
|
sig do
|
74
72
|
override
|
75
|
-
.params(root:
|
73
|
+
.params(root: RBI::Tree, constant: T.class_of(::ActionController::Base))
|
76
74
|
.void
|
77
75
|
end
|
78
76
|
def decorate(root, constant)
|
77
|
+
helpers_module = constant._helpers
|
78
|
+
proxied_helper_methods = constant._helper_methods.map(&:to_s).map(&:to_sym)
|
79
|
+
|
79
80
|
helper_proxy_name = "HelperProxy"
|
80
81
|
helper_methods_name = "HelperMethods"
|
81
|
-
proxied_helper_methods = constant._helper_methods.map(&:to_s).map(&:to_sym)
|
82
82
|
|
83
83
|
# Define the helpers method
|
84
|
-
root.
|
85
|
-
create_method(
|
84
|
+
root.create_path(constant) do |controller|
|
85
|
+
controller.create_method("helpers", return_type: helper_proxy_name)
|
86
86
|
|
87
87
|
# Create helper method module
|
88
88
|
controller.create_module(helper_methods_name) do |helper_methods|
|
89
|
-
|
89
|
+
# If the controller has no helper defined, then it just inherits
|
90
|
+
# the Action Controlller base helper methods module, so we should
|
91
|
+
# just add that as an include and stop doing more processing.
|
92
|
+
if helpers_module.name == "ActionController::Base::HelperMethods"
|
93
|
+
next helper_methods.create_include(T.must(qualified_name_of(helpers_module)))
|
94
|
+
end
|
90
95
|
|
96
|
+
# Find all the included helper modules and generate an include
|
97
|
+
# for each of those helper modules
|
91
98
|
gather_includes(helpers_module).each do |ancestor|
|
92
99
|
helper_methods.create_include(ancestor)
|
93
100
|
end
|
94
101
|
|
102
|
+
# Generate a method definition in the helper module for each
|
103
|
+
# helper method defined via the `helper_method` call in the controller.
|
95
104
|
helpers_module.instance_methods(false).each do |method_name|
|
96
105
|
method = if proxied_helper_methods.include?(method_name)
|
97
|
-
constant
|
106
|
+
helper_method_proxy_target(constant, method_name)
|
98
107
|
else
|
99
108
|
helpers_module.instance_method(method_name)
|
100
109
|
end
|
101
|
-
|
110
|
+
|
111
|
+
if method
|
112
|
+
create_method_from_def(helper_methods, method)
|
113
|
+
else
|
114
|
+
create_unknown_proxy_method(helper_methods, method_name)
|
115
|
+
end
|
102
116
|
end
|
103
117
|
end
|
104
118
|
|
105
119
|
# Create helper proxy class
|
106
|
-
controller.create_class(helper_proxy_name,
|
120
|
+
controller.create_class(helper_proxy_name, superclass_name: "::ActionView::Base") do |proxy|
|
107
121
|
proxy.create_include(helper_methods_name)
|
108
122
|
end
|
109
123
|
end
|
@@ -111,16 +125,42 @@ module Tapioca
|
|
111
125
|
|
112
126
|
sig { override.returns(T::Enumerable[Module]) }
|
113
127
|
def gather_constants
|
114
|
-
::ActionController::Base.
|
128
|
+
descendants_of(::ActionController::Base).reject(&:abstract?).select(&:name)
|
115
129
|
end
|
116
130
|
|
117
131
|
private
|
118
132
|
|
133
|
+
sig do
|
134
|
+
params(
|
135
|
+
constant: T.class_of(::ActionController::Base),
|
136
|
+
method_name: Symbol
|
137
|
+
).returns(T.nilable(UnboundMethod))
|
138
|
+
end
|
139
|
+
def helper_method_proxy_target(constant, method_name)
|
140
|
+
# Lookup the proxy target method only if it is defined as a public/protected or private method.
|
141
|
+
if constant.method_defined?(method_name) || constant.private_method_defined?(method_name)
|
142
|
+
constant.instance_method(method_name)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
sig { params(helper_methods: RBI::Scope, method_name: Symbol).void }
|
147
|
+
def create_unknown_proxy_method(helper_methods, method_name)
|
148
|
+
helper_methods.create_method(
|
149
|
+
method_name.to_s,
|
150
|
+
parameters: [
|
151
|
+
create_rest_param("args", type: "T.untyped"),
|
152
|
+
create_kw_rest_param("kwargs", type: "T.untyped"),
|
153
|
+
create_block_param("blk", type: "T.untyped"),
|
154
|
+
],
|
155
|
+
return_type: "T.untyped"
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
119
159
|
sig { params(mod: Module).returns(T::Array[String]) }
|
120
160
|
def gather_includes(mod)
|
121
161
|
mod.ancestors
|
122
162
|
.reject { |ancestor| ancestor.is_a?(Class) || ancestor == mod || ancestor.name.nil? }
|
123
|
-
.map { |ancestor|
|
163
|
+
.map { |ancestor| T.must(qualified_name_of(ancestor)) }
|
124
164
|
.reverse
|
125
165
|
end
|
126
166
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "parlour"
|
5
|
-
|
6
4
|
begin
|
7
5
|
require "action_mailer"
|
8
6
|
rescue LoadError
|
@@ -38,17 +36,16 @@ module Tapioca
|
|
38
36
|
class ActionMailer < Base
|
39
37
|
extend T::Sig
|
40
38
|
|
41
|
-
sig { override.params(root:
|
39
|
+
sig { override.params(root: RBI::Tree, constant: T.class_of(::ActionMailer::Base)).void }
|
42
40
|
def decorate(root, constant)
|
43
|
-
root.
|
41
|
+
root.create_path(constant) do |mailer|
|
44
42
|
constant.action_methods.to_a.each do |mailer_method|
|
45
43
|
method_def = constant.instance_method(mailer_method)
|
46
|
-
parameters =
|
47
|
-
create_method(
|
48
|
-
mailer,
|
44
|
+
parameters = compile_method_parameters_to_rbi(method_def)
|
45
|
+
mailer.create_method(
|
49
46
|
mailer_method,
|
50
47
|
parameters: parameters,
|
51
|
-
return_type:
|
48
|
+
return_type: "::ActionMailer::MessageDelivery",
|
52
49
|
class_method: true
|
53
50
|
)
|
54
51
|
end
|
@@ -57,7 +54,7 @@ module Tapioca
|
|
57
54
|
|
58
55
|
sig { override.returns(T::Enumerable[Module]) }
|
59
56
|
def gather_constants
|
60
|
-
::ActionMailer::Base.
|
57
|
+
descendants_of(::ActionMailer::Base).reject(&:abstract?)
|
61
58
|
end
|
62
59
|
end
|
63
60
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "parlour"
|
5
|
-
|
6
4
|
begin
|
7
5
|
require "active_job"
|
8
6
|
rescue LoadError
|
@@ -42,25 +40,23 @@ module Tapioca
|
|
42
40
|
class ActiveJob < Base
|
43
41
|
extend T::Sig
|
44
42
|
|
45
|
-
sig { override.params(root:
|
43
|
+
sig { override.params(root: RBI::Tree, constant: T.class_of(::ActiveJob::Base)).void }
|
46
44
|
def decorate(root, constant)
|
47
|
-
|
48
|
-
next unless constant.instance_methods(false).include?(:perform)
|
45
|
+
return unless constant.instance_methods(false).include?(:perform)
|
49
46
|
|
47
|
+
root.create_path(constant) do |job|
|
50
48
|
method = constant.instance_method(:perform)
|
51
|
-
parameters =
|
52
|
-
return_type =
|
49
|
+
parameters = compile_method_parameters_to_rbi(method)
|
50
|
+
return_type = compile_method_return_type_to_rbi(method)
|
53
51
|
|
54
|
-
create_method(
|
55
|
-
job,
|
52
|
+
job.create_method(
|
56
53
|
"perform_later",
|
57
54
|
parameters: parameters,
|
58
55
|
return_type: "T.any(#{constant.name}, FalseClass)",
|
59
56
|
class_method: true
|
60
57
|
)
|
61
58
|
|
62
|
-
create_method(
|
63
|
-
job,
|
59
|
+
job.create_method(
|
64
60
|
"perform_now",
|
65
61
|
parameters: parameters,
|
66
62
|
return_type: return_type,
|
@@ -71,7 +67,7 @@ module Tapioca
|
|
71
67
|
|
72
68
|
sig { override.returns(T::Enumerable[Module]) }
|
73
69
|
def gather_constants
|
74
|
-
::ActiveJob::Base
|
70
|
+
descendants_of(::ActiveJob::Base)
|
75
71
|
end
|
76
72
|
end
|
77
73
|
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "active_model"
|
6
|
+
rescue LoadError
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
module Tapioca
|
11
|
+
module Compilers
|
12
|
+
module Dsl
|
13
|
+
# `Tapioca::Compilers::Dsl::ActiveModelAttributes` decorates RBI files for all
|
14
|
+
# classes that use [`ActiveModel::Attributes`](https://edgeapi.rubyonrails.org/classes/ActiveModel/Attributes/ClassMethods.html).
|
15
|
+
#
|
16
|
+
# For example, with the following class:
|
17
|
+
#
|
18
|
+
# ~~~rb
|
19
|
+
# class Shop
|
20
|
+
# include ActiveModel::Attributes
|
21
|
+
#
|
22
|
+
# attribute :name, :string
|
23
|
+
# end
|
24
|
+
# ~~~
|
25
|
+
#
|
26
|
+
# this generator will produce an RBI file with the following content:
|
27
|
+
# ~~~rbi
|
28
|
+
# # typed: true
|
29
|
+
#
|
30
|
+
# class Shop
|
31
|
+
#
|
32
|
+
# sig { returns(T.nilable(::String)) }
|
33
|
+
# def name; end
|
34
|
+
#
|
35
|
+
# sig { params(name: T.nilable(::String)).returns(T.nilable(::String)) }
|
36
|
+
# def name=(name); end
|
37
|
+
# end
|
38
|
+
# ~~~
|
39
|
+
class ActiveModelAttributes < Base
|
40
|
+
extend T::Sig
|
41
|
+
|
42
|
+
sig { override.params(root: RBI::Tree, constant: T.all(Class, ::ActiveModel::Attributes::ClassMethods)).void }
|
43
|
+
def decorate(root, constant)
|
44
|
+
attribute_methods = attribute_methods_for(constant)
|
45
|
+
return if attribute_methods.empty?
|
46
|
+
|
47
|
+
root.create_path(constant) do |klass|
|
48
|
+
attribute_methods.each do |method, attribute_type|
|
49
|
+
generate_method(klass, method, attribute_type)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
sig { override.returns(T::Enumerable[Module]) }
|
55
|
+
def gather_constants
|
56
|
+
all_classes.grep(::ActiveModel::Attributes::ClassMethods)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
HANDLED_METHOD_TARGETS = T.let(["attribute", "attribute="], T::Array[String])
|
62
|
+
|
63
|
+
sig { params(constant: ::ActiveModel::Attributes::ClassMethods).returns(T::Array[[::String, ::String]]) }
|
64
|
+
def attribute_methods_for(constant)
|
65
|
+
constant.attribute_method_matchers.flat_map do |matcher|
|
66
|
+
constant.attribute_types.map do |name, value|
|
67
|
+
next unless handle_method_matcher?(matcher)
|
68
|
+
|
69
|
+
[matcher.method_name(name), type_for(value)]
|
70
|
+
end.compact
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
sig do
|
75
|
+
params(matcher: ::ActiveModel::AttributeMethods::ClassMethods::AttributeMethodMatcher)
|
76
|
+
.returns(T::Boolean)
|
77
|
+
end
|
78
|
+
def handle_method_matcher?(matcher)
|
79
|
+
target = if matcher.respond_to?(:method_missing_target)
|
80
|
+
# Pre-Rails 6.0, the field is named "method_missing_target"
|
81
|
+
T.unsafe(matcher).method_missing_target
|
82
|
+
else
|
83
|
+
# Rails 6.0+ has renamed the field to "target"
|
84
|
+
matcher.target
|
85
|
+
end
|
86
|
+
|
87
|
+
HANDLED_METHOD_TARGETS.include?(target.to_s)
|
88
|
+
end
|
89
|
+
|
90
|
+
sig { params(attribute_type_value: ::ActiveModel::Type::Value).returns(::String) }
|
91
|
+
def type_for(attribute_type_value)
|
92
|
+
type = case attribute_type_value
|
93
|
+
when ActiveModel::Type::Boolean
|
94
|
+
"T::Boolean"
|
95
|
+
when ActiveModel::Type::Date
|
96
|
+
"::Date"
|
97
|
+
when ActiveModel::Type::DateTime, ActiveModel::Type::Time
|
98
|
+
"::DateTime"
|
99
|
+
when ActiveModel::Type::Decimal
|
100
|
+
"::BigDecimal"
|
101
|
+
when ActiveModel::Type::Float
|
102
|
+
"::Float"
|
103
|
+
when ActiveModel::Type::Integer
|
104
|
+
"::Integer"
|
105
|
+
when ActiveModel::Type::String
|
106
|
+
"::String"
|
107
|
+
else
|
108
|
+
# we don't want untyped to be wrapped by T.nilable, so just return early
|
109
|
+
return "T.untyped"
|
110
|
+
end
|
111
|
+
|
112
|
+
"T.nilable(#{type})"
|
113
|
+
end
|
114
|
+
|
115
|
+
sig { params(klass: RBI::Scope, method: String, type: String).void }
|
116
|
+
def generate_method(klass, method, type)
|
117
|
+
if method.end_with?("=")
|
118
|
+
parameter = create_param("value", type: type)
|
119
|
+
klass.create_method(
|
120
|
+
method,
|
121
|
+
parameters: [parameter],
|
122
|
+
return_type: type
|
123
|
+
)
|
124
|
+
else
|
125
|
+
klass.create_method(method, return_type: type)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "parlour"
|
5
|
-
|
6
4
|
begin
|
7
5
|
require "active_record"
|
8
6
|
rescue LoadError
|
@@ -70,7 +68,7 @@ module Tapioca
|
|
70
68
|
# sig { params(ids: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
|
71
69
|
# def comment_ids=(ids); end
|
72
70
|
#
|
73
|
-
# sig { returns(::ActiveRecord::Associations::CollectionProxy[Comment]) }
|
71
|
+
# sig { returns(::ActiveRecord::Associations::CollectionProxy[::Comment]) }
|
74
72
|
# def comments; end
|
75
73
|
#
|
76
74
|
# sig { params(value: T::Enumerable[::Comment]).void }
|
@@ -106,11 +104,11 @@ module Tapioca
|
|
106
104
|
T.any(::ActiveRecord::Reflection::ThroughReflection, ::ActiveRecord::Reflection::AssociationReflection)
|
107
105
|
end
|
108
106
|
|
109
|
-
sig { override.params(root:
|
107
|
+
sig { override.params(root: RBI::Tree, constant: T.class_of(ActiveRecord::Base)).void }
|
110
108
|
def decorate(root, constant)
|
111
109
|
return if constant.reflections.empty?
|
112
110
|
|
113
|
-
root.
|
111
|
+
root.create_path(constant) do |model|
|
114
112
|
module_name = "GeneratedAssociationMethods"
|
115
113
|
|
116
114
|
model.create_module(module_name) do |mod|
|
@@ -124,26 +122,23 @@ module Tapioca
|
|
124
122
|
|
125
123
|
sig { override.returns(T::Enumerable[Module]) }
|
126
124
|
def gather_constants
|
127
|
-
ActiveRecord::Base.
|
125
|
+
descendants_of(::ActiveRecord::Base).reject(&:abstract_class?)
|
128
126
|
end
|
129
127
|
|
130
128
|
private
|
131
129
|
|
132
|
-
sig { params(mod:
|
130
|
+
sig { params(mod: RBI::Scope, constant: T.class_of(ActiveRecord::Base)).void }
|
133
131
|
def populate_nested_attribute_writers(mod, constant)
|
134
132
|
constant.nested_attributes_options.keys.each do |association_name|
|
135
|
-
create_method(
|
136
|
-
mod,
|
133
|
+
mod.create_method(
|
137
134
|
"#{association_name}_attributes=",
|
138
|
-
parameters: [
|
139
|
-
Parlour::RbiGenerator::Parameter.new("attributes", type: "T.untyped"),
|
140
|
-
],
|
135
|
+
parameters: [create_param("attributes", type: "T.untyped")],
|
141
136
|
return_type: "T.untyped"
|
142
137
|
)
|
143
138
|
end
|
144
139
|
end
|
145
140
|
|
146
|
-
sig { params(mod:
|
141
|
+
sig { params(mod: RBI::Scope, constant: T.class_of(ActiveRecord::Base)).void }
|
147
142
|
def populate_associations(mod, constant)
|
148
143
|
constant.reflections.each do |association_name, reflection|
|
149
144
|
if reflection.collection?
|
@@ -156,7 +151,7 @@ module Tapioca
|
|
156
151
|
|
157
152
|
sig do
|
158
153
|
params(
|
159
|
-
klass:
|
154
|
+
klass: RBI::Scope,
|
160
155
|
constant: T.class_of(ActiveRecord::Base),
|
161
156
|
association_name: T.any(String, Symbol),
|
162
157
|
reflection: ReflectionType
|
@@ -166,49 +161,41 @@ module Tapioca
|
|
166
161
|
association_class = type_for(constant, reflection)
|
167
162
|
association_type = "T.nilable(#{association_class})"
|
168
163
|
|
169
|
-
create_method(
|
170
|
-
klass,
|
164
|
+
klass.create_method(
|
171
165
|
association_name.to_s,
|
172
166
|
return_type: association_type,
|
173
167
|
)
|
174
|
-
create_method(
|
175
|
-
klass,
|
168
|
+
klass.create_method(
|
176
169
|
"#{association_name}=",
|
177
|
-
parameters: [
|
178
|
-
|
179
|
-
],
|
180
|
-
return_type: nil
|
170
|
+
parameters: [create_param("value", type: association_type)],
|
171
|
+
return_type: "void"
|
181
172
|
)
|
182
|
-
create_method(
|
183
|
-
klass,
|
173
|
+
klass.create_method(
|
184
174
|
"reload_#{association_name}",
|
185
175
|
return_type: association_type,
|
186
176
|
)
|
187
177
|
unless reflection.polymorphic?
|
188
|
-
create_method(
|
189
|
-
klass,
|
178
|
+
klass.create_method(
|
190
179
|
"build_#{association_name}",
|
191
180
|
parameters: [
|
192
|
-
|
193
|
-
|
181
|
+
create_rest_param("args", type: "T.untyped"),
|
182
|
+
create_block_param("blk", type: "T.untyped"),
|
194
183
|
],
|
195
184
|
return_type: association_class
|
196
185
|
)
|
197
|
-
create_method(
|
198
|
-
klass,
|
186
|
+
klass.create_method(
|
199
187
|
"create_#{association_name}",
|
200
188
|
parameters: [
|
201
|
-
|
202
|
-
|
189
|
+
create_rest_param("args", type: "T.untyped"),
|
190
|
+
create_block_param("blk", type: "T.untyped"),
|
203
191
|
],
|
204
192
|
return_type: association_class
|
205
193
|
)
|
206
|
-
create_method(
|
207
|
-
klass,
|
194
|
+
klass.create_method(
|
208
195
|
"create_#{association_name}!",
|
209
196
|
parameters: [
|
210
|
-
|
211
|
-
|
197
|
+
create_rest_param("args", type: "T.untyped"),
|
198
|
+
create_block_param("blk", type: "T.untyped"),
|
212
199
|
],
|
213
200
|
return_type: association_class
|
214
201
|
)
|
@@ -217,7 +204,7 @@ module Tapioca
|
|
217
204
|
|
218
205
|
sig do
|
219
206
|
params(
|
220
|
-
klass:
|
207
|
+
klass: RBI::Scope,
|
221
208
|
constant: T.class_of(ActiveRecord::Base),
|
222
209
|
association_name: T.any(String, Symbol),
|
223
210
|
reflection: ReflectionType
|
@@ -227,30 +214,22 @@ module Tapioca
|
|
227
214
|
association_class = type_for(constant, reflection)
|
228
215
|
relation_class = relation_type_for(constant, reflection)
|
229
216
|
|
230
|
-
create_method(
|
231
|
-
klass,
|
217
|
+
klass.create_method(
|
232
218
|
association_name.to_s,
|
233
219
|
return_type: relation_class,
|
234
220
|
)
|
235
|
-
create_method(
|
236
|
-
klass,
|
221
|
+
klass.create_method(
|
237
222
|
"#{association_name}=",
|
238
|
-
parameters: [
|
239
|
-
|
240
|
-
],
|
241
|
-
return_type: nil,
|
223
|
+
parameters: [create_param("value", type: "T::Enumerable[#{association_class}]")],
|
224
|
+
return_type: "void",
|
242
225
|
)
|
243
|
-
create_method(
|
244
|
-
klass,
|
226
|
+
klass.create_method(
|
245
227
|
"#{association_name.to_s.singularize}_ids",
|
246
228
|
return_type: "T::Array[T.untyped]"
|
247
229
|
)
|
248
|
-
create_method(
|
249
|
-
klass,
|
230
|
+
klass.create_method(
|
250
231
|
"#{association_name.to_s.singularize}_ids=",
|
251
|
-
parameters: [
|
252
|
-
Parlour::RbiGenerator::Parameter.new("ids", type: "T::Array[T.untyped]"),
|
253
|
-
],
|
232
|
+
parameters: [create_param("ids", type: "T::Array[T.untyped]")],
|
254
233
|
return_type: "T::Array[T.untyped]"
|
255
234
|
)
|
256
235
|
end
|
@@ -264,7 +243,7 @@ module Tapioca
|
|
264
243
|
def type_for(constant, reflection)
|
265
244
|
return "T.untyped" if !constant.table_exists? || polymorphic_association?(reflection)
|
266
245
|
|
267
|
-
|
246
|
+
T.must(qualified_name_of(reflection.klass))
|
268
247
|
end
|
269
248
|
|
270
249
|
sig do
|
@@ -278,7 +257,7 @@ module Tapioca
|
|
278
257
|
polymorphic_association?(reflection)
|
279
258
|
|
280
259
|
# Change to: "::#{reflection.klass.name}::ActiveRecord_Associations_CollectionProxy"
|
281
|
-
"::ActiveRecord::Associations::CollectionProxy[#{reflection.klass
|
260
|
+
"::ActiveRecord::Associations::CollectionProxy[#{qualified_name_of(reflection.klass)}]"
|
282
261
|
end
|
283
262
|
|
284
263
|
sig do
|