tapioca 0.10.3 → 0.10.5
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/exe/tapioca +15 -13
- data/lib/tapioca/cli.rb +9 -4
- data/lib/tapioca/commands/configure.rb +2 -2
- data/lib/tapioca/commands/gem.rb +4 -2
- data/lib/tapioca/dsl/compiler.rb +4 -4
- data/lib/tapioca/dsl/compilers/aasm.rb +11 -2
- data/lib/tapioca/dsl/compilers/active_record_delegated_types.rb +163 -0
- data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +8 -5
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +48 -16
- data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +14 -11
- data/lib/tapioca/dsl/compilers/active_resource.rb +22 -15
- data/lib/tapioca/dsl/compilers/active_storage.rb +4 -2
- data/lib/tapioca/dsl/compilers/protobuf.rb +5 -0
- data/lib/tapioca/dsl/compilers/smart_properties.rb +7 -4
- data/lib/tapioca/dsl/compilers/url_helpers.rb +7 -4
- data/lib/tapioca/dsl/extensions/active_record.rb +29 -0
- data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +37 -27
- data/lib/tapioca/dsl/helpers/active_record_constants_helper.rb +1 -0
- data/lib/tapioca/dsl/pipeline.rb +3 -1
- data/lib/tapioca/gem/listeners/yard_doc.rb +13 -10
- data/lib/tapioca/gem/pipeline.rb +1 -2
- data/lib/tapioca/gemfile.rb +6 -2
- data/lib/tapioca/helpers/gem_helper.rb +1 -1
- data/lib/tapioca/helpers/rbi_files_helper.rb +14 -7
- data/lib/tapioca/helpers/sorbet_helper.rb +7 -3
- data/lib/tapioca/helpers/source_uri.rb +10 -7
- data/lib/tapioca/loaders/gem.rb +4 -2
- data/lib/tapioca/loaders/loader.rb +6 -3
- data/lib/tapioca/rbi_ext/model.rb +7 -2
- data/lib/tapioca/rbi_formatter.rb +11 -8
- data/lib/tapioca/runtime/trackers.rb +17 -0
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +35 -13
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +8 -5
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9df4814fb4f17b9f1d53aab7a9b9b23498cfea0330fb48b47d909af119ac6ea0
|
4
|
+
data.tar.gz: 7f2d233a47a7ceb2b4a1f4894c794d65c2cca9c9e1547022630d7b395de0cd47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f65d462c261005c62b31f0864df29b550d5a07551433203f485f8f66c57a8e100fccdb1deb1b7f29e185a1f6e8bf5b4e9f59387a1ba24ea8b4cff168b1b4ca12
|
7
|
+
data.tar.gz: 721c40a48f379eda0e6302ff59b2a3228f0262c5d2b2bac1111016d92ec02597e9d35c28a38a6fcc903a8ac13b0b8c4dddcc7e1d747907390762f47601d19e68
|
data/exe/tapioca
CHANGED
@@ -3,19 +3,21 @@
|
|
3
3
|
|
4
4
|
require "sorbet-runtime"
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
6
|
+
unless ENV["ENFORCE_TYPECHECKING"] == "1"
|
7
|
+
begin
|
8
|
+
T::Configuration.default_checked_level = :never
|
9
|
+
# Suppresses call validation errors
|
10
|
+
T::Configuration.call_validation_error_handler = ->(*) {}
|
11
|
+
# Suppresses errors caused by T.cast, T.let, T.must, etc.
|
12
|
+
T::Configuration.inline_type_error_handler = ->(*) {}
|
13
|
+
# Suppresses errors caused by incorrect parameter ordering
|
14
|
+
T::Configuration.sig_validation_error_handler = ->(*) {}
|
15
|
+
rescue
|
16
|
+
# Need this rescue so that if another gem has
|
17
|
+
# already set the checked level by the time we
|
18
|
+
# get to it, we don't fail outright.
|
19
|
+
nil
|
20
|
+
end
|
19
21
|
end
|
20
22
|
|
21
23
|
require_relative "../lib/tapioca/internal"
|
data/lib/tapioca/cli.rb
CHANGED
@@ -25,9 +25,12 @@ module Tapioca
|
|
25
25
|
|
26
26
|
desc "init", "get project ready for type checking"
|
27
27
|
def init
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
# We need to make sure that trackers stay enabled until the `gem` command is invoked
|
29
|
+
Runtime::Trackers.with_trackers_enabled do
|
30
|
+
invoke(:configure)
|
31
|
+
invoke(:annotations)
|
32
|
+
invoke(:gem)
|
33
|
+
end
|
31
34
|
invoke(:todo)
|
32
35
|
|
33
36
|
print_init_next_steps
|
@@ -293,7 +296,9 @@ module Tapioca
|
|
293
296
|
end
|
294
297
|
|
295
298
|
desc "annotations", "Pull gem RBI annotations from remote sources"
|
296
|
-
option :sources,
|
299
|
+
option :sources,
|
300
|
+
type: :array,
|
301
|
+
default: [CENTRAL_REPO_ROOT_URI],
|
297
302
|
desc: "URIs of the sources to pull gem RBI annotations from"
|
298
303
|
option :netrc, type: :boolean, default: true, desc: "Use .netrc to authenticate to private sources"
|
299
304
|
option :netrc_file, type: :string, desc: "Path to .netrc file"
|
@@ -70,7 +70,7 @@ module Tapioca
|
|
70
70
|
# typed: true
|
71
71
|
# frozen_string_literal: true
|
72
72
|
|
73
|
-
# Add your extra requires here (`#{default_command(:require)}` can be used to
|
73
|
+
# Add your extra requires here (`#{default_command(:require)}` can be used to bootstrap this list)
|
74
74
|
CONTENT
|
75
75
|
end
|
76
76
|
|
@@ -92,7 +92,7 @@ module Tapioca
|
|
92
92
|
@installer ||= Bundler::Installer.new(Bundler.root, Bundler.definition)
|
93
93
|
end
|
94
94
|
|
95
|
-
sig { returns(Bundler::StubSpecification) }
|
95
|
+
sig { returns(T.any(Bundler::StubSpecification, ::Gem::Specification)) }
|
96
96
|
def spec
|
97
97
|
@spec ||= Bundler.definition.specs.find { |s| s.name == "tapioca" }
|
98
98
|
end
|
data/lib/tapioca/commands/gem.rb
CHANGED
@@ -156,9 +156,11 @@ module Tapioca
|
|
156
156
|
|
157
157
|
rbi = RBI::File.new(strictness: @typed_overrides[gem.name] || "true")
|
158
158
|
|
159
|
-
@rbi_formatter.write_header!(
|
159
|
+
@rbi_formatter.write_header!(
|
160
|
+
rbi,
|
160
161
|
default_command(:gem, gem.name),
|
161
|
-
reason: "types exported from the `#{gem.name}` gem"
|
162
|
+
reason: "types exported from the `#{gem.name}` gem",
|
163
|
+
) if @file_header
|
162
164
|
|
163
165
|
rbi.root = Tapioca::Gem::Pipeline.new(gem, include_doc: @include_doc, include_loc: @include_loc).compile
|
164
166
|
|
data/lib/tapioca/dsl/compiler.rb
CHANGED
@@ -101,6 +101,9 @@ module Tapioca
|
|
101
101
|
# rest parameter type
|
102
102
|
params << signature.rest_type.to_s if signature.has_rest
|
103
103
|
|
104
|
+
# keyrest parameter type
|
105
|
+
params << signature.keyrest_type.to_s if signature.has_keyrest
|
106
|
+
|
104
107
|
# special case `.void` in a proc
|
105
108
|
unless signature.block_name.nil?
|
106
109
|
params << signature.block_type.to_s.gsub("returns(<VOID>)", "void")
|
@@ -159,10 +162,7 @@ module Tapioca
|
|
159
162
|
def compile_method_return_type_to_rbi(method_def)
|
160
163
|
signature = signature_of(method_def)
|
161
164
|
return_type = signature.nil? ? "T.untyped" : name_of_type(signature.return_type)
|
162
|
-
return_type
|
163
|
-
# Map <NOT-TYPED> to `T.untyped`
|
164
|
-
return_type = "T.untyped" if return_type == "<NOT-TYPED>"
|
165
|
-
return_type
|
165
|
+
sanitize_signature_types(return_type)
|
166
166
|
end
|
167
167
|
end
|
168
168
|
end
|
@@ -44,8 +44,17 @@ module Tapioca
|
|
44
44
|
# https://github.com/aasm/aasm/blob/0e03746/lib/aasm/core/event.rb#L21-L29
|
45
45
|
EVENT_CALLBACKS =
|
46
46
|
T.let(
|
47
|
-
[
|
48
|
-
|
47
|
+
[
|
48
|
+
"after",
|
49
|
+
"after_commit",
|
50
|
+
"after_transaction",
|
51
|
+
"before",
|
52
|
+
"before_transaction",
|
53
|
+
"ensure",
|
54
|
+
"error",
|
55
|
+
"before_success",
|
56
|
+
"success",
|
57
|
+
].freeze,
|
49
58
|
T::Array[String],
|
50
59
|
)
|
51
60
|
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "active_record"
|
6
|
+
rescue LoadError
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
require "tapioca/dsl/helpers/active_record_column_type_helper"
|
11
|
+
require "tapioca/dsl/helpers/active_record_constants_helper"
|
12
|
+
|
13
|
+
module Tapioca
|
14
|
+
module Dsl
|
15
|
+
module Compilers
|
16
|
+
# `Tapioca::Dsl::Compilers::DelegatedTypes` defines RBI files for subclasses of
|
17
|
+
# [`ActiveRecord::Base`](https://api.rubyonrails.org/classes/ActiveRecord/Base.html).
|
18
|
+
# This compiler is only responsible for defining the methods that would be created for delegated_types that
|
19
|
+
# are defined in the Active Record model.
|
20
|
+
#
|
21
|
+
# For example, with the following model class:
|
22
|
+
#
|
23
|
+
# ~~~rb
|
24
|
+
# class Entry < ActiveRecord::Base
|
25
|
+
# delegated_type :entryable, types: %w[ Message Comment ]
|
26
|
+
# end
|
27
|
+
# ~~~
|
28
|
+
#
|
29
|
+
# this compiler will produce the following methods in the RBI file
|
30
|
+
# `entry.rbi`:
|
31
|
+
#
|
32
|
+
# ~~~rbi
|
33
|
+
# # entry.rbi
|
34
|
+
# # typed: true
|
35
|
+
#
|
36
|
+
# class Entry
|
37
|
+
# include GeneratedDelegatedTypeMethods
|
38
|
+
#
|
39
|
+
# module GeneratedDelegatedTypeMethods
|
40
|
+
# sig { params(args: T.untyped).returns(T.any(Message, Comment)) }
|
41
|
+
# def build_entryable(*args); end
|
42
|
+
#
|
43
|
+
# sig { returns(Class) }
|
44
|
+
# def entryable_class; end
|
45
|
+
#
|
46
|
+
# sig { returns(ActiveSupport::StringInquirer) }
|
47
|
+
# def entryable_name; end
|
48
|
+
#
|
49
|
+
# sig { returns(T::Boolean) }
|
50
|
+
# def message?; end
|
51
|
+
#
|
52
|
+
# sig { returns(T.nilable(Message)) }
|
53
|
+
# def message; end
|
54
|
+
#
|
55
|
+
# sig { returns(T.nilable(Integer)) }
|
56
|
+
# def message_id; end
|
57
|
+
#
|
58
|
+
# sig { returns(T::Boolean) }
|
59
|
+
# def comment?; end
|
60
|
+
#
|
61
|
+
# sig { returns(T.nilable(Comment)) }
|
62
|
+
# def comment; end
|
63
|
+
#
|
64
|
+
# sig { returns(T.nilable(Integer)) }
|
65
|
+
# def comment_id; end
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# ~~~
|
70
|
+
class ActiveRecordDelegatedTypes < Compiler
|
71
|
+
extend T::Sig
|
72
|
+
include Helpers::ActiveRecordConstantsHelper
|
73
|
+
|
74
|
+
ConstantType = type_member { { fixed: T.all(T.class_of(ActiveRecord::Base), Extensions::ActiveRecord) } }
|
75
|
+
|
76
|
+
sig { override.void }
|
77
|
+
def decorate
|
78
|
+
return if constant.__tapioca_delegated_types.nil?
|
79
|
+
|
80
|
+
root.create_path(constant) do |model|
|
81
|
+
model.create_module(DelegatedTypesModuleName) do |mod|
|
82
|
+
constant.__tapioca_delegated_types.each do |role, data|
|
83
|
+
types = data.fetch(:types)
|
84
|
+
options = data.fetch(:options, {})
|
85
|
+
populate_role_accessors(mod, role, types)
|
86
|
+
populate_type_helpers(mod, role, types, options)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
model.create_include(DelegatedTypesModuleName)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class << self
|
95
|
+
extend T::Sig
|
96
|
+
|
97
|
+
sig { override.returns(T::Enumerable[Module]) }
|
98
|
+
def gather_constants
|
99
|
+
descendants_of(::ActiveRecord::Base).reject(&:abstract_class?)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
sig { params(mod: RBI::Scope, role: Symbol, types: T::Array[String]).void }
|
106
|
+
def populate_role_accessors(mod, role, types)
|
107
|
+
mod.create_method(
|
108
|
+
"#{role}_name",
|
109
|
+
parameters: [],
|
110
|
+
return_type: "ActiveSupport::StringInquirer",
|
111
|
+
)
|
112
|
+
|
113
|
+
mod.create_method(
|
114
|
+
"#{role}_class",
|
115
|
+
parameters: [],
|
116
|
+
return_type: "Class",
|
117
|
+
)
|
118
|
+
|
119
|
+
mod.create_method(
|
120
|
+
"build_#{role}",
|
121
|
+
parameters: [create_rest_param("args", type: "T.untyped")],
|
122
|
+
return_type: "T.any(#{types.join(", ")})",
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
sig { params(mod: RBI::Scope, role: Symbol, types: T::Array[String], options: T::Hash[Symbol, T.untyped]).void }
|
127
|
+
def populate_type_helpers(mod, role, types, options)
|
128
|
+
types.each do |type|
|
129
|
+
populate_type_helper(mod, role, type, options)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
sig { params(mod: RBI::Scope, role: Symbol, type: String, options: T::Hash[Symbol, T.untyped]).void }
|
134
|
+
def populate_type_helper(mod, role, type, options)
|
135
|
+
singular = type.tableize.tr("/", "_").singularize
|
136
|
+
query = "#{singular}?"
|
137
|
+
primary_key = options[:primary_key] || "id"
|
138
|
+
role_id = options[:foreign_key] || "#{role}_id"
|
139
|
+
|
140
|
+
getter_type, _ = Helpers::ActiveRecordColumnTypeHelper.new(constant).type_for(role_id.to_s)
|
141
|
+
|
142
|
+
mod.create_method(
|
143
|
+
query,
|
144
|
+
parameters: [],
|
145
|
+
return_type: "T::Boolean",
|
146
|
+
)
|
147
|
+
|
148
|
+
mod.create_method(
|
149
|
+
singular,
|
150
|
+
parameters: [],
|
151
|
+
return_type: "T.nilable(#{type})",
|
152
|
+
)
|
153
|
+
|
154
|
+
mod.create_method(
|
155
|
+
"#{singular}_#{primary_key}",
|
156
|
+
parameters: [],
|
157
|
+
return_type: as_nilable_type(getter_type),
|
158
|
+
)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -72,11 +72,14 @@ module Tapioca
|
|
72
72
|
|
73
73
|
sig { returns(Class) }
|
74
74
|
def fixture_loader
|
75
|
-
@fixture_loader ||= T.let(
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
75
|
+
@fixture_loader ||= T.let(
|
76
|
+
Class.new do
|
77
|
+
T.unsafe(self).include(ActiveRecord::TestFixtures)
|
78
|
+
T.unsafe(self).fixture_path = Rails.root.join("test", "fixtures")
|
79
|
+
T.unsafe(self).fixtures(:all)
|
80
|
+
end,
|
81
|
+
T.nilable(Class),
|
82
|
+
)
|
80
83
|
end
|
81
84
|
|
82
85
|
sig { returns(T::Array[String]) }
|
@@ -196,27 +196,34 @@ module Tapioca
|
|
196
196
|
T::Array[Symbol],
|
197
197
|
)
|
198
198
|
|
199
|
-
QUERY_METHODS = T.let(
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
199
|
+
QUERY_METHODS = T.let(
|
200
|
+
begin
|
201
|
+
# Grab all Query methods
|
202
|
+
query_methods = ActiveRecord::QueryMethods.instance_methods(false)
|
203
|
+
# Grab all Spawn methods
|
204
|
+
query_methods |= ActiveRecord::SpawnMethods.instance_methods(false)
|
205
|
+
# Remove the ones we know are private API
|
206
|
+
query_methods -= [:arel, :build_subquery, :construct_join_dependency, :extensions, :spawn]
|
207
|
+
# Remove "where" which needs a custom return type for WhereChains
|
208
|
+
query_methods -= [:where]
|
209
|
+
# Remove the methods that ...
|
210
|
+
query_methods
|
211
|
+
.grep_v(/_clause$/) # end with "_clause"
|
212
|
+
.grep_v(/_values?$/) # end with "_value" or "_values"
|
213
|
+
.grep_v(/=$/) # end with "=""
|
214
|
+
.grep_v(/(?<!uniq)!$/) # end with "!" except for "uniq!"
|
215
|
+
end,
|
216
|
+
T::Array[Symbol],
|
217
|
+
)
|
215
218
|
WHERE_CHAIN_QUERY_METHODS = T.let(
|
216
219
|
ActiveRecord::QueryMethods::WhereChain.instance_methods(false),
|
217
220
|
T::Array[Symbol],
|
218
221
|
)
|
219
222
|
FINDER_METHODS = T.let(ActiveRecord::FinderMethods.instance_methods(false), T::Array[Symbol])
|
223
|
+
SIGNED_FINDER_METHODS = T.let(
|
224
|
+
defined?(ActiveRecord::SignedId) ? ActiveRecord::SignedId::ClassMethods.instance_methods(false) : [],
|
225
|
+
T::Array[Symbol],
|
226
|
+
)
|
220
227
|
CALCULATION_METHODS = T.let(ActiveRecord::Calculations.instance_methods(false), T::Array[Symbol])
|
221
228
|
ENUMERABLE_QUERY_METHODS = T.let([:any?, :many?, :none?, :one?], T::Array[Symbol])
|
222
229
|
FIND_OR_CREATE_METHODS = T.let(
|
@@ -593,6 +600,31 @@ module Tapioca
|
|
593
600
|
end
|
594
601
|
end
|
595
602
|
|
603
|
+
SIGNED_FINDER_METHODS.each do |method_name|
|
604
|
+
case method_name
|
605
|
+
when :find_signed
|
606
|
+
create_common_method(
|
607
|
+
"find_signed",
|
608
|
+
common_relation_methods_module,
|
609
|
+
parameters: [
|
610
|
+
create_param("signed_id", type: "T.untyped"),
|
611
|
+
create_kw_opt_param("purpose", type: "T.untyped", default: "nil"),
|
612
|
+
],
|
613
|
+
return_type: as_nilable_type(constant_name),
|
614
|
+
)
|
615
|
+
when :find_signed!
|
616
|
+
create_common_method(
|
617
|
+
"find_signed!",
|
618
|
+
common_relation_methods_module,
|
619
|
+
parameters: [
|
620
|
+
create_param("signed_id", type: "T.untyped"),
|
621
|
+
create_kw_opt_param("purpose", type: "T.untyped", default: "nil"),
|
622
|
+
],
|
623
|
+
return_type: constant_name,
|
624
|
+
)
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
596
628
|
CALCULATION_METHODS.each do |method_name|
|
597
629
|
case method_name
|
598
630
|
when :average, :maximum, :minimum
|
@@ -126,17 +126,20 @@ module Tapioca
|
|
126
126
|
|
127
127
|
private
|
128
128
|
|
129
|
-
TYPES = T.let(
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
129
|
+
TYPES = T.let(
|
130
|
+
{
|
131
|
+
boolean: "T::Boolean",
|
132
|
+
integer: "Integer",
|
133
|
+
string: "String",
|
134
|
+
float: "Float",
|
135
|
+
date: "Date",
|
136
|
+
time: "Time",
|
137
|
+
datetime: "DateTime",
|
138
|
+
decimal: "BigDecimal",
|
139
|
+
any: "T.untyped",
|
140
|
+
}.freeze,
|
141
|
+
T::Hash[Symbol, String],
|
142
|
+
)
|
140
143
|
|
141
144
|
sig { params(attr_type: Symbol).returns(String) }
|
142
145
|
def type_for(attr_type)
|
@@ -85,18 +85,21 @@ module Tapioca
|
|
85
85
|
|
86
86
|
private
|
87
87
|
|
88
|
-
TYPES = T.let(
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
88
|
+
TYPES = T.let(
|
89
|
+
{
|
90
|
+
boolean: "T::Boolean",
|
91
|
+
integer: "Integer",
|
92
|
+
string: "String",
|
93
|
+
float: "Float",
|
94
|
+
date: "Date",
|
95
|
+
time: "Time",
|
96
|
+
datetime: "DateTime",
|
97
|
+
decimal: "BigDecimal",
|
98
|
+
binary: "String",
|
99
|
+
text: "String",
|
100
|
+
}.freeze,
|
101
|
+
T::Hash[Symbol, String],
|
102
|
+
)
|
100
103
|
|
101
104
|
sig { params(attr_type: Symbol).returns(String) }
|
102
105
|
def type_for(attr_type)
|
@@ -109,9 +112,13 @@ module Tapioca
|
|
109
112
|
|
110
113
|
klass.create_method(attribute, return_type: return_type)
|
111
114
|
klass.create_method("#{attribute}?", return_type: "T::Boolean")
|
112
|
-
klass.create_method(
|
113
|
-
|
114
|
-
|
115
|
+
klass.create_method(
|
116
|
+
"#{attribute}=",
|
117
|
+
parameters: [
|
118
|
+
create_param("value", type: return_type),
|
119
|
+
],
|
120
|
+
return_type: return_type,
|
121
|
+
)
|
115
122
|
end
|
116
123
|
end
|
117
124
|
end
|
@@ -48,8 +48,10 @@ module Tapioca
|
|
48
48
|
|
49
49
|
ConstantType = type_member do
|
50
50
|
{
|
51
|
-
fixed: T.all(
|
52
|
-
|
51
|
+
fixed: T.all(
|
52
|
+
Module,
|
53
|
+
::ActiveStorage::Reflection::ActiveRecordExtensions::ClassMethods,
|
54
|
+
),
|
53
55
|
}
|
54
56
|
end
|
55
57
|
|
@@ -119,10 +119,13 @@ module Tapioca
|
|
119
119
|
mod.create_method(property.reader.to_s, return_type: type)
|
120
120
|
end
|
121
121
|
|
122
|
-
BOOLEANS = T.let(
|
123
|
-
[
|
124
|
-
|
125
|
-
|
122
|
+
BOOLEANS = T.let(
|
123
|
+
[
|
124
|
+
[true, false],
|
125
|
+
[false, true],
|
126
|
+
].freeze,
|
127
|
+
T::Array[[T::Boolean, T::Boolean]],
|
128
|
+
)
|
126
129
|
|
127
130
|
sig { params(property: ::SmartProperties::Property).returns(String) }
|
128
131
|
def type_for(property)
|
@@ -102,10 +102,13 @@ module Tapioca
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
-
NON_DISCOVERABLE_INCLUDERS = T.let(
|
106
|
-
|
107
|
-
|
108
|
-
|
105
|
+
NON_DISCOVERABLE_INCLUDERS = T.let(
|
106
|
+
[
|
107
|
+
ActionDispatch::IntegrationTest,
|
108
|
+
ActionView::Helpers,
|
109
|
+
],
|
110
|
+
T::Array[Module],
|
111
|
+
)
|
109
112
|
|
110
113
|
class << self
|
111
114
|
extend T::Sig
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "active_record"
|
6
|
+
rescue LoadError
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
module Tapioca
|
11
|
+
module Dsl
|
12
|
+
module Compilers
|
13
|
+
module Extensions
|
14
|
+
module ActiveRecord
|
15
|
+
attr_reader :__tapioca_delegated_types
|
16
|
+
|
17
|
+
def delegated_type(role, types:, **options)
|
18
|
+
@__tapioca_delegated_types ||= {}
|
19
|
+
@__tapioca_delegated_types[role] = { types: types, options: options }
|
20
|
+
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
::ActiveRecord::Base.singleton_class.prepend(self)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -19,33 +19,7 @@ module Tapioca
|
|
19
19
|
|
20
20
|
column_type = @constant.attribute_types[column_name]
|
21
21
|
|
22
|
-
getter_type =
|
23
|
-
case column_type
|
24
|
-
when defined?(MoneyColumn) && MoneyColumn::ActiveRecordType
|
25
|
-
"::Money"
|
26
|
-
when ActiveRecord::Type::Integer
|
27
|
-
"::Integer"
|
28
|
-
when ActiveRecord::Type::String
|
29
|
-
"::String"
|
30
|
-
when ActiveRecord::Type::Date
|
31
|
-
"::Date"
|
32
|
-
when ActiveRecord::Type::Decimal
|
33
|
-
"::BigDecimal"
|
34
|
-
when ActiveRecord::Type::Float
|
35
|
-
"::Float"
|
36
|
-
when ActiveRecord::Type::Boolean
|
37
|
-
"T::Boolean"
|
38
|
-
when ActiveRecord::Type::DateTime, ActiveRecord::Type::Time
|
39
|
-
"::Time"
|
40
|
-
when ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter
|
41
|
-
"::ActiveSupport::TimeWithZone"
|
42
|
-
when ActiveRecord::Enum::EnumType
|
43
|
-
"::String"
|
44
|
-
when ActiveRecord::Type::Serialized
|
45
|
-
serialized_column_type(column_type)
|
46
|
-
else
|
47
|
-
handle_unknown_type(column_type)
|
48
|
-
end
|
22
|
+
getter_type = type_for_activerecord_value(column_type)
|
49
23
|
|
50
24
|
column = @constant.columns_hash[column_name]
|
51
25
|
setter_type =
|
@@ -71,6 +45,42 @@ module Tapioca
|
|
71
45
|
|
72
46
|
private
|
73
47
|
|
48
|
+
sig { params(column_type: T.untyped).returns(String) }
|
49
|
+
def type_for_activerecord_value(column_type)
|
50
|
+
case column_type
|
51
|
+
when defined?(MoneyColumn) && MoneyColumn::ActiveRecordType
|
52
|
+
"::Money"
|
53
|
+
when ActiveRecord::Type::Integer
|
54
|
+
"::Integer"
|
55
|
+
when ActiveRecord::Type::String
|
56
|
+
"::String"
|
57
|
+
when ActiveRecord::Type::Date
|
58
|
+
"::Date"
|
59
|
+
when ActiveRecord::Type::Decimal
|
60
|
+
"::BigDecimal"
|
61
|
+
when ActiveRecord::Type::Float
|
62
|
+
"::Float"
|
63
|
+
when ActiveRecord::Type::Boolean
|
64
|
+
"T::Boolean"
|
65
|
+
when ActiveRecord::Type::DateTime, ActiveRecord::Type::Time
|
66
|
+
"::Time"
|
67
|
+
when ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter
|
68
|
+
"::ActiveSupport::TimeWithZone"
|
69
|
+
when ActiveRecord::Enum::EnumType
|
70
|
+
"::String"
|
71
|
+
when ActiveRecord::Type::Serialized
|
72
|
+
serialized_column_type(column_type)
|
73
|
+
when defined?(ActiveRecord::ConnectionAdapters::PostgreSQL) &&
|
74
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Hstore
|
75
|
+
"T::Hash[::String, ::String]"
|
76
|
+
when defined?(ActiveRecord::ConnectionAdapters::PostgreSQL) &&
|
77
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array
|
78
|
+
"T::Array[#{type_for_activerecord_value(column_type.subtype)}]"
|
79
|
+
else
|
80
|
+
handle_unknown_type(column_type)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
74
84
|
sig { params(constant: Module).returns(T::Boolean) }
|
75
85
|
def do_not_generate_strong_types?(constant)
|
76
86
|
Object.const_defined?(:StrongTypeGeneration) &&
|
@@ -13,6 +13,7 @@ module Tapioca
|
|
13
13
|
|
14
14
|
AttributeMethodsModuleName = T.let("GeneratedAttributeMethods", String)
|
15
15
|
AssociationMethodsModuleName = T.let("GeneratedAssociationMethods", String)
|
16
|
+
DelegatedTypesModuleName = T.let("GeneratedDelegatedTypeMethods", String)
|
16
17
|
|
17
18
|
RelationMethodsModuleName = T.let("GeneratedRelationMethods", String)
|
18
19
|
AssociationRelationMethodsModuleName = T.let("GeneratedAssociationRelationMethods", String)
|
data/lib/tapioca/dsl/pipeline.rb
CHANGED
@@ -128,9 +128,11 @@ module Tapioca
|
|
128
128
|
def filter_anonymous_and_reloaded_constants(constants)
|
129
129
|
# Group constants by their names
|
130
130
|
constants_by_name = constants
|
131
|
-
.group_by { |c|
|
131
|
+
.group_by { |c| Runtime::Reflection.name_of(c) }
|
132
132
|
.select { |name, _| !name.nil? }
|
133
133
|
|
134
|
+
constants_by_name = T.cast(constants_by_name, T::Hash[String, T::Array[Module]])
|
135
|
+
|
134
136
|
# Find the constants that have been reloaded
|
135
137
|
reloaded_constants = constants_by_name.select { |_, constants| constants.size > 1 }.keys
|
136
138
|
|
@@ -7,16 +7,19 @@ module Tapioca
|
|
7
7
|
class YardDoc < Base
|
8
8
|
extend T::Sig
|
9
9
|
|
10
|
-
IGNORED_COMMENTS = T.let(
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
IGNORED_COMMENTS = T.let(
|
11
|
+
[
|
12
|
+
":doc:",
|
13
|
+
":nodoc:",
|
14
|
+
"typed:",
|
15
|
+
"frozen_string_literal:",
|
16
|
+
"encoding:",
|
17
|
+
"warn_indent:",
|
18
|
+
"shareable_constant_value:",
|
19
|
+
"rubocop:",
|
20
|
+
],
|
21
|
+
T::Array[String],
|
22
|
+
)
|
20
23
|
|
21
24
|
IGNORED_SIG_TAGS = T.let(["param", "return"], T::Array[String])
|
22
25
|
|
data/lib/tapioca/gem/pipeline.rb
CHANGED
@@ -241,8 +241,7 @@ module Tapioca
|
|
241
241
|
klass = class_of(value)
|
242
242
|
|
243
243
|
klass_name = if klass == ObjectSpace::WeakMap
|
244
|
-
|
245
|
-
"ObjectSpace::WeakMap[T.untyped]"
|
244
|
+
sorbet_supports?(:non_generic_weak_map) ? "ObjectSpace::WeakMap" : "ObjectSpace::WeakMap[T.untyped]"
|
246
245
|
elsif T::Generic === klass
|
247
246
|
generic_name_of(klass)
|
248
247
|
else
|
data/lib/tapioca/gemfile.rb
CHANGED
@@ -154,8 +154,12 @@ module Tapioca
|
|
154
154
|
|
155
155
|
IGNORED_GEMS = T.let(
|
156
156
|
[
|
157
|
-
"sorbet",
|
158
|
-
"
|
157
|
+
"sorbet",
|
158
|
+
"sorbet-static",
|
159
|
+
"sorbet-runtime",
|
160
|
+
"sorbet-static-and-runtime",
|
161
|
+
"debug",
|
162
|
+
"fakefs",
|
159
163
|
].freeze,
|
160
164
|
T::Array[String],
|
161
165
|
)
|
@@ -5,7 +5,7 @@ module Tapioca
|
|
5
5
|
module GemHelper
|
6
6
|
extend T::Sig
|
7
7
|
|
8
|
-
sig { params(app_dir: String, full_gem_path: String).returns(T::Boolean) }
|
8
|
+
sig { params(app_dir: T.any(String, Pathname), full_gem_path: String).returns(T::Boolean) }
|
9
9
|
def gem_in_app_dir?(app_dir, full_gem_path)
|
10
10
|
app_dir = to_realpath(app_dir)
|
11
11
|
full_gem_path = to_realpath(full_gem_path)
|
@@ -161,7 +161,8 @@ module Tapioca
|
|
161
161
|
RBI::Parser.parse_file(file)
|
162
162
|
rescue RBI::ParseError => e
|
163
163
|
say_error("\nWarning: #{e} (#{e.location})", :yellow)
|
164
|
-
|
164
|
+
nil
|
165
|
+
end.compact
|
165
166
|
|
166
167
|
index.visit_all(trees)
|
167
168
|
end
|
@@ -211,16 +212,22 @@ module Tapioca
|
|
211
212
|
|
212
213
|
sig { params(nodes: T::Array[RBI::Node]).returns(T::Array[T.any(RBI::Method, RBI::Attr)]) }
|
213
214
|
def extract_methods_and_attrs(nodes)
|
214
|
-
T.cast(
|
215
|
-
|
216
|
-
|
215
|
+
T.cast(
|
216
|
+
nodes.select do |node|
|
217
|
+
node.is_a?(RBI::Method) || node.is_a?(RBI::Attr)
|
218
|
+
end,
|
219
|
+
T::Array[T.any(RBI::Method, RBI::Attr)],
|
220
|
+
)
|
217
221
|
end
|
218
222
|
|
219
223
|
sig { params(nodes: T::Array[RBI::Node]).returns(T::Array[T.any(RBI::Mixin, RBI::RequiresAncestor)]) }
|
220
224
|
def extract_mixins(nodes)
|
221
|
-
T.cast(
|
222
|
-
|
223
|
-
|
225
|
+
T.cast(
|
226
|
+
nodes.select do |node|
|
227
|
+
node.is_a?(RBI::Mixin) || node.is_a?(RBI::RequiresAncestor)
|
228
|
+
end,
|
229
|
+
T::Array[T.all(RBI::Mixin, RBI::RequiresAncestor)],
|
230
|
+
)
|
224
231
|
end
|
225
232
|
|
226
233
|
sig { params(nodes: T::Array[T.any(RBI::Method, RBI::Attr)]).returns(T::Array[T.any(RBI::Method, RBI::Attr)]) }
|
@@ -19,9 +19,13 @@ module Tapioca
|
|
19
19
|
|
20
20
|
SORBET_PAYLOAD_URL = "https://github.com/sorbet/sorbet/tree/master/rbi"
|
21
21
|
|
22
|
-
FEATURE_REQUIREMENTS = T.let(
|
23
|
-
|
24
|
-
|
22
|
+
FEATURE_REQUIREMENTS = T.let(
|
23
|
+
{
|
24
|
+
# feature_name: ::Gem::Requirement.new(">= ___"), # https://github.com/sorbet/sorbet/pull/___
|
25
|
+
non_generic_weak_map: ::Gem::Requirement.new(">= 0.5.10587"), # https://github.com/sorbet/sorbet/pull/6610
|
26
|
+
}.freeze,
|
27
|
+
T::Hash[Symbol, ::Gem::Requirement],
|
28
|
+
)
|
25
29
|
|
26
30
|
sig { params(sorbet_args: String).returns(Spoom::ExecResult) }
|
27
31
|
def sorbet(*sorbet_args)
|
@@ -7,13 +7,16 @@ module URI
|
|
7
7
|
class Source < URI::File
|
8
8
|
extend T::Sig
|
9
9
|
|
10
|
-
COMPONENT = T.let(
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
COMPONENT = T.let(
|
11
|
+
[
|
12
|
+
:scheme,
|
13
|
+
:gem_name,
|
14
|
+
:gem_version,
|
15
|
+
:path,
|
16
|
+
:line_number,
|
17
|
+
].freeze,
|
18
|
+
T::Array[Symbol],
|
19
|
+
)
|
17
20
|
|
18
21
|
alias_method(:gem_name, :host)
|
19
22
|
alias_method(:line_number, :fragment)
|
data/lib/tapioca/loaders/gem.rb
CHANGED
@@ -18,10 +18,12 @@ module Tapioca
|
|
18
18
|
).void
|
19
19
|
end
|
20
20
|
def load_application(bundle:, prerequire:, postrequire:, default_command:)
|
21
|
-
loader = new(
|
21
|
+
loader = new(
|
22
|
+
bundle: bundle,
|
22
23
|
prerequire: prerequire,
|
23
24
|
postrequire: postrequire,
|
24
|
-
default_command: default_command
|
25
|
+
default_command: default_command,
|
26
|
+
)
|
25
27
|
loader.load
|
26
28
|
end
|
27
29
|
end
|
@@ -47,9 +47,12 @@ module Tapioca
|
|
47
47
|
|
48
48
|
eager_load_rails_app if eager_load
|
49
49
|
rescue LoadError, StandardError => e
|
50
|
-
say(
|
51
|
-
"
|
52
|
-
|
50
|
+
say(
|
51
|
+
"Tapioca attempted to load the Rails application after encountering a `config/application.rb` file, " \
|
52
|
+
"but it failed. If your application uses Rails please ensure it can be loaded correctly before " \
|
53
|
+
"generating RBIs.\n#{e}",
|
54
|
+
:yellow,
|
55
|
+
)
|
53
56
|
say("Continuing RBI generation without loading the Rails application.")
|
54
57
|
end
|
55
58
|
|
@@ -91,8 +91,13 @@ module RBI
|
|
91
91
|
return unless Tapioca::RBIHelper.valid_method_name?(name)
|
92
92
|
|
93
93
|
sig = RBI::Sig.new(return_type: return_type)
|
94
|
-
method = RBI::Method.new(
|
95
|
-
|
94
|
+
method = RBI::Method.new(
|
95
|
+
name,
|
96
|
+
sigs: [sig],
|
97
|
+
is_singleton: class_method,
|
98
|
+
visibility: visibility,
|
99
|
+
comments: comments,
|
100
|
+
)
|
96
101
|
parameters.each do |param|
|
97
102
|
method << param.param
|
98
103
|
sig << RBI::SigParam.new(param.param.name, param.type)
|
@@ -26,12 +26,15 @@ module Tapioca
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
DEFAULT_RBI_FORMATTER = T.let(
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
29
|
+
DEFAULT_RBI_FORMATTER = T.let(
|
30
|
+
RBIFormatter.new(
|
31
|
+
add_sig_templates: false,
|
32
|
+
group_nodes: true,
|
33
|
+
max_line_length: nil,
|
34
|
+
nest_singleton_methods: true,
|
35
|
+
nest_non_public_methods: true,
|
36
|
+
sort_nodes: true,
|
37
|
+
),
|
38
|
+
RBIFormatter,
|
39
|
+
)
|
37
40
|
end
|
@@ -13,6 +13,23 @@ module Tapioca
|
|
13
13
|
class << self
|
14
14
|
extend T::Sig
|
15
15
|
|
16
|
+
sig do
|
17
|
+
type_parameters(:Return)
|
18
|
+
.params(blk: T.proc.returns(T.type_parameter(:Return)))
|
19
|
+
.returns(T.type_parameter(:Return))
|
20
|
+
end
|
21
|
+
def with_trackers_enabled(&blk)
|
22
|
+
# Currently this is a dirty hack to ensure disabling trackers
|
23
|
+
# doesn't work while in the block passed to this method.
|
24
|
+
disable_all_method = method(:disable_all!)
|
25
|
+
define_singleton_method(:disable_all!) {}
|
26
|
+
blk.call
|
27
|
+
ensure
|
28
|
+
if disable_all_method
|
29
|
+
define_singleton_method(:disable_all!, disable_all_method)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
16
33
|
sig { void }
|
17
34
|
def disable_all!
|
18
35
|
@trackers.each(&:disable!)
|
@@ -62,8 +62,8 @@ module T
|
|
62
62
|
# we've created a clone of that type with the `name` method returning the
|
63
63
|
# appropriate name for that specific concrete type.
|
64
64
|
def name
|
65
|
-
if T::Generic === @raw_type
|
66
|
-
# for types that are generic
|
65
|
+
if T::Generic === @raw_type
|
66
|
+
# for types that are generic, use the name
|
67
67
|
# returned by the "name" method of this instance
|
68
68
|
@name ||= T.unsafe(@raw_type).name.freeze
|
69
69
|
else
|
@@ -78,20 +78,42 @@ module T
|
|
78
78
|
end
|
79
79
|
|
80
80
|
module Utils
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
val
|
87
|
-
|
88
|
-
|
81
|
+
# This duplication is required to preserve backwards compatibility with sorbet-runtime versions prior to the
|
82
|
+
# introduction of the `Private` module in https://github.com/sorbet/sorbet/pull/6559.
|
83
|
+
if defined?(T::Utils::Private)
|
84
|
+
module Private
|
85
|
+
module PrivateCoercePatch
|
86
|
+
def coerce_and_check_module_types(val, check_val, check_module_type)
|
87
|
+
if val.is_a?(Tapioca::TypeVariableModule)
|
88
|
+
val.coerce_to_type_variable
|
89
|
+
elsif val.respond_to?(:__tapioca_override_type)
|
90
|
+
val.__tapioca_override_type
|
91
|
+
else
|
92
|
+
super
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class << self
|
98
|
+
prepend(PrivateCoercePatch)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
else
|
102
|
+
module CoercePatch
|
103
|
+
def coerce(val)
|
104
|
+
if val.is_a?(Tapioca::TypeVariableModule)
|
105
|
+
val.coerce_to_type_variable
|
106
|
+
elsif val.respond_to?(:__tapioca_override_type)
|
107
|
+
val.__tapioca_override_type
|
108
|
+
else
|
109
|
+
super
|
110
|
+
end
|
89
111
|
end
|
90
112
|
end
|
91
|
-
end
|
92
113
|
|
93
|
-
|
94
|
-
|
114
|
+
class << self
|
115
|
+
prepend(CoercePatch)
|
116
|
+
end
|
95
117
|
end
|
96
118
|
end
|
97
119
|
end
|
data/lib/tapioca/version.rb
CHANGED
data/lib/tapioca.rb
CHANGED
@@ -43,11 +43,14 @@ module Tapioca
|
|
43
43
|
DEFAULT_TODO_FILE = T.let("#{DEFAULT_RBI_DIR}/todo.rbi", String)
|
44
44
|
DEFAULT_ANNOTATIONS_DIR = T.let("#{DEFAULT_RBI_DIR}/annotations", String)
|
45
45
|
|
46
|
-
DEFAULT_OVERRIDES = T.let(
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
DEFAULT_OVERRIDES = T.let(
|
47
|
+
{
|
48
|
+
# ActiveSupport overrides some core methods with different signatures
|
49
|
+
# so we generate a typed: false RBI for it to suppress errors
|
50
|
+
"activesupport" => "false",
|
51
|
+
}.freeze,
|
52
|
+
T::Hash[String, String],
|
53
|
+
)
|
51
54
|
|
52
55
|
DEFAULT_RBI_MAX_LINE_LENGTH = 120
|
53
56
|
DEFAULT_ENVIRONMENT = "development"
|
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.10.
|
4
|
+
version: 0.10.5
|
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:
|
14
|
+
date: 2023-01-04 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -81,14 +81,14 @@ dependencies:
|
|
81
81
|
requirements:
|
82
82
|
- - ">="
|
83
83
|
- !ruby/object:Gem::Version
|
84
|
-
version: 0.5.
|
84
|
+
version: 0.5.10187
|
85
85
|
type: :runtime
|
86
86
|
prerelease: false
|
87
87
|
version_requirements: !ruby/object:Gem::Requirement
|
88
88
|
requirements:
|
89
89
|
- - ">="
|
90
90
|
- !ruby/object:Gem::Version
|
91
|
-
version: 0.5.
|
91
|
+
version: 0.5.10187
|
92
92
|
- !ruby/object:Gem::Dependency
|
93
93
|
name: spoom
|
94
94
|
requirement: !ruby/object:Gem::Requirement
|
@@ -171,6 +171,7 @@ files:
|
|
171
171
|
- lib/tapioca/dsl/compilers/active_model_secure_password.rb
|
172
172
|
- lib/tapioca/dsl/compilers/active_record_associations.rb
|
173
173
|
- lib/tapioca/dsl/compilers/active_record_columns.rb
|
174
|
+
- lib/tapioca/dsl/compilers/active_record_delegated_types.rb
|
174
175
|
- lib/tapioca/dsl/compilers/active_record_enum.rb
|
175
176
|
- lib/tapioca/dsl/compilers/active_record_fixtures.rb
|
176
177
|
- lib/tapioca/dsl/compilers/active_record_relations.rb
|
@@ -192,6 +193,7 @@ files:
|
|
192
193
|
- lib/tapioca/dsl/compilers/smart_properties.rb
|
193
194
|
- lib/tapioca/dsl/compilers/state_machines.rb
|
194
195
|
- lib/tapioca/dsl/compilers/url_helpers.rb
|
196
|
+
- lib/tapioca/dsl/extensions/active_record.rb
|
195
197
|
- lib/tapioca/dsl/extensions/frozen_record.rb
|
196
198
|
- lib/tapioca/dsl/helpers/active_record_column_type_helper.rb
|
197
199
|
- lib/tapioca/dsl/helpers/active_record_constants_helper.rb
|