Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOPS-4867_RuboCop::Cop::Sidekiq::SymbolArgument -> hash literal with symbols #86

Merged
merged 15 commits into from
Jan 15, 2025
Merged
4 changes: 3 additions & 1 deletion lib/rubocop/cop/sidekiq/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ def sidekiq_arguments(node)

def expand_arguments(arguments)
arguments.flat_map do |argument|
if argument.array_type? || argument.hash_type?
if argument.array_type?
expand_arguments(argument.values)
elsif argument.hash_type?
expand_arguments(argument.pairs)
else
argument
end
Expand Down
54 changes: 52 additions & 2 deletions lib/rubocop/cop/sidekiq/symbol_argument.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,64 @@ module Sidekiq
#
# # good
# MyWorker.perform_async('foo')
#
# # bad
# MyWorker.perform_async(foo: 1)
#
# # good
# MyWorker.perform_async({'foo' => 1})
class SymbolArgument < Base
extend AutoCorrector

include Helpers

MSG = 'Symbols are not Sidekiq-serializable; use strings instead.'

def on_send(node)
sidekiq_arguments(node).select(&:sym_type?).each do |argument|
add_offense(argument)
sidekiq_arguments(node).each do |argument|
manage_sym_type(argument) || manage_pair_type(argument)
end
end

private

def manage_sym_type(argument)
return unless argument.sym_type?

add_offense(argument) do |corrector|
corrector.replace(argument, "'#{argument.value}'")
end
end

def manage_pair_type(argument)
return unless argument.pair_type?

manage_pair_key_value_symbol(argument) ||
manage_pair_key_symbol(argument) ||
manage_pair_value_symbol(argument)
end

def manage_pair_key_value_symbol(argument)
return unless argument.key.sym_type? && argument.value.sym_type?

add_offense(argument) do |corrector|
corrector.replace(argument, "'#{argument.key.value}' => '#{argument.value.value}'")
end
end

def manage_pair_key_symbol(argument)
return unless argument.key.sym_type?

add_offense(argument.key) do |corrector|
corrector.replace(argument, "'#{argument.key.value}' => #{argument.value.source}")
end
end

def manage_pair_value_symbol(argument)
return unless argument.value.sym_type?

add_offense(argument.value) do |corrector|
corrector.replace(argument.value, "'#{argument.value.value}'")
end
end
end
Expand Down
95 changes: 95 additions & 0 deletions spec/rubocop/cop/sidekiq/symbol_argument_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,101 @@
MyWorker.perform_async('a', 1, :foo)
^^^^ Sidekiq/SymbolArgument: Symbols are not Sidekiq-serializable; use strings instead.
RUBY

expect_correction(<<~RUBY)
MyWorker.perform_async('a', 1, 'foo')
RUBY
end
end

context 'when argument is a Hash' do
context 'when key is a symbol' do
it 'registers an offense' do
expect_offense(<<~RUBY)
MyWorker.perform_async('a', 1, foo: 1)
^^^ Sidekiq/SymbolArgument: Symbols are not Sidekiq-serializable; use strings instead.
RUBY

expect_correction(<<~RUBY)
MyWorker.perform_async('a', 1, 'foo' => 1)
RUBY
end

context 'when value is a var type' do
it 'registers an offense' do
expect_offense(<<~RUBY)
a = 1
MyWorker.perform_async('a', 1, bar: a)
^^^ Sidekiq/SymbolArgument: Symbols are not Sidekiq-serializable; use strings instead.
RUBY
expect_correction(<<~RUBY)
a = 1
MyWorker.perform_async('a', 1, 'bar' => a)
RUBY
end
end

context 'when value is a function type' do
it 'registers an offense' do
expect_offense(<<~RUBY)
MyWorker.perform_async('a', 1, bar: 1.hour)
^^^ Sidekiq/SymbolArgument: Symbols are not Sidekiq-serializable; use strings instead.
RUBY
expect_correction(<<~RUBY)
MyWorker.perform_async('a', 1, 'bar' => 1.hour)
RUBY
end
end

context 'when value is a block type' do
it 'registers an offense' do
expect_offense(<<~RUBY)
my_service = MyService.new('a')
MyWorker.perform_async('a', 1, bar: my_service.call('b'))
^^^ Sidekiq/SymbolArgument: Symbols are not Sidekiq-serializable; use strings instead.
RUBY
expect_correction(<<~RUBY)
my_service = MyService.new('a')
MyWorker.perform_async('a', 1, 'bar' => my_service.call('b'))
RUBY
end
end

context 'when value is a boolean type' do
it 'registers an offense' do
expect_offense(<<~RUBY)
MyWorker.perform_async('a', 1, bar: true)
^^^ Sidekiq/SymbolArgument: Symbols are not Sidekiq-serializable; use strings instead.
RUBY
expect_correction(<<~RUBY)
MyWorker.perform_async('a', 1, 'bar' => true)
RUBY
end
end
end

context 'when value is a symbol' do
it 'registers an offense' do
expect_offense(<<~RUBY)
MyWorker.perform_async('a', 1, 'bar' => :baz)
^^^^ Sidekiq/SymbolArgument: Symbols are not Sidekiq-serializable; use strings instead.
RUBY
expect_correction(<<~RUBY)
MyWorker.perform_async('a', 1, 'bar' => 'baz')
RUBY
end
end

context 'when key/value are symbols' do
it 'registers an offense' do
expect_offense(<<~RUBY)
MyWorker.perform_async('a', 1, bar: :baz)
^^^^^^^^^ Sidekiq/SymbolArgument: Symbols are not Sidekiq-serializable; use strings instead.
RUBY
expect_correction(<<~RUBY)
MyWorker.perform_async('a', 1, 'bar' => 'baz')
RUBY
end
end
end
end
Expand Down
Loading