tapioca 0.5.6 → 0.6.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/README.md +114 -23
- data/lib/tapioca/cli.rb +188 -64
- data/lib/tapioca/compilers/dsl/active_record_associations.rb +94 -8
- data/lib/tapioca/compilers/dsl/active_record_columns.rb +5 -4
- data/lib/tapioca/compilers/dsl/active_record_relations.rb +703 -0
- data/lib/tapioca/compilers/dsl/active_record_scope.rb +43 -13
- data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +2 -4
- data/lib/tapioca/compilers/dsl/base.rb +25 -42
- data/lib/tapioca/compilers/dsl/extensions/frozen_record.rb +29 -0
- data/lib/tapioca/compilers/dsl/frozen_record.rb +37 -0
- data/lib/tapioca/compilers/dsl/helper/active_record_constants.rb +27 -0
- data/lib/tapioca/compilers/dsl/param_helper.rb +52 -0
- data/lib/tapioca/compilers/dsl/rails_generators.rb +120 -0
- data/lib/tapioca/compilers/dsl_compiler.rb +32 -6
- data/lib/tapioca/compilers/sorbet.rb +2 -0
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +47 -46
- data/lib/tapioca/executor.rb +79 -0
- data/lib/tapioca/gemfile.rb +23 -0
- data/lib/tapioca/generators/base.rb +11 -18
- data/lib/tapioca/generators/dsl.rb +33 -38
- data/lib/tapioca/generators/gem.rb +50 -29
- data/lib/tapioca/generators/init.rb +41 -16
- data/lib/tapioca/generators/todo.rb +6 -6
- data/lib/tapioca/helpers/cli_helper.rb +26 -0
- data/lib/tapioca/helpers/config_helper.rb +84 -0
- data/lib/tapioca/helpers/test/content.rb +51 -0
- data/lib/tapioca/helpers/test/isolation.rb +125 -0
- data/lib/tapioca/helpers/test/template.rb +34 -0
- data/lib/tapioca/internal.rb +3 -2
- data/lib/tapioca/rbi_ext/model.rb +12 -9
- data/lib/tapioca/reflection.rb +13 -0
- data/lib/tapioca/trackers/autoload.rb +70 -0
- data/lib/tapioca/trackers/constant_definition.rb +42 -0
- data/lib/tapioca/trackers/mixin.rb +78 -0
- data/lib/tapioca/trackers.rb +14 -0
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +28 -2
- metadata +19 -7
- data/lib/tapioca/config.rb +0 -45
- data/lib/tapioca/config_builder.rb +0 -73
- data/lib/tapioca/constant_locator.rb +0 -40
@@ -7,6 +7,8 @@ rescue LoadError
|
|
7
7
|
return
|
8
8
|
end
|
9
9
|
|
10
|
+
require "tapioca/compilers/dsl/helper/active_record_constants"
|
11
|
+
|
10
12
|
module Tapioca
|
11
13
|
module Compilers
|
12
14
|
module Dsl
|
@@ -99,6 +101,23 @@ module Tapioca
|
|
99
101
|
# ~~~
|
100
102
|
class ActiveRecordAssociations < Base
|
101
103
|
extend T::Sig
|
104
|
+
include Helper::ActiveRecordConstants
|
105
|
+
|
106
|
+
class SourceReflectionError < StandardError
|
107
|
+
end
|
108
|
+
|
109
|
+
class MissingConstantError < StandardError
|
110
|
+
extend T::Sig
|
111
|
+
|
112
|
+
sig { returns(String) }
|
113
|
+
attr_reader :class_name
|
114
|
+
|
115
|
+
sig { params(class_name: String).void }
|
116
|
+
def initialize(class_name)
|
117
|
+
@class_name = class_name
|
118
|
+
super
|
119
|
+
end
|
120
|
+
end
|
102
121
|
|
103
122
|
ReflectionType = T.type_alias do
|
104
123
|
T.any(::ActiveRecord::Reflection::ThroughReflection, ::ActiveRecord::Reflection::AssociationReflection)
|
@@ -109,14 +128,12 @@ module Tapioca
|
|
109
128
|
return if constant.reflections.empty?
|
110
129
|
|
111
130
|
root.create_path(constant) do |model|
|
112
|
-
|
113
|
-
|
114
|
-
model.create_module(module_name) do |mod|
|
131
|
+
model.create_module(AssociationMethodsModuleName) do |mod|
|
115
132
|
populate_nested_attribute_writers(mod, constant)
|
116
133
|
populate_associations(mod, constant)
|
117
134
|
end
|
118
135
|
|
119
|
-
model.create_include(
|
136
|
+
model.create_include(AssociationMethodsModuleName)
|
120
137
|
end
|
121
138
|
end
|
122
139
|
|
@@ -146,6 +163,14 @@ module Tapioca
|
|
146
163
|
else
|
147
164
|
populate_single_assoc_getter_setter(mod, constant, association_name, reflection)
|
148
165
|
end
|
166
|
+
rescue SourceReflectionError
|
167
|
+
add_error(<<~MSG.strip)
|
168
|
+
Cannot generate association `#{reflection.name}` on `#{constant}` since the source of the through association is missing.
|
169
|
+
MSG
|
170
|
+
rescue MissingConstantError => error
|
171
|
+
add_error(<<~MSG.strip)
|
172
|
+
Cannot generate association `#{declaration(reflection)}` on `#{constant}` since the constant `#{error.class_name}` does not exist.
|
173
|
+
MSG
|
149
174
|
end
|
150
175
|
end
|
151
176
|
|
@@ -241,11 +266,61 @@ module Tapioca
|
|
241
266
|
).returns(String)
|
242
267
|
end
|
243
268
|
def type_for(constant, reflection)
|
269
|
+
validate_reflection!(reflection)
|
270
|
+
|
244
271
|
return "T.untyped" if !constant.table_exists? || polymorphic_association?(reflection)
|
245
272
|
|
246
273
|
T.must(qualified_name_of(reflection.klass))
|
247
274
|
end
|
248
275
|
|
276
|
+
sig do
|
277
|
+
params(
|
278
|
+
reflection: ReflectionType
|
279
|
+
).void
|
280
|
+
end
|
281
|
+
def validate_reflection!(reflection)
|
282
|
+
# Check existence of source reflection, first, since, calling
|
283
|
+
# `.klass` also tries to go through the source reflection
|
284
|
+
# and fails with a cryptic error, otherwise.
|
285
|
+
if reflection.through_reflection?
|
286
|
+
raise SourceReflectionError unless reflection.source_reflection
|
287
|
+
end
|
288
|
+
|
289
|
+
# For non-polymorphic reflections, `.klass` should not be raising
|
290
|
+
# a `NameError`.
|
291
|
+
unless reflection.polymorphic?
|
292
|
+
reflection.klass
|
293
|
+
end
|
294
|
+
rescue NameError
|
295
|
+
class_name = if reflection.through_reflection?
|
296
|
+
reflection.send(:delegate_reflection).class_name
|
297
|
+
else
|
298
|
+
reflection.class_name
|
299
|
+
end
|
300
|
+
|
301
|
+
raise MissingConstantError, class_name
|
302
|
+
end
|
303
|
+
|
304
|
+
sig { params(reflection: ReflectionType).returns(T.nilable(String)) }
|
305
|
+
def declaration(reflection)
|
306
|
+
case reflection
|
307
|
+
when ActiveRecord::Reflection::HasOneReflection
|
308
|
+
"has_one :#{reflection.name}"
|
309
|
+
when ActiveRecord::Reflection::HasManyReflection
|
310
|
+
"has_many :#{reflection.name}"
|
311
|
+
when ActiveRecord::Reflection::HasAndBelongsToManyReflection
|
312
|
+
"has_and_belongs_to_many :#{reflection.name}"
|
313
|
+
when ActiveRecord::Reflection::BelongsToReflection
|
314
|
+
"belongs_to :#{reflection.name}"
|
315
|
+
when ActiveRecord::Reflection::ThroughReflection
|
316
|
+
delegate_reflection = reflection.send(:delegate_reflection)
|
317
|
+
declaration = declaration(delegate_reflection)
|
318
|
+
through_name = delegate_reflection.options[:through]
|
319
|
+
|
320
|
+
"#{declaration}, through: :#{through_name}"
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
249
324
|
sig do
|
250
325
|
params(
|
251
326
|
constant: T.class_of(ActiveRecord::Base),
|
@@ -253,11 +328,22 @@ module Tapioca
|
|
253
328
|
).returns(String)
|
254
329
|
end
|
255
330
|
def relation_type_for(constant, reflection)
|
256
|
-
|
257
|
-
|
331
|
+
validate_reflection!(reflection)
|
332
|
+
|
333
|
+
relations_enabled = generator_enabled?("ActiveRecordRelations")
|
334
|
+
polymorphic_association = !constant.table_exists? || polymorphic_association?(reflection)
|
258
335
|
|
259
|
-
|
260
|
-
|
336
|
+
if relations_enabled
|
337
|
+
if polymorphic_association
|
338
|
+
"ActiveRecord::Associations::CollectionProxy"
|
339
|
+
else
|
340
|
+
"#{qualified_name_of(reflection.klass)}::#{AssociationsCollectionProxyClassName}"
|
341
|
+
end
|
342
|
+
elsif polymorphic_association
|
343
|
+
"ActiveRecord::Associations::CollectionProxy[T.untyped]"
|
344
|
+
else
|
345
|
+
"::ActiveRecord::Associations::CollectionProxy[#{qualified_name_of(reflection.klass)}]"
|
346
|
+
end
|
261
347
|
end
|
262
348
|
|
263
349
|
sig do
|
@@ -7,6 +7,8 @@ rescue LoadError
|
|
7
7
|
return
|
8
8
|
end
|
9
9
|
|
10
|
+
require "tapioca/compilers/dsl/helper/active_record_constants"
|
11
|
+
|
10
12
|
module Tapioca
|
11
13
|
module Compilers
|
12
14
|
module Dsl
|
@@ -96,15 +98,14 @@ module Tapioca
|
|
96
98
|
# ~~~
|
97
99
|
class ActiveRecordColumns < Base
|
98
100
|
extend T::Sig
|
101
|
+
include Helper::ActiveRecordConstants
|
99
102
|
|
100
103
|
sig { override.params(root: RBI::Tree, constant: T.class_of(ActiveRecord::Base)).void }
|
101
104
|
def decorate(root, constant)
|
102
105
|
return unless constant.table_exists?
|
103
106
|
|
104
107
|
root.create_path(constant) do |model|
|
105
|
-
|
106
|
-
|
107
|
-
model.create_module(module_name) do |mod|
|
108
|
+
model.create_module(AttributeMethodsModuleName) do |mod|
|
108
109
|
constant.columns_hash.each_key do |column_name|
|
109
110
|
column_name = column_name.to_s
|
110
111
|
add_methods_for_attribute(mod, constant, column_name)
|
@@ -121,7 +122,7 @@ module Tapioca
|
|
121
122
|
end
|
122
123
|
end
|
123
124
|
|
124
|
-
model.create_include(
|
125
|
+
model.create_include(AttributeMethodsModuleName)
|
125
126
|
end
|
126
127
|
end
|
127
128
|
|