From 35ef5ed43c36bc5bb0bae839a8fb9bd3cee1ff7c Mon Sep 17 00:00:00 2001 From: Anton Antonov Date: Tue, 28 Jul 2015 21:29:58 +0300 Subject: [PATCH] New cop `Style/Send` checks for the use of `send` (disabled by default) --- CHANGELOG.md | 2 + config/disabled.yml | 4 ++ lib/rubocop.rb | 1 + lib/rubocop/cop/style/send.rb | 18 +++++++ spec/rubocop/cop/style/send_spec.rb | 81 +++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+) create mode 100644 lib/rubocop/cop/style/send.rb create mode 100644 spec/rubocop/cop/style/send_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index dcac4323a12a..90b9bfb725f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### New features +* [#2081](https://github.com/bbatsov/rubocop/pull/2081): New cop `Style/Send` checks for the use of `send` and instead encourages changing it to `BasicObject#__send__` or `Object#public_send` (disabled by default). ([@syndbg][]) * [#2057](https://github.com/bbatsov/rubocop/pull/2057): New cop `Lint/FormatParameterMismatch` checks for a mismatch between the number of fields expected in format/sprintf/% and what was pased to it. ([@edmz][]) * [#2010](https://github.com/bbatsov/rubocop/pull/2010): Add `space` style for SpaceInsideStringInterpolation. ([@gotrevor][]) * [#2007](https://github.com/bbatsov/rubocop/pull/2007): Allow any modifier before `def`, not only visibility modifiers. ([@fphilipe][]) @@ -1521,3 +1522,4 @@ [@maxjacobson]: https://github.com/maxjacobson [@sliuu]: https://github.com/sliuu [@edmz]: https://github.com/edmz +[@syndbg]: https://github.com/syndbg diff --git a/config/disabled.yml b/config/disabled.yml index da57d97146d0..b4aa850a03cf 100644 --- a/config/disabled.yml +++ b/config/disabled.yml @@ -46,6 +46,10 @@ Style/MissingElse: Style/OptionHash: Description: "Don't use option hashes when you can use keyword arguments." + +Style/Send: + Description: 'Prefer `Object#__send__` or `Object#public_send` to `send`, as `send` may overlap with existing methods.' + StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#prefer-public-send' Enabled: false Style/SymbolArray: diff --git a/lib/rubocop.rb b/lib/rubocop.rb index 53b982fcbbbb..c3684064fba7 100644 --- a/lib/rubocop.rb +++ b/lib/rubocop.rb @@ -247,6 +247,7 @@ require 'rubocop/cop/style/rescue_modifier' require 'rubocop/cop/style/self_assignment' require 'rubocop/cop/style/semicolon' +require 'rubocop/cop/style/send' require 'rubocop/cop/style/signal_exception' require 'rubocop/cop/style/single_line_block_params' require 'rubocop/cop/style/single_line_methods' diff --git a/lib/rubocop/cop/style/send.rb b/lib/rubocop/cop/style/send.rb new file mode 100644 index 000000000000..22416b9da9d1 --- /dev/null +++ b/lib/rubocop/cop/style/send.rb @@ -0,0 +1,18 @@ +# encoding: utf-8 + +module RuboCop + module Cop + module Style + # This cop checks for the use of the send method. + class Send < Cop + MSG = 'Prefer `Object#__send__` or `Object#public_send` to `send`.' + + def on_send(node) + _receiver, method_name, *args = *node + return unless method_name == :send && args.length > 0 + add_offense(node, :selector) + end + end + end + end +end diff --git a/spec/rubocop/cop/style/send_spec.rb b/spec/rubocop/cop/style/send_spec.rb new file mode 100644 index 000000000000..2ff9b99e54f3 --- /dev/null +++ b/spec/rubocop/cop/style/send_spec.rb @@ -0,0 +1,81 @@ +# encoding: utf-8 + +require 'spec_helper' + +describe RuboCop::Cop::Style::Send do + subject(:cop) { described_class.new } + + context 'with send' do + context 'and with a receiver' do + it 'registers an offense for an invocation with args' do + inspect_source(cop, 'Object.send(:inspect)') + expect(cop.offenses.size).to eq(1) + end + + it 'does not register an offense for an invocation without args' do + inspect_source(cop, 'Object.send') + expect(cop.offenses).to be_empty + end + end + + context 'and without a receiver' do + it 'registers an offense for an invocation with args' do + inspect_source(cop, 'send(:inspect)') + expect(cop.offenses.size).to eq(1) + end + + it 'does not register an offense for an invocation without args' do + inspect_source(cop, 'send') + expect(cop.offenses).to be_empty + end + end + end + + context 'with __send__' do + after(:each) { expect(cop.offenses).to be_empty } + + context 'and with a receiver' do + it 'does not register an offense for an invocation with args' do + inspect_source(cop, 'Object.__send__(:inspect)') + end + + it 'does not register an offense for an invocation without args' do + inspect_source(cop, 'Object.__send__') + end + end + + context 'and without a receiver' do + it 'does not register an offense for an invocation with args' do + inspect_source(cop, '__send__(:inspect)') + end + + it 'does not register an offense for an invocation without args' do + inspect_source(cop, '__send__') + end + end + end + + context 'with public_send' do + after(:each) { expect(cop.offenses).to be_empty } + + context 'and with a receiver' do + it 'does not register an offense for an invocation with args' do + inspect_source(cop, 'Object.public_send(:inspect)') + end + + it 'does not register an offense for an invocation without args' do + inspect_source(cop, 'Object.public_send') + end + end + + context 'and without a receiver' do + it 'does not register an offense for an invocation with args' do + inspect_source(cop, 'public_send(:inspect)') + end + + it 'does not register an offense for an invocation without args' do + inspect_source(cop, 'public_send') + end + end + end +end