tapioca 0.10.3 → 0.10.4

Sign up to get free protection for your applications and to get access to all the features.
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