From d5e43b4e42fb85fd338bcede068d5332df76f31a Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Tue, 22 Dec 2020 11:28:16 +0100 Subject: [PATCH 01/13] * Support for Ruby 3.0 added --- lib/delayed/performable_mailer.rb | 2 +- lib/delayed/performable_method.rb | 32 +++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/delayed/performable_mailer.rb b/lib/delayed/performable_mailer.rb index 8535c452d..7c5d6d7b0 100644 --- a/lib/delayed/performable_mailer.rb +++ b/lib/delayed/performable_mailer.rb @@ -3,7 +3,7 @@ module Delayed class PerformableMailer < PerformableMethod def perform - mailer = object.send(method_name, *args) + mailer = super mailer.respond_to?(:deliver_now) ? mailer.deliver_now : mailer.deliver end end diff --git a/lib/delayed/performable_method.rb b/lib/delayed/performable_method.rb index 96a28b056..7941d3826 100644 --- a/lib/delayed/performable_method.rb +++ b/lib/delayed/performable_method.rb @@ -22,8 +22,26 @@ def display_name end end - def perform - object.send(method_name, *args) if object + if RUBY_VERSION >= '3.0' + def perform + if args_is_a_hash? + object.send(method_name, **args.first) + else + object.send(method_name, *args) + end if object + rescue => e + p e.message + p args + raise e + end + + def args_is_a_hash? + args.size == 1 && args.first.is_a?(Hash) + end + else + def perform + object.send(method_name, *args) if object + end end def method(sym) @@ -31,8 +49,14 @@ def method(sym) end # rubocop:disable MethodMissing - def method_missing(symbol, *args) - object.send(symbol, *args) + if RUBY_VERSION >= '3.0' + def method_missing(symbol, ...) + object.send(symbol, ...) + end + else + def method_missing(symbol, *args) + object.send(symbol, *args) + end end # rubocop:enable MethodMissing From 7c73130d74f4628d9c6bc500e0fae0e14842bf84 Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Tue, 22 Dec 2020 15:01:19 +0100 Subject: [PATCH 02/13] * debug messages commented out --- lib/delayed/performable_method.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/delayed/performable_method.rb b/lib/delayed/performable_method.rb index 7941d3826..b5315717b 100644 --- a/lib/delayed/performable_method.rb +++ b/lib/delayed/performable_method.rb @@ -29,10 +29,10 @@ def perform else object.send(method_name, *args) end if object - rescue => e - p e.message - p args - raise e +# rescue => e +# p e.message +# p args +# raise e end def args_is_a_hash? From bfdabfe68134202f302507b3db1567d910386623 Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Tue, 22 Dec 2020 15:25:35 +0100 Subject: [PATCH 03/13] * syntax fixed --- lib/delayed/performable_method.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/delayed/performable_method.rb b/lib/delayed/performable_method.rb index b5315717b..1cb192ac2 100644 --- a/lib/delayed/performable_method.rb +++ b/lib/delayed/performable_method.rb @@ -50,8 +50,8 @@ def method(sym) # rubocop:disable MethodMissing if RUBY_VERSION >= '3.0' - def method_missing(symbol, ...) - object.send(symbol, ...) + def method_missing(...) + object.send(...) end else def method_missing(symbol, *args) From 90faa82d9fc1f65a610f981eb4401f220ad9e9c6 Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Tue, 22 Dec 2020 15:51:56 +0100 Subject: [PATCH 04/13] * Syntax fixed --- lib/delayed/performable_method.rb | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/delayed/performable_method.rb b/lib/delayed/performable_method.rb index 1cb192ac2..c13c8a00c 100644 --- a/lib/delayed/performable_method.rb +++ b/lib/delayed/performable_method.rb @@ -49,15 +49,11 @@ def method(sym) end # rubocop:disable MethodMissing - if RUBY_VERSION >= '3.0' - def method_missing(...) - object.send(...) - end - else - def method_missing(symbol, *args) - object.send(symbol, *args) - end - end + definition = RUBY_VERSION >= '3.0' ? '...' : '*args, &block' + method_def << + "def method_missing(#{definition})" << + " object.send(#{definition})" << + "end" # rubocop:enable MethodMissing def respond_to?(symbol, include_private = false) From 34dc5c9e6339724d92aaef4688e16b3b8b3eecc3 Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Tue, 22 Dec 2020 15:56:47 +0100 Subject: [PATCH 05/13] * Syntax fixed --- lib/delayed/performable_method.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/delayed/performable_method.rb b/lib/delayed/performable_method.rb index c13c8a00c..ee2084684 100644 --- a/lib/delayed/performable_method.rb +++ b/lib/delayed/performable_method.rb @@ -49,11 +49,15 @@ def method(sym) end # rubocop:disable MethodMissing + method_def = [] + location = caller_locations(1, 1).first + file, line = location.path, location.lineno definition = RUBY_VERSION >= '3.0' ? '...' : '*args, &block' method_def << "def method_missing(#{definition})" << " object.send(#{definition})" << "end" + module_eval(method_def.join(";"), file, line) # rubocop:enable MethodMissing def respond_to?(symbol, include_private = false) From c93b433fab05e2e25a5b36da3ecd41dd7845920d Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Sat, 27 Mar 2021 02:17:44 +0100 Subject: [PATCH 06/13] * specs added --- lib/delayed/performable_method.rb | 4 ++ spec/performable_method_spec.rb | 103 ++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/lib/delayed/performable_method.rb b/lib/delayed/performable_method.rb index ee2084684..2f4d41eb1 100644 --- a/lib/delayed/performable_method.rb +++ b/lib/delayed/performable_method.rb @@ -22,6 +22,10 @@ def display_name end end + # required to support named parameters in RUBY 3.0 + # Otherwise the following error is thrown + # ArgumentError: + # wrong number of arguments (given 1, expected 0; required keywords: if RUBY_VERSION >= '3.0' def perform if args_is_a_hash? diff --git a/spec/performable_method_spec.rb b/spec/performable_method_spec.rb index a4d700322..87e50d860 100644 --- a/spec/performable_method_spec.rb +++ b/spec/performable_method_spec.rb @@ -1,4 +1,5 @@ require 'helper' +require 'action_controller/metal/strong_parameters' describe Delayed::PerformableMethod do describe 'perform' do @@ -21,6 +22,108 @@ @method.perform end end + + describe 'perform with hash object' do + before do + @method = Delayed::PerformableMethod.new('foo', :count, [{o: true}]) + end + + it 'calls the method on the object' do + expect(@method.object).to receive(:count).with(o: true) + @method.perform + end + end + + describe 'perform with many hash objects' do + before do + @method = Delayed::PerformableMethod.new('foo', :count, [{o: true}, {o2: true}]) + end + + it 'calls the method on the object' do + expect(@method.object).to receive(:count).with({o: true}, {o2: true}) + @method.perform + end + end + + describe 'perform with params object' do + before do + @params = ActionController::Parameters.new({ + person: { + name: "Francesco", + age: 22, + role: "admin" + } + }) + + @method = Delayed::PerformableMethod.new('foo', :count, [@params]) + end + + it 'calls the method on the object' do + expect(@method.object).to receive(:count).with(@params) + @method.perform + end + end + + describe 'perform with sample object and params object' do + before do + @params = ActionController::Parameters.new({ + person: { + name: "Francesco", + age: 22, + role: "admin" + } + }) + + klass = Class.new do + def test_method(o1, o2) + true + end + end + + @method = Delayed::PerformableMethod.new(klass.new, :test_method, ['o', @params]) + end + + it 'calls the method on the object' do + expect(@method.object).to receive(:test_method).with('o', @params) + @method.perform + end + + it 'calls the method on the object (real)' do + expect(@method.perform).to be true + end + end + + describe 'perform with sample object and hash object' do + before do + @method = Delayed::PerformableMethod.new('foo', :count, ['o', {o: true}]) + end + + it 'calls the method on the object' do + expect(@method.object).to receive(:count).with('o', {o: true}) + @method.perform + end + end + + describe 'perform with hash to named parameters' do + before do + klass = Class.new do + def test_method(name:, any:) + true + end + end + + @method = Delayed::PerformableMethod.new(klass.new, :test_method, [{name: 'name', any: 'any'}]) + end + + it 'calls the method on the object' do + expect(@method.object).to receive(:test_method).with({name: 'name', any: 'any'}) + @method.perform + end + + it 'calls the method on the object (real)' do + expect(@method.perform).to be true + end + end it "raises a NoMethodError if target method doesn't exist" do expect do From 87a2aefd77017e6bbdc2e9052337e37b0c2c65d3 Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Sat, 27 Mar 2021 02:21:08 +0100 Subject: [PATCH 07/13] * Ruby 3.0 added --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f78e0b26..6fecf10ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: [2.5, 2.6, 2.7, jruby, jruby-head, ruby-head] + ruby: [2.5, 2.6, 2.7, 3.0, jruby, jruby-head, ruby-head] rails_version: - '5.2.0' - '6.0.0' From 8903aaa619db567c4575c06071e1ca0610a45260 Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Sun, 28 Mar 2021 00:40:55 +0100 Subject: [PATCH 08/13] * ci fixed --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6fecf10ea..7fd1e8544 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,9 +14,9 @@ jobs: matrix: ruby: [2.5, 2.6, 2.7, 3.0, jruby, jruby-head, ruby-head] rails_version: - - '5.2.0' + - '5.2.5' - '6.0.0' - - '6.1.0.rc2' + - '6.1.0' - 'edge' include: # From 25b0a4316c558ac74026dff8d22dae395e671b77 Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Sun, 28 Mar 2021 00:48:00 +0100 Subject: [PATCH 09/13] * dependencies fixed --- Gemfile | 6 +++--- delayed_job.gemspec | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index b83acb5bc..0bd41d117 100644 --- a/Gemfile +++ b/Gemfile @@ -27,7 +27,7 @@ platforms :jruby do elsif ENV['RAILS_VERSION'] gem 'railties', "~> #{ENV['RAILS_VERSION']}" else - gem 'railties', ['>= 3.0', '< 6.2'] + gem 'railties', ['>= 3.0', '< 7.1'] end end @@ -43,8 +43,8 @@ group :test do gem 'actionmailer', "~> #{ENV['RAILS_VERSION']}" gem 'activerecord', "~> #{ENV['RAILS_VERSION']}" else - gem 'actionmailer', ['>= 3.0', '< 6.2'] - gem 'activerecord', ['>= 3.0', '< 6.2'] + gem 'actionmailer', ['>= 3.0', '< 7.1'] + gem 'activerecord', ['>= 3.0', '< 7.1'] end gem 'rspec', '>= 3' diff --git a/delayed_job.gemspec b/delayed_job.gemspec index c9b60a781..23eec33e6 100644 --- a/delayed_job.gemspec +++ b/delayed_job.gemspec @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- Gem::Specification.new do |spec| - spec.add_dependency 'activesupport', ['>= 3.0', '< 6.2'] + spec.add_dependency 'activesupport', ['>= 3.0', '< 7.1'] spec.authors = ['Brandon Keepers', 'Brian Ryckbost', 'Chris Gaffney', 'David Genord II', 'Erik Michaels-Ober', 'Matt Griffin', 'Steve Richert', 'Tobias Lütke'] spec.description = 'Delayed_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background. It is a direct extraction from Shopify where the job table is responsible for a multitude of core tasks.' spec.email = ['brian@collectiveidea.com'] From 7819cb8cf1726631698eb527055430c723b431af Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Sun, 28 Mar 2021 01:06:31 +0100 Subject: [PATCH 10/13] * rubocop fixed --- lib/delayed/performable_method.rb | 21 +++++------ spec/performable_method_spec.rb | 58 ++++++++++++++----------------- 2 files changed, 36 insertions(+), 43 deletions(-) diff --git a/lib/delayed/performable_method.rb b/lib/delayed/performable_method.rb index 2f4d41eb1..9f64a6167 100644 --- a/lib/delayed/performable_method.rb +++ b/lib/delayed/performable_method.rb @@ -28,15 +28,13 @@ def display_name # wrong number of arguments (given 1, expected 0; required keywords: if RUBY_VERSION >= '3.0' def perform + return unless object + if args_is_a_hash? object.send(method_name, **args.first) else object.send(method_name, *args) - end if object -# rescue => e -# p e.message -# p args -# raise e + end end def args_is_a_hash? @@ -51,17 +49,16 @@ def perform def method(sym) object.method(sym) end - - # rubocop:disable MethodMissing method_def = [] location = caller_locations(1, 1).first - file, line = location.path, location.lineno + file = location.path + line = location.lineno definition = RUBY_VERSION >= '3.0' ? '...' : '*args, &block' method_def << - "def method_missing(#{definition})" << - " object.send(#{definition})" << - "end" - module_eval(method_def.join(";"), file, line) + "def method_missing(#{definition})" \ + " object.send(#{definition})" \ + 'end' + module_eval(method_def.join(';'), file, line) # rubocop:enable MethodMissing def respond_to?(symbol, include_private = false) diff --git a/spec/performable_method_spec.rb b/spec/performable_method_spec.rb index 87e50d860..33d687c96 100644 --- a/spec/performable_method_spec.rb +++ b/spec/performable_method_spec.rb @@ -22,38 +22,36 @@ @method.perform end end - + describe 'perform with hash object' do before do - @method = Delayed::PerformableMethod.new('foo', :count, [{o: true}]) + @method = Delayed::PerformableMethod.new('foo', :count, [{:o => true}]) end it 'calls the method on the object' do - expect(@method.object).to receive(:count).with(o: true) + expect(@method.object).to receive(:count).with(:o => true) @method.perform end end - + describe 'perform with many hash objects' do before do - @method = Delayed::PerformableMethod.new('foo', :count, [{o: true}, {o2: true}]) + @method = Delayed::PerformableMethod.new('foo', :count, [{:o => true}, {:o2 => true}]) end it 'calls the method on the object' do - expect(@method.object).to receive(:count).with({o: true}, {o2: true}) + expect(@method.object).to receive(:count).with({:o => true}, :o2 => true) @method.perform end end - + describe 'perform with params object' do before do - @params = ActionController::Parameters.new({ - person: { - name: "Francesco", - age: 22, - role: "admin" - } - }) + @params = ActionController::Parameters.new(:person => { + :name => 'Francesco', + :age => 22, + :role => 'admin' + }) @method = Delayed::PerformableMethod.new('foo', :count, [@params]) end @@ -63,19 +61,17 @@ @method.perform end end - + describe 'perform with sample object and params object' do before do - @params = ActionController::Parameters.new({ - person: { - name: "Francesco", - age: 22, - role: "admin" - } - }) - + @params = ActionController::Parameters.new(:person => { + :name => 'Francesco', + :age => 22, + :role => 'admin' + }) + klass = Class.new do - def test_method(o1, o2) + def test_method(_o1, _o2) true end end @@ -92,31 +88,31 @@ def test_method(o1, o2) expect(@method.perform).to be true end end - + describe 'perform with sample object and hash object' do before do - @method = Delayed::PerformableMethod.new('foo', :count, ['o', {o: true}]) + @method = Delayed::PerformableMethod.new('foo', :count, ['o', {:o => true}]) end it 'calls the method on the object' do - expect(@method.object).to receive(:count).with('o', {o: true}) + expect(@method.object).to receive(:count).with('o', :o => true) @method.perform end end - + describe 'perform with hash to named parameters' do before do klass = Class.new do def test_method(name:, any:) - true + true if name && any end end - @method = Delayed::PerformableMethod.new(klass.new, :test_method, [{name: 'name', any: 'any'}]) + @method = Delayed::PerformableMethod.new(klass.new, :test_method, [{:name => 'name', :any => 'any'}]) end it 'calls the method on the object' do - expect(@method.object).to receive(:test_method).with({name: 'name', any: 'any'}) + expect(@method.object).to receive(:test_method).with(:name => 'name', :any => 'any') @method.perform end From fff4e1e6d52af4320b152ee5850f3c1207948d46 Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Sun, 28 Mar 2021 01:30:19 +0100 Subject: [PATCH 11/13] * specs for older rails versions fixed --- spec/performable_method_spec.rb | 70 +++++++++++++++++---------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/spec/performable_method_spec.rb b/spec/performable_method_spec.rb index 33d687c96..0d01eb528 100644 --- a/spec/performable_method_spec.rb +++ b/spec/performable_method_spec.rb @@ -1,5 +1,5 @@ require 'helper' -require 'action_controller/metal/strong_parameters' +require 'action_controller/metal/strong_parameters' if ActionPack.version.to_s >= '4.0' describe Delayed::PerformableMethod do describe 'perform' do @@ -45,47 +45,49 @@ end end - describe 'perform with params object' do - before do - @params = ActionController::Parameters.new(:person => { - :name => 'Francesco', - :age => 22, - :role => 'admin' - }) + if ActionPack.version.to_s >= '4.0' + describe 'perform with params object' do + before do + @params = ActionController::Parameters.new(:person => { + :name => 'Francesco', + :age => 22, + :role => 'admin' + }) - @method = Delayed::PerformableMethod.new('foo', :count, [@params]) - end + @method = Delayed::PerformableMethod.new('foo', :count, [@params]) + end - it 'calls the method on the object' do - expect(@method.object).to receive(:count).with(@params) - @method.perform + it 'calls the method on the object' do + expect(@method.object).to receive(:count).with(@params) + @method.perform + end end - end - describe 'perform with sample object and params object' do - before do - @params = ActionController::Parameters.new(:person => { - :name => 'Francesco', - :age => 22, - :role => 'admin' - }) - - klass = Class.new do - def test_method(_o1, _o2) - true + describe 'perform with sample object and params object' do + before do + @params = ActionController::Parameters.new(:person => { + :name => 'Francesco', + :age => 22, + :role => 'admin' + }) + + klass = Class.new do + def test_method(_o1, _o2) + true + end end - end - @method = Delayed::PerformableMethod.new(klass.new, :test_method, ['o', @params]) - end + @method = Delayed::PerformableMethod.new(klass.new, :test_method, ['o', @params]) + end - it 'calls the method on the object' do - expect(@method.object).to receive(:test_method).with('o', @params) - @method.perform - end + it 'calls the method on the object' do + expect(@method.object).to receive(:test_method).with('o', @params) + @method.perform + end - it 'calls the method on the object (real)' do - expect(@method.perform).to be true + it 'calls the method on the object (real)' do + expect(@method.perform).to be true + end end end From 0afc6a2c9005dc5ab868f48196198ac8e1bea761 Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Sun, 28 Mar 2021 01:37:10 +0100 Subject: [PATCH 12/13] * specs for old rails versions fixed --- spec/performable_method_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/performable_method_spec.rb b/spec/performable_method_spec.rb index 0d01eb528..352daf095 100644 --- a/spec/performable_method_spec.rb +++ b/spec/performable_method_spec.rb @@ -1,5 +1,5 @@ require 'helper' -require 'action_controller/metal/strong_parameters' if ActionPack.version.to_s >= '4.0' +require 'action_controller/metal/strong_parameters' if ActionPack::VERSION::MAJOR >= 4 describe Delayed::PerformableMethod do describe 'perform' do @@ -45,7 +45,7 @@ end end - if ActionPack.version.to_s >= '4.0' + if ActionPack::VERSION::MAJOR >= 4 describe 'perform with params object' do before do @params = ActionController::Parameters.new(:person => { From 1e977484cbe57c8f2375b510ef788cc75c536172 Mon Sep 17 00:00:00 2001 From: Christian Eichhorn Date: Sun, 28 Mar 2021 01:44:21 +0100 Subject: [PATCH 13/13] + specs for old rails versions fixed --- spec/performable_method_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/performable_method_spec.rb b/spec/performable_method_spec.rb index 352daf095..17179c676 100644 --- a/spec/performable_method_spec.rb +++ b/spec/performable_method_spec.rb @@ -1,5 +1,5 @@ require 'helper' -require 'action_controller/metal/strong_parameters' if ActionPack::VERSION::MAJOR >= 4 +require 'action_controller/metal/strong_parameters' if ActionPack::VERSION::MAJOR >= 5 describe Delayed::PerformableMethod do describe 'perform' do @@ -45,7 +45,7 @@ end end - if ActionPack::VERSION::MAJOR >= 4 + if ActionPack::VERSION::MAJOR >= 5 describe 'perform with params object' do before do @params = ActionController::Parameters.new(:person => {