tapioca 0.16.2 → 0.16.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: cc2c2c6ae059634316e511dce8839f7e4930b0263093e6250612aa7d6aae582d
4
- data.tar.gz: 7ee41089cca733c46e3d3c9dca9384c1e8a516fd7ebb0fb347eb31935da8d3ee
3
+ metadata.gz: 80c01f44b0600c3a471756da73e43322f23a951c8f3ebc15c922173a0ccf4d3c
4
+ data.tar.gz: c778cfa78b0494513f5ad329e432c534486c3ba75fcf83969462a874c7dc7654
5
5
  SHA512:
6
- metadata.gz: 00ecd9606853f9bf27821df7c20b74af4898d84d5b3a32472a5156c2d0ba353b4ab53e7ddc4d21474a2b1599409aecad05693ac6713100798a4cf77dc2d50b83
7
- data.tar.gz: 4b8d2455cf3cd89c0744d4e266331ee61c3ca585380db1da348bafaa014fbeaa7483401100f1148f8c89fe21119c9a555e9af86be3699ba2733f48cab1929901
6
+ metadata.gz: f12a7fbe0d64109a5de03d8a98f564413bee79dc0db1ced8c1eaeae8dae73e68c73e8e76a188a06ddfefa333b11024d606359b7f706d13e15dacea081b0a19ea
7
+ data.tar.gz: 99ef8194c8dab5e776b591992aefa8b59b0b8e2d8927caecfc68d63bf7bb4c7687a92af772c6f8ac5fcfbdd8ebe1f9c1b748a2334b8207d233939d35d02d2b26
@@ -25,6 +25,8 @@ module Tapioca
25
25
  sig { returns(T::Hash[String, T.untyped]) }
26
26
  attr_reader :options
27
27
 
28
+ @@requested_constants = T.let([], T::Array[Module]) # rubocop:disable Style/ClassVars
29
+
28
30
  class << self
29
31
  extend T::Sig
30
32
 
@@ -44,12 +46,39 @@ module Tapioca
44
46
  )
45
47
  end
46
48
 
49
+ sig { params(constants: T::Array[Module]).void }
50
+ def requested_constants=(constants)
51
+ @@requested_constants = constants # rubocop:disable Style/ClassVars
52
+ end
53
+
47
54
  private
48
55
 
56
+ sig do
57
+ type_parameters(:U)
58
+ .params(klass: T.all(T::Class[T.anything], T.type_parameter(:U)))
59
+ .returns(T::Array[T.type_parameter(:U)])
60
+ end
61
+ def descendants_of(klass)
62
+ if @@requested_constants.any?
63
+ T.cast(
64
+ @@requested_constants.select do |k|
65
+ k < klass && !k.singleton_class?
66
+ end,
67
+ T::Array[T.type_parameter(:U)],
68
+ )
69
+ else
70
+ super
71
+ end
72
+ end
73
+
49
74
  sig { returns(T::Enumerable[T::Class[T.anything]]) }
50
75
  def all_classes
51
76
  @all_classes ||= T.let(
52
- ObjectSpace.each_object(Class),
77
+ if @@requested_constants.any?
78
+ @@requested_constants.grep(Class)
79
+ else
80
+ ObjectSpace.each_object(Class)
81
+ end,
53
82
  T.nilable(T::Enumerable[T::Class[T.anything]]),
54
83
  )
55
84
  end
@@ -57,7 +86,11 @@ module Tapioca
57
86
  sig { returns(T::Enumerable[Module]) }
58
87
  def all_modules
59
88
  @all_modules ||= T.let(
60
- ObjectSpace.each_object(Module),
89
+ if @@requested_constants.any?
90
+ @@requested_constants.select { |k| k.is_a?(Module) }
91
+ else
92
+ ObjectSpace.each_object(Module)
93
+ end,
61
94
  T.nilable(T::Enumerable[Module]),
62
95
  )
63
96
  end
@@ -69,6 +69,17 @@ module Tapioca
69
69
  T::Array[String],
70
70
  )
71
71
 
72
+ TRANSITION_CALLBACKS =
73
+ T.let(
74
+ [
75
+ "on_transition",
76
+ "guard",
77
+ "after",
78
+ "success",
79
+ ].freeze,
80
+ T::Array[String],
81
+ )
82
+
72
83
  ConstantType = type_member { { fixed: T.all(T::Class[::AASM], ::AASM::ClassMethods) } }
73
84
 
74
85
  sig { override.void }
@@ -162,8 +173,37 @@ module Tapioca
162
173
  method,
