tapioca 0.10.3 → 0.10.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c5b81fee880c497fca1e34c644d6da53e4f155e45f564c95eb886f0f6c30d69
4
- data.tar.gz: d0973ab750b577064e5891c0fbd9dd71ddeb82b54d7d8dfcabad4841052e8d6d
3
+ metadata.gz: bbed9bfddb52a94735d9455ed4351c4ef1389236ceba2e19ce46d999a05536b0
4
+ data.tar.gz: b1a35528c1e9cfa5fd735a64d4988bfd72c0f980835d58e4a37c62d5694e3daa
5
5
  SHA512:
6
- metadata.gz: 105ab9194d3e62657fedff6d0fd78b187980b5084af80be294690c00a86ac1544b29bd9d86951f50072c895516ce1541251ac2ff05cbb3a2acbbee5d0e103b51
7
- data.tar.gz: 612f856fd4b36301dbfee4cdd80615ee4a684447ea077037c5a72e1c7c216be7c465aae13a5b4462a8db9889929765703293d2935036d7ac1e94b8d21d4ee5fb
6
+ metadata.gz: 6138060ec0cea66dda6f96484329626d613494404cf99f851d1dbd59249546ffdfa0b0dd58236ef63d65b93acd250eb3a46b5a3eb1a3f8491014125b18a50800
7
+ data.tar.gz: 266205a5dd212e87836d1d26f1f018ab83d64aaacc9b793e9a01b88c6213bda834991194896a602ce6f267ef96e3ef8f78d14464005cefcfc010bb666ddc6f3e
data/exe/tapioca CHANGED
@@ -3,19 +3,21 @@
3
3
 
4
4
  require "sorbet-runtime"
5
5
 
6
- begin
7
- T::Configuration.default_checked_level = :never
8
- # Suppresses call validation errors
9
- T::Configuration.call_validation_error_handler = ->(*) {}
10
- # Suppresses errors caused by T.cast, T.let, T.must, etc.
11
- T::Configuration.inline_type_error_handler = ->(*) {}
12
- # Suppresses errors caused by incorrect parameter ordering
13
- T::Configuration.sig_validation_error_handler = ->(*) {}
14
- rescue
15
- # Need this rescue so that if another gem has
16
- # already set the checked level by the time we
17
- # get to it, we don't fail outright.
18
- nil
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"
@@ -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 boostrap this list)
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
@@ -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 = "void" if return_type == "<VOID>"
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
@@ -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
@@ -217,6 +217,7 @@ module Tapioca
217
217
  T::Array[Symbol],
218
218
  )
219
219
  FINDER_METHODS = T.let(ActiveRecord::FinderMethods.instance_methods(false), T::Array[Symbol])
220
+ SIGNED_FINDER_METHODS = T.let(ActiveRecord::SignedId::ClassMethods.instance_methods(false), T::Array[Symbol])
220
221
  CALCULATION_METHODS = T.let(ActiveRecord::Calculations.instance_methods(false), T::Array[Symbol])
221
222
  ENUMERABLE_QUERY_METHODS = T.let([:any?, :many?, :none?, :one?], T::Array[Symbol])
222
223
  FIND_OR_CREATE_METHODS = T.let(
@@ -593,6 +594,31 @@ module Tapioca
593
594
  end
594
595
  end
595
596
 
597
+ SIGNED_FINDER_METHODS.each do |method_name|
598
+ case method_name
599
+ when :find_signed
600
+ create_common_method(
601
+ "find_signed",
602
+ common_relation_methods_module,
603
+ parameters: [
604
+ create_param("signed_id", type: "T.untyped"),
605
+ create_kw_opt_param("purpose", type: "T.untyped", default: "nil"),
606
+ ],
607
+ return_type: as_nilable_type(constant_name),
608
+ )
609
+ when :find_signed!
610
+ create_common_method(
611
+ "find_signed!",
612
+ common_relation_methods_module,
613
+ parameters: [
614
+ create_param("signed_id", type: "T.untyped"),
615
+ create_kw_opt_param("purpose", type: "T.untyped", default: "nil"),
616
+ ],
617
+ return_type: constant_name,
618
+ )
619
+ end
620
+ end
621
+
596
622
  CALCULATION_METHODS.each do |method_name|
597
623
  case method_name
598
624
  when :average, :maximum, :minimum
@@ -284,6 +284,11 @@ module Tapioca
284
284
  return_type: "void",
285
285
  )
286
286
 
287
+ klass.create_method(
288
+ "clear_#{field.name}",
289
+ return_type: "void",
290
+ )
291
+
287
292
  field
288
293
  end
289
294
 
@@ -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
@@ -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)
@@ -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| T.must(Runtime::Reflection.name_of(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
 
@@ -241,8 +241,7 @@ module Tapioca
241
241
  klass = class_of(value)
242
242
 
243
243
  klass_name = if klass == ObjectSpace::WeakMap
244
- # WeakMap is an implicit generic with one type variable
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
@@ -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
- end
164
+ nil
165
+ end.compact
165
166
 
166
167
  index.visit_all(trees)
167
168
  end
@@ -21,6 +21,7 @@ module Tapioca
21
21
 
22
22
  FEATURE_REQUIREMENTS = T.let({
23
23
  # feature_name: ::Gem::Requirement.new(">= ___"), # https://github.com/sorbet/sorbet/pull/___
24
+ non_generic_weak_map: ::Gem::Requirement.new(">= 0.5.10587"), # https://github.com/sorbet/sorbet/pull/6610
24
25
  }.freeze, T::Hash[Symbol, ::Gem::Requirement])
25
26
 
26
27
  sig { params(sorbet_args: String).returns(Spoom::ExecResult) }
@@ -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 || Tapioca::TypeVariableModule === @raw_type
66
- # for types that are generic or are type variables, use the name
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
- module CoercePatch
82
- def coerce(val)
83
- if val.is_a?(Tapioca::TypeVariableModule)
84
- val.coerce_to_type_variable
85
- elsif val.respond_to?(:__tapioca_override_type)
86
- val.__tapioca_override_type
87
- else
88
- super
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
- class << self
94
- prepend(CoercePatch)
114
+ class << self
115
+ prepend(CoercePatch)
116
+ end
95
117
  end
96
118
  end
97
119
  end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.10.3"
5
+ VERSION = "0.10.4"
6
6
  end
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.3
4
+ version: 0.10.4
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: 2022-11-10 00:00:00.000000000 Z
14
+ date: 2022-12-19 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.9892
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.9892
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