Skip to content

Commit 78b9371

Browse files
committed
Add new Performance/BigDecimalString cop
1 parent bb3cf35 commit 78b9371

File tree

7 files changed

+114
-0
lines changed

7 files changed

+114
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### New features
66

7+
* [#129](https://github.com/rubocop-hq/rubocop-performance/pull/129): Add new `Performance/BigDecimalString` cop. ([@fatkodima][])
78
* [#81](https://github.com/rubocop-hq/rubocop-performance/issues/81): Add new `Performance/StringInclude` cop. ([@fatkodima][])
89
* [#123](https://github.com/rubocop-hq/rubocop-performance/pull/123): Add new `Performance/AncestorsInclude` cop. ([@fatkodima][])
910
* [#125](https://github.com/rubocop-hq/rubocop-performance/pull/125): Support `Range#member?` method for `Performance/RangeInclude` cop. ([@fatkodima][])

config/default.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ Performance/AncestorsInclude:
66
Enabled: true
77
VersionAdded: '1.7'
88

9+
Performance/BigDecimalString:
10+
Description: 'Convert numeric argument to string before passing to BigDecimal.'
11+
Enabled: true
12+
VersionAdded: '1.7'
13+
914
Performance/BindCall:
1015
Description: 'Use `bind_call(obj, args, ...)` instead of `bind(obj).call(args, ...)`.'
1116
Enabled: true

docs/modules/ROOT/pages/cops.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
= Department xref:cops_performance.adoc[Performance]
44

55
* xref:cops_performance.adoc#performanceancestorsinclude[Performance/AncestorsInclude]
6+
* xref:cops_performance.adoc#performancebigdecimalstring[Performance/BigDecimalString]
67
* xref:cops_performance.adoc#performancebindcall[Performance/BindCall]
78
* xref:cops_performance.adoc#performancecaller[Performance/Caller]
89
* xref:cops_performance.adoc#performancecasewhensplat[Performance/CaseWhenSplat]

docs/modules/ROOT/pages/cops_performance.adoc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,36 @@ A <= B
3030

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

33+
== Performance/BigDecimalString
34+
35+
|===
36+
| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
37+
38+
| Enabled
39+
| Yes
40+
| Yes
41+
| 1.7
42+
| -
43+
|===
44+
45+
This cop identifies places where numeric argument to BigDecimal should be
46+
converted to string. Initializing from String is faster
47+
than from Numeric for BigDecimal.
48+
49+
BigDecimal(1, 2)
50+
BigDecimal(1.2, 3, exception: true)
51+
52+
# good
53+
BigDecimal('1', 2)
54+
BigDecimal('1.2', 3, exception: true)
55+
56+
=== Examples
57+
58+
[source,ruby]
59+
----
60+
# bad
61+
----
62+
3363
== Performance/BindCall
3464

3565
NOTE: Required Ruby version: 2.7
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module Performance
6+
# This cop identifies places where numeric argument to BigDecimal should be
7+
# converted to string. Initializing from String is faster
8+
# than from Numeric for BigDecimal.
9+
#
10+
# @example
11+
#
12+
# # bad
13+
# BigDecimal(1, 2)
14+
# BigDecimal(1.2, 3, exception: true)
15+
#
16+
# # good
17+
# BigDecimal('1', 2)
18+
# BigDecimal('1.2', 3, exception: true)
19+
#
20+
class BigDecimalString < Cop
21+
MSG = 'Convert numeric argument to string before passing to `BigDecimal`.'
22+
23+
def_node_matcher :big_decimal_string_candidate?, <<~PATTERN
24+
(send nil? :BigDecimal !str_type? ...)
25+
PATTERN
26+
27+
def on_send(node)
28+
return unless big_decimal_string_candidate?(node)
29+
30+
add_offense(node)
31+
end
32+
33+
def autocorrect(node)
34+
lambda do |corrector|
35+
replacement = build_replacement(node)
36+
corrector.replace(node, replacement)
37+
end
38+
end
39+
40+
private
41+
42+
def build_replacement(node)
43+
number, *rest = node.arguments
44+
number = "'#{number.source}'"
45+
args = [number].concat(rest.map(&:source)).join(', ')
46+
"BigDecimal(#{args})"
47+
end
48+
end
49+
end
50+
end
51+
end

lib/rubocop/cop/performance_cops.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require_relative 'mixin/regexp_metacharacter'
44

55
require_relative 'performance/ancestors_include'
6+
require_relative 'performance/big_decimal_string'
67
require_relative 'performance/bind_call'
78
require_relative 'performance/caller'
89
require_relative 'performance/case_when_splat'
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe RuboCop::Cop::Performance::BigDecimalString do
4+
subject(:cop) { described_class.new }
5+
6+
it 'registers an offense and corrects when using `BigDecimal` with integer' do
7+
expect_offense(<<~RUBY)
8+
BigDecimal(1)
9+
^^^^^^^^^^^^^ Convert numeric argument to string before passing to `BigDecimal`.
10+
RUBY
11+
end
12+
13+
it 'registers an offense and corrects when using `BigDecimal` with float' do
14+
expect_offense(<<~RUBY)
15+
BigDecimal(1.5, 2, exception: true)
16+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Convert numeric argument to string before passing to `BigDecimal`.
17+
RUBY
18+
end
19+
20+
it 'does not register an offense when using `BigDecimal` with string' do
21+
expect_no_offenses(<<~RUBY)
22+
BigDecimal('1')
23+
RUBY
24+
end
25+
end

0 commit comments

Comments
 (0)