Skip to content

Commit

Permalink
Add new Performance/BigDecimalString cop
Browse files Browse the repository at this point in the history
  • Loading branch information
fatkodima committed Jun 7, 2020
1 parent bb3cf35 commit 78b9371
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### New features

* [#129](https://github.com/rubocop-hq/rubocop-performance/pull/129): Add new `Performance/BigDecimalString` cop. ([@fatkodima][])
* [#81](https://github.com/rubocop-hq/rubocop-performance/issues/81): Add new `Performance/StringInclude` cop. ([@fatkodima][])
* [#123](https://github.com/rubocop-hq/rubocop-performance/pull/123): Add new `Performance/AncestorsInclude` cop. ([@fatkodima][])
* [#125](https://github.com/rubocop-hq/rubocop-performance/pull/125): Support `Range#member?` method for `Performance/RangeInclude` cop. ([@fatkodima][])
Expand Down
5 changes: 5 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ Performance/AncestorsInclude:
Enabled: true
VersionAdded: '1.7'

Performance/BigDecimalString:
Description: 'Convert numeric argument to string before passing to BigDecimal.'
Enabled: true
VersionAdded: '1.7'

Performance/BindCall:
Description: 'Use `bind_call(obj, args, ...)` instead of `bind(obj).call(args, ...)`.'
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/cops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
= Department xref:cops_performance.adoc[Performance]

* xref:cops_performance.adoc#performanceancestorsinclude[Performance/AncestorsInclude]
* xref:cops_performance.adoc#performancebigdecimalstring[Performance/BigDecimalString]
* xref:cops_performance.adoc#performancebindcall[Performance/BindCall]
* xref:cops_performance.adoc#performancecaller[Performance/Caller]
* xref:cops_performance.adoc#performancecasewhensplat[Performance/CaseWhenSplat]
Expand Down
30 changes: 30 additions & 0 deletions docs/modules/ROOT/pages/cops_performance.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,36 @@ A <= B

* https://github.com/JuanitoFatas/fast-ruby#ancestorsinclude-vs--code

== Performance/BigDecimalString

|===
| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged

| Enabled
| Yes
| Yes
| 1.7
| -
|===

This cop identifies places where numeric argument to BigDecimal should be
converted to string. Initializing from String is faster
than from Numeric for BigDecimal.

BigDecimal(1, 2)
BigDecimal(1.2, 3, exception: true)

# good
BigDecimal('1', 2)
BigDecimal('1.2', 3, exception: true)

=== Examples

[source,ruby]
----
# bad
----

== Performance/BindCall

NOTE: Required Ruby version: 2.7
Expand Down
51 changes: 51 additions & 0 deletions lib/rubocop/cop/performance/big_decimal_string.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Performance
# This cop identifies places where numeric argument to BigDecimal should be
# converted to string. Initializing from String is faster
# than from Numeric for BigDecimal.
#
# @example
#
# # bad
# BigDecimal(1, 2)
# BigDecimal(1.2, 3, exception: true)
#
# # good
# BigDecimal('1', 2)
# BigDecimal('1.2', 3, exception: true)
#
class BigDecimalString < Cop
MSG = 'Convert numeric argument to string before passing to `BigDecimal`.'

def_node_matcher :big_decimal_string_candidate?, <<~PATTERN
(send nil? :BigDecimal !str_type? ...)
PATTERN

def on_send(node)
return unless big_decimal_string_candidate?(node)

add_offense(node)
end

def autocorrect(node)
lambda do |corrector|
replacement = build_replacement(node)
corrector.replace(node, replacement)
end
end

private

def build_replacement(node)
number, *rest = node.arguments
number = "'#{number.source}'"
args = [number].concat(rest.map(&:source)).join(', ')
"BigDecimal(#{args})"
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/performance_cops.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require_relative 'mixin/regexp_metacharacter'

require_relative 'performance/ancestors_include'
require_relative 'performance/big_decimal_string'
require_relative 'performance/bind_call'
require_relative 'performance/caller'
require_relative 'performance/case_when_splat'
Expand Down
25 changes: 25 additions & 0 deletions spec/rubocop/cop/performance/big_decimal_string_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Performance::BigDecimalString do
subject(:cop) { described_class.new }

it 'registers an offense and corrects when using `BigDecimal` with integer' do
expect_offense(<<~RUBY)
BigDecimal(1)
^^^^^^^^^^^^^ Convert numeric argument to string before passing to `BigDecimal`.
RUBY
end

it 'registers an offense and corrects when using `BigDecimal` with float' do
expect_offense(<<~RUBY)
BigDecimal(1.5, 2, exception: true)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Convert numeric argument to string before passing to `BigDecimal`.
RUBY
end

it 'does not register an offense when using `BigDecimal` with string' do
expect_no_offenses(<<~RUBY)
BigDecimal('1')
RUBY
end
end

0 comments on commit 78b9371

Please sign in to comment.