delayed 3.0.1 → 3.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2078916c01265f24d3f7bb05ef6bb752dae563413973d4efaf8622bb3c7a40bf
4
- data.tar.gz: d388130dd48000d4148eeb5246e8975989b45e106d144fcbea7ffbc140fb0e4e
3
+ metadata.gz: 40ac1d14d7043c15029a5e563ad4e278315f50cd99d947b97ecb5205cde483fa
4
+ data.tar.gz: 0e4d7ffd516267c28a2b2ab6468cfe383a5c486aaf4875ffeb92b72797af9e29
5
5
  SHA512:
6
- metadata.gz: f624aabb72e24fb49b8f81e1bf90562a6dd62354f5145ea6ff693d08b13a4089ef03a17544cc26359d5ef0891fdc2e1bdd6d82e7fc683684cb6006aefd12f8d3
7
- data.tar.gz: c1a3066fcd79c66b0b264467364a9640d0854fe5a08cd61a4ed305ba23c3998afb9297775a7d49a9a2761799dc9bf56497173e73f618ddee8a3991303d2cff0e
6
+ metadata.gz: bfa5833f65f57e02447e6ace001d8cd0be205399ab5a108f1cc2d7ef13ce749b99b557f3bd36a79a9e4cb6e0ef37bd6c11746318013c9f084626a96b2fd4b1a4
7
+ data.tar.gz: 8aa12f59cbf61b68881853351cb19af8ff8b391014e3eacafe8f78e556dcf98bbde2a918fdb0b24386ea95d72d14ec43ec4a1af98db60ee297c4d31db071139a
@@ -70,10 +70,12 @@ module Delayed
70
70
  def names=(names)
71
71
  raise "must include a name for priority >= 0" if names && !names.value?(0)
72
72
 
73
+ remove_named_priority_methods
73
74
  @ranges = nil
74
75
  @alerts = nil
75
76
  @names_to_priority = nil
76
77
  @names = names&.sort_by(&:last)&.to_h&.transform_values { |v| new(v) }
78
+ define_named_priority_methods
77
79
  end
78
80
 
79
81
  def alerts=(alerts)
@@ -124,17 +126,35 @@ module Delayed
124
126
  low + ((high - low).to_d / 2).ceil
125
127
  end
126
128
 
127
- def respond_to_missing?(method_name, include_private = false)
128
- names_to_priority.key?(method_name) || super
129
+ # Defines a class method (e.g. `Priority.eventual`) and an instance predicate (e.g.
130
+ # `priority.eventual?`) per name, as real, introspectable methods (visible to `methods`,
131
+ # RDoc, and Sorbet's tapioca, unlike `method_missing` dispatch). Pre-existing methods
132
+ # (e.g. a name of `superclass`) are never overridden.
133
+ def define_named_priority_methods
134
+ names.each_key do |name|
135
+ predicate = :"#{name}?"
136
+ define_singleton_method(name) { names_to_priority.fetch(name) } unless method_defined_on?(singleton_class, name)
137
+ define_method(predicate) { name.to_s == to_s } unless method_defined_on?(self, predicate)
138
+ end
129
139
  end
130
140
 
131
- def method_missing(method_name, *args)
132
- if names_to_priority.key?(method_name) && args.none?
133
- names_to_priority[method_name]
134
- else
135
- super
141
+ # Removes the methods previously defined for the current `names` (called before `names` is
142
+ # reassigned). The non-inherited (`false`) checks mean we only remove methods we defined
143
+ # ourselves, leaving any pre-existing method a colliding name never overrode (e.g.
144
+ # `Class#superclass`, `Numeric#zero?`) in place.
145
+ def remove_named_priority_methods
146
+ names.each_key do |name|
147
+ predicate = :"#{name}?"
148
+ singleton_class.send(:remove_method, name) if singleton_class.method_defined?(name, false)
149
+ remove_method(predicate) if method_defined?(predicate, false)
136
150
  end
137
151
  end
152
+
153
+ # Whether `mod` already responds to `name` (public, protected, private, or inherited), in
154
+ # which case a same-named priority must not override it.
155
+ def method_defined_on?(mod, name)
156
+ mod.method_defined?(name) || mod.private_method_defined?(name)
157
+ end
138
158
  end
139
159
 
140
160
  attr_reader :value
@@ -188,18 +208,6 @@ module Delayed
188
208
  to_i.to_d
189
209
  end
190
210
 
191
- private
192
-
193
- def respond_to_missing?(method_name, include_private = false)
194
- (method_name.to_s.end_with?('?') && self.class.names.key?(method_name.to_s[0..-2].to_sym)) || super
195
- end
196
-
197
- def method_missing(method_name, *args)
198
- if method_name.to_s.end_with?('?') && self.class.names.key?(method_name.to_s[0..-2].to_sym)
199
- method_name.to_s[0..-2] == to_s
200
- else
201
- super
202
- end
203
- end
211
+ send(:define_named_priority_methods)
204
212
  end
205
213
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delayed
4
- VERSION = '3.0.1'
4
+ VERSION = '3.1.0'
5
5
  end
@@ -13,9 +13,10 @@ RSpec.describe Delayed::Priority do
13
13
  ensure
14
14
  described_class.alerts = nil
15
15
  described_class.names = nil
16
+ described_class.assign_at_midpoint = nil
16
17
  end
17
18
 
18
- describe '.names, .ranges, .alerts, .names_to_priority, method_missing' do
19
+ describe '.names, .ranges, .alerts, .names_to_priority, named priority methods' do
19
20
  it 'defaults to interactive, user_visible, eventual, reporting' do
20
21
  expect(described_class.names).to eq(
21
22
  interactive: 0,
@@ -68,6 +69,34 @@ RSpec.describe Delayed::Priority do
68
69
  end
69
70
  end
70
71
 
72
+ it 'defines named priority methods as real, introspectable methods' do
73
+ expect(described_class.singleton_class.method_defined?(:eventual)).to be true
74
+ expect(described_class.method_defined?(:eventual?)).to be true
75
+ end
76
+
77
+ it 'removes methods for the old names when names are reassigned' do
78
+ described_class.names = { high: 0 }
79
+ expect(described_class).to respond_to(:high)
80
+ expect(described_class.new(0)).to be_high
81
+
82
+ described_class.names = nil
83
+ expect(described_class).not_to respond_to(:high)
84
+ expect(described_class.new(0)).not_to respond_to(:high?)
85
+ expect(described_class).to respond_to(:interactive)
86
+ expect(described_class.new(0)).to be_interactive
87
+ end
88
+
89
+ context 'when a name collides with an existing method' do
90
+ let(:custom_names) { { superclass: 0, zero: 10 } }
91
+
92
+ it 'does not redefine the existing method' do
93
+ expect(described_class.superclass).to eq Numeric # Class#superclass, not the priority
94
+ expect(described_class.new(0).zero?).to be true # Numeric#zero?, not the range predicate
95
+ expect(described_class.zero).to eq 10
96
+ expect(described_class.new(5).superclass?).to be true
97
+ end
98
+ end
99
+
71
100
  context 'when customized to high, medium, low' do
72
101
  let(:custom_names) { { high: 0, medium: 100, low: 500 } }
73
102
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Griffith
@@ -19,7 +19,7 @@ authors:
19
19
  autorequire:
20
20
  bindir: bin
21
21
  cert_chain: []
22
- date: 2026-06-15 00:00:00.000000000 Z
22
+ date: 2026-07-13 00:00:00.000000000 Z
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
25
25
  name: activerecord