163
174
  parameters: [
164
175
  create_opt_param("symbol", type: "T.nilable(Symbol)", default: "nil"),
165
- create_block_param("block", type: "T.nilable(T.proc.bind(#{constant_name}).void)"),
176
+ create_block_param(
177
+ "block",
178
+ type: "T.nilable(T.proc.bind(#{constant_name}).params(opts: T.untyped).void)",
179
+ ),
180
+ ],
181
+ )
182
+ end
183
+
184
+ event.create_method(
185
+ "transitions",
186
+ parameters: [
187
+ create_opt_param("definitions", default: "nil", type: "T.untyped"),
188
+ create_block_param("block", type: "T.nilable(T.proc.bind(PrivateAASMTransition).void)"),
189
+ ],
190
+ )
191
+ end
192
+
193
+ machine.create_class("PrivateAASMTransition", superclass_name: "AASM::Core::Transition") do |transition|
194
+ TRANSITION_CALLBACKS.each do |method|
195
+ return_type = "T.untyped"
196
+ return_type = "T::Boolean" if method == "guard"
197
+
198
+ transition.create_method(
199
+ method,
200
+ parameters: [
201
+ create_block_param(
202
+ "block",
203
+ type: "T.nilable(T.proc.bind(#{constant_name}).params(opts: T.untyped).void)",
204
+ ),
166
205
  ],
206
+ return_type: return_type,
167
207
  )
168
208
  end
169
209
  end
@@ -88,17 +88,24 @@ module Tapioca
88
88
  sig { returns([String, String]) }
89
89
  def id_type
90
90
  if @constant.respond_to?(:composite_primary_key?) && T.unsafe(@constant).composite_primary_key?
91
- @constant.primary_key.map do |column|
92
- column_type_for(column)
93
- end.map do |tuple|
94
- "[#{tuple.join(", ")}]"
91
+ primary_key_columns = @constant.primary_key
92
+
93
+ getters = []
94
+ setters = []
95
+
96
+ primary_key_columns.each do |column|
97
+ getter, setter = column_type_for(column)
98
+ getters << getter
99
+ setters << setter
95
100
  end
101
+
102
+ ["[#{getters.join(", ")}]", "[#{setters.join(", ")}]"]
96
103
  else
97
104
  column_type_for(@constant.primary_key)
98
105
  end
99
106
  end
100
107
 
101
- sig { params(column_name: String).returns([String, String]) }
108
+ sig { params(column_name: T.nilable(String)).returns([String, String]) }
102
109
  def column_type_for(column_name)
103
110
  return ["T.untyped", "T.untyped"] if @column_type_option.untyped?
104
111
 
@@ -179,11 +186,31 @@ module Tapioca
179
186
  ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Hstore === type
180
187
  }
181
188
  "T::Hash[::String, ::String]"
189
+ when ->(type) {
190
+ defined?(ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Interval) &&
191
+ ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Interval === type
192
+ }
193
+ "::ActiveSupport::Duration"
182
194
  when ->(type) {
183
195
  defined?(ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array) &&
184
196
  ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array === type
185
197
  }
186
198
  "T::Array[#{type_for_activerecord_value(column_type.subtype, column_nullability:)}]"
199
+ when ->(type) {
200
+ defined?(ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bit) &&
201
+ ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bit === type
202
+ }
203
+ "::String"
204
+ when ->(type) {
205
+ defined?(ActiveRecord::ConnectionAdapters::PostgreSQL::OID::BitVarying) &&
206
+ ActiveRecord::ConnectionAdapters::PostgreSQL::OID::BitVarying === type
207
+ }
208
+ "::String"
209
+ when ->(type) {
210
+ defined?(ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Range) &&
211
+ ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Range === type
212
+ }
213
+ "T::Range[#{type_for_activerecord_value(column_type.subtype, column_nullability:)}]"
187
214
  else
188
215
  as_non_nilable_if_persisted_and_not_nullable(
189
216
  ActiveModelTypeHelper.type_for(column_type),
@@ -145,6 +145,7 @@ module Tapioca
145
145
  ).returns(T::Set[Module])
146
146
  end
147
147
  def gather_constants(requested_constants, requested_paths, skipped_constants)
148
+ Compiler.requested_constants = requested_constants
148
149
  constants = Set.new.compare_by_identity
149
150
  active_compilers.each do |compiler|
150
151
  constants.merge(compiler.processable_constants)
@@ -107,36 +107,12 @@ module Tapioca
107
107
 
108
108
  sig { params(name: String).returns(T::Boolean) }
109
109
  def valid_method_name?(name)
110
- # try to parse a method definition with this name
111
- iseq = RubyVM::InstructionSequence.compile("def #{name}; end", nil, nil, 0, false)
112
- # pull out the first operation in the instruction sequence and its first argument
113
- op, arg, _data = iseq.to_a.dig(-1, 0)
114
- # make sure that the operation is a method definition and the method that was
115
- # defined has the expected name, for example, for `def !foo; end` we don't get
116
- # a syntax error but instead get a method defined as `"foo"`
117
- op == :definemethod && arg == name.to_sym
118
- rescue SyntaxError
119
- false
110
+ Prism.parse_success?("def self.#{name}(a); end")
120
111
  end
121
112
 
122
113
  sig { params(name: String).returns(T::Boolean) }
123
114
  def valid_parameter_name?(name)
124
- sentinel_method_name = :sentinel_method_name
125
- # try to parse a method definition with this name as the name of a
126
- # keyword parameter. If we use a positional parameter, then parameter names
127
- # like `&` (and maybe others) will be treated like `def foo(&); end` and will
128
- # thus be considered valid. Using a required keyword parameter prevents that
129
- # confusion between Ruby syntax and parameter name.
130
- iseq = RubyVM::InstructionSequence.compile("def #{sentinel_method_name}(#{name}:); end", nil, nil, 0, false)
131
- # pull out the first operation in the instruction sequence and its first argument and data
132
- op, arg, data = iseq.to_a.dig(-1, 0)
133
- # make sure that:
134
- # 1. a method was defined, and
135
- # 2. the method has the expected method name, and
136
- # 3. the method has a keyword parameter with the expected name
137
- op == :definemethod && arg == sentinel_method_name && data.dig(11, :keyword, 0) == name.to_sym
138
- rescue SyntaxError
139
- false
115
+ Prism.parse_success?("def sentinel_method_name(#{name}:); end")
140
116
  end
141
117
  end
142
118
  end
@@ -18,6 +18,13 @@ module URI
18
18
  T::Array[Symbol],
19
19
  )
20
20
 
21
+ # `uri` for Ruby 3.4 switched the default parser from RFC2396 to RFC3986. The new parser emits a deprecation
22
+ # warning on a few methods and delegates them to RFC2396, namely `extract`/`make_regexp`/`escape`/`unescape`.
23
+ # On earlier versions of the uri gem, the RFC2396_PARSER constant doesn't exist, so it needs some special
24
+ # handling to select a parser that doesn't emit deprecations. While it was backported to Ruby 3.1, users may
25
+ # have the uri gem in their own bundle and thus not use a compatible version.
26
+ PARSER = T.let(const_defined?(:RFC2396_PARSER) ? RFC2396_PARSER : DEFAULT_PARSER, RFC2396_Parser)
27
+
21
28
  alias_method(:gem_name, :host)
22
29
  alias_method(:line_number, :fragment)
23
30
 
@@ -40,7 +47,7 @@ module URI
40
47
  {
41
48
  scheme: "source",
42
49
  host: gem_name,
43
- path: DEFAULT_PARSER.escape("/#{gem_version}/#{path}"),
50
+ path: PARSER.escape("/#{gem_version}/#{path}"),
44
51
  fragment: line_number,
45
52
  }
46
53
  )
@@ -23,6 +23,7 @@ require "tempfile"
23
23
  require "thor"
24
24
  require "yaml"
25
25
  require "yard-sorbet"
26
+ require "prism"
26
27
 
27
28
  require "tapioca/runtime/dynamic_mixin_compiler"
28
29
  require "tapioca/sorbet_ext/backcompat_patches"
@@ -178,13 +178,19 @@ module Tapioca
178
178
  end
179
179
 
180
180
  # Examines the call stack to identify the closest location where a "require" is performed
181
- # by searching for the label "<top (required)>". If none is found, it returns the location
181
+ # by searching for the label "<top (required)>" or "block in <class:...>" in the
182
+ # case of an ActiveSupport.on_load hook. If none is found, it returns the location
182
183
  # labeled "<main>", which is the original call site.
183
184
  sig { params(locations: T.nilable(T::Array[Thread::Backtrace::Location])).returns(String) }
184
185
  def resolve_loc(locations)
185
186
  return "" unless locations
186
187
 
187
- resolved_loc = locations.find { |loc| REQUIRED_FROM_LABELS.include?(loc.label) }
188
+ resolved_loc = locations.find do |loc|
189
+ label = loc.label
190
+ next unless label
191
+
192
+ REQUIRED_FROM_LABELS.include?(label) || label.start_with?("block in <class:")
193
+ end
188
194
  return "" unless resolved_loc
189
195
 
190
196
  resolved_loc.absolute_path || ""
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.16.2"
5
+ VERSION = "0.16.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.16.2
4
+ version: 0.16.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: 2024-08-29 00:00:00.000000000 Z
14
+ date: 2024-11-07 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -284,7 +284,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
284
284
  - !ruby/object:Gem::Version
285
285
  version: '0'
286
286
  requirements: []
287
- rubygems_version: 3.5.17
287
+ rubygems_version: 3.5.23
288
288
  signing_key:
289
289
  specification_version: 4
290
290
  summary: A Ruby Interface file generator for gems, core types and the Ruby standard