Commit 023b38de authored by Qingyu Zhao's avatar Qingyu Zhao

Add rubocop for AR exists? and present?/blank?

parent 7da7c18c
......@@ -22,13 +22,13 @@
.content-list.manage-labels-list.js-prioritized-labels{ data: { url: set_priorities_project_labels_path(@project), sortable: can_admin_label } }
#js-priority-labels-empty-state.priority-labels-empty-state{ class: "#{'hidden' unless @prioritized_labels.empty? && search.blank?}" }
= render 'shared/empty_states/priority_labels'
- if @prioritized_labels.present?
- if @prioritized_labels.any?
= render partial: 'shared/label', collection: @prioritized_labels, as: :label, locals: { force_priority: true, subject: @project }
- elsif search.present?
.nothing-here-block
= _('No prioritized labels with such name or description')
- if @labels.present?
- if @labels.any?
.other-labels
%h5{ class: ('hide' if hide) }= _('Other Labels')
.content-list.manage-labels-list.js-other-labels
......
# frozen_string_literal: true
module RuboCop
module Cop
module Performance
class ARExistsAndPresentBlank < RuboCop::Cop::Cop
def message_present(ivar)
"Avoid `#{ivar}.present?`, because it will generate database query 'Select TABLE.*' which is expensive. "\
"Suggest to use `#{ivar}.any?` to replace `#{ivar}.present?`"
end
def message_blank(ivar)
"Avoid `#{ivar}.blank?`, because it will generate database query 'Select TABLE.*' which is expensive. "\
"Suggest to use `#{ivar}.empty?` to replace `#{ivar}.blank?`"
end
def_node_matcher :exists_match, <<~PATTERN
(send (ivar $_) :exists?)
PATTERN
def_node_matcher :present_match, <<~PATTERN
(send (ivar $_) :present?)
PATTERN
def_node_matcher :blank_match, <<~PATTERN
(send (ivar $_) :blank?)
PATTERN
def file_name(node)
node.location.expression.source_buffer.name
end
def in_haml_file?(node)
file_name(node).end_with?('.haml.rb')
end
def on_send(node)
return unless in_haml_file?(node)
ivar_present = present_match(node)
ivar_blank = blank_match(node)
return unless ivar_present || ivar_blank
node.each_ancestor(:begin) do |begin_node|
begin_node.each_descendant do |n|
ivar_exists = exists_match(n)
next unless ivar_exists
add_offense(node, location: :expression, message: message_present(ivar_exists)) if ivar_exists == ivar_present
add_offense(node, location: :expression, message: message_blank(ivar_exists)) if ivar_exists == ivar_blank
end
end
end
end
end
end
end
# frozen_string_literal: true
require 'fast_spec_helper'
require_relative '../../../support/helpers/expect_offense'
require_relative '../../../../rubocop/cop/performance/ar_exists_and_present_blank.rb'
describe RuboCop::Cop::Performance::ARExistsAndPresentBlank do
include CopHelper
include ExpectOffense
subject(:cop) { described_class.new }
context 'when it is not haml file' do
it 'does not flag it as an offense' do
expect(subject).to receive(:in_haml_file?).with(anything).at_least(:once).and_return(false)
expect_no_offenses <<~SOURCE
return unless @users.exists?
show @users if @users.present?
SOURCE
end
end
context 'when it is haml file' do
before do
expect(subject).to receive(:in_haml_file?).with(anything).at_least(:once).and_return(true)
end
context 'the same object uses exists? and present?' do
it 'flags it as an offense' do
expect_offense <<~SOURCE
return unless @users.exists?
show @users if @users.present?
^^^^^^^^^^^^^^^ Avoid `@users.present?`, because it will generate database query 'Select TABLE.*' which is expensive. Suggest to use `@users.any?` to replace `@users.present?`
SOURCE
expect(cop.offenses.map(&:cop_name)).to contain_exactly('Performance/ARExistsAndPresentBlank')
end
end
context 'the same object uses exists? and blank?' do
it 'flags it as an offense' do
expect_offense <<~SOURCE
return unless @users.exists?
show @users if @users.blank?
^^^^^^^^^^^^^ Avoid `@users.blank?`, because it will generate database query 'Select TABLE.*' which is expensive. Suggest to use `@users.empty?` to replace `@users.blank?`
SOURCE
expect(cop.offenses.map(&:cop_name)).to contain_exactly('Performance/ARExistsAndPresentBlank')
end
end
context 'the same object uses exists?, blank? and present?' do
it 'flags it as an offense' do
expect_offense <<~SOURCE
return unless @users.exists?
show @users if @users.blank?
^^^^^^^^^^^^^ Avoid `@users.blank?`, because it will generate database query 'Select TABLE.*' which is expensive. Suggest to use `@users.empty?` to replace `@users.blank?`
show @users if @users.present?
^^^^^^^^^^^^^^^ Avoid `@users.present?`, because it will generate database query 'Select TABLE.*' which is expensive. Suggest to use `@users.any?` to replace `@users.present?`
SOURCE
expect(cop.offenses.map(&:cop_name)).to contain_exactly('Performance/ARExistsAndPresentBlank', 'Performance/ARExistsAndPresentBlank')
end
end
RSpec.shared_examples 'different object uses exists? and present?/blank?' do |another_method|
it 'does not flag it as an offense' do
expect_no_offenses <<~SOURCE
return unless @users.exists?
present @emails if @emails.#{another_method}
SOURCE
end
end
it_behaves_like 'different object uses exists? and present?/blank?', 'present?'
it_behaves_like 'different object uses exists? and present?/blank?', 'blank?'
RSpec.shared_examples 'Only using one present?/blank? without exists?' do |non_exists_method|
it 'does not flag it as an offense' do
expect_no_offenses "@users.#{non_exists_method}"
end
end
it_behaves_like 'Only using one present?/blank? without exists?', 'present?'
it_behaves_like 'Only using one present?/blank? without exists?', 'blank?'
context 'when using many present?/empty? without exists?' do
it 'does not flag it as an offense' do
expect_no_offenses <<~SOURCE
@user.present?
@user.blank?
@user.present?
@user.blank?
SOURCE
end
end
context 'when just using exists? without present?/blank?' do
it 'does not flag it as an offense' do
expect_no_offenses '@users.exists?'
expect_no_offenses <<~SOURCE
@users.exists?
@users.some_other_method?
@users.exists?
SOURCE
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment