From dc7a28c201bd1c3aaf672f86fa4e179fea400a57 Mon Sep 17 00:00:00 2001 From: Manjunath Date: Fri, 6 Aug 2021 17:40:41 +0530 Subject: [PATCH] Hash#update() vs Hash#[]= --- .fasterer.yml | 1 + README.md | 1 + lib/fasterer/offense.rb | 3 +++ lib/fasterer/scanners/method_call_scanner.rb | 13 ++++++++++++ .../17_hash_update_vs_hash_brackets_spec.rb | 11 ++++++++++ .../17_hash_update_vs_hash_brackets.rb | 21 +++++++++++++++++++ 6 files changed, 50 insertions(+) create mode 100644 spec/lib/fasterer/analyzer/17_hash_update_vs_hash_brackets_spec.rb create mode 100644 spec/support/analyzer/17_hash_update_vs_hash_brackets.rb diff --git a/.fasterer.yml b/.fasterer.yml index c125758..08ffd51 100644 --- a/.fasterer.yml +++ b/.fasterer.yml @@ -12,6 +12,7 @@ speedups: fetch_with_argument_vs_block: true keys_each_vs_each_key: true hash_merge_bang_vs_hash_brackets: true + hash_update_vs_hash_brackets: true block_vs_symbol_to_proc: true proc_call_vs_yield: true gsub_vs_tr: true diff --git a/README.md b/README.md index 59c941a..57597da 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ speedups: fetch_with_argument_vs_block: true keys_each_vs_each_key: true hash_merge_bang_vs_hash_brackets: true + hash_update_vs_hash_brackets: true block_vs_symbol_to_proc: true proc_call_vs_yield: true gsub_vs_tr: true diff --git a/lib/fasterer/offense.rb b/lib/fasterer/offense.rb index 883b7b1..11001da 100644 --- a/lib/fasterer/offense.rb +++ b/lib/fasterer/offense.rb @@ -52,6 +52,9 @@ def explanation hash_merge_bang_vs_hash_brackets: 'Hash#merge! with one argument is slower than Hash#[]', + hash_update_vs_hash_brackets: + 'Hash#update with one argument is slower than Hash#[]', + block_vs_symbol_to_proc: 'Calling argumentless methods within blocks is slower than using symbol to proc', diff --git a/lib/fasterer/scanners/method_call_scanner.rb b/lib/fasterer/scanners/method_call_scanner.rb index a8f976e..7eb5b90 100644 --- a/lib/fasterer/scanners/method_call_scanner.rb +++ b/lib/fasterer/scanners/method_call_scanner.rb @@ -39,6 +39,8 @@ def check_offense check_fetch_offense when :merge! check_merge_bang_offense + when :update + check_update_offense when :last check_last_offense when :include? @@ -149,6 +151,17 @@ def check_merge_bang_offense end end + def check_update_offense + return unless method_call.arguments.count == 1 + + first_argument = method_call.arguments.first + return unless first_argument.type == :hash + + if first_argument.element.drop(1).count == 2 # each key and value is an item by itself. + add_offense(:hash_update_vs_hash_brackets) + end + end + def check_last_offense return method_call unless method_call.receiver.is_a?(MethodCall) diff --git a/spec/lib/fasterer/analyzer/17_hash_update_vs_hash_brackets_spec.rb b/spec/lib/fasterer/analyzer/17_hash_update_vs_hash_brackets_spec.rb new file mode 100644 index 0000000..6df092a --- /dev/null +++ b/spec/lib/fasterer/analyzer/17_hash_update_vs_hash_brackets_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe Fasterer::Analyzer do + let(:test_file_path) { RSpec.root.join('support', 'analyzer', '17_hash_update_vs_hash_brackets.rb') } + + it 'should detect keys each 3 times' do + analyzer = Fasterer::Analyzer.new(test_file_path) + analyzer.scan + expect(analyzer.errors[:hash_update_vs_hash_brackets].count).to eq(3) + end +end diff --git a/spec/support/analyzer/17_hash_update_vs_hash_brackets.rb b/spec/support/analyzer/17_hash_update_vs_hash_brackets.rb new file mode 100644 index 0000000..252f680 --- /dev/null +++ b/spec/support/analyzer/17_hash_update_vs_hash_brackets.rb @@ -0,0 +1,21 @@ +h.update(item: 1, item2: 3) + +h.update + +h.update(item, item: 1) + +h.update(item: 1) + +ENUM.each_with_object({}) do |e, h| + h.update(e => e) +end + +ENUM.each_with_object({}) do |e, h| + h[e] = e +end + +h.update(item: 1) + +h.update({item: 1}) + +h.update({})