rubocop-performance 1.6.1 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -0
  3. data/config/default.yml +95 -8
  4. data/lib/rubocop/cop/mixin/regexp_metacharacter.rb +4 -4
  5. data/lib/rubocop/cop/mixin/sort_block.rb +28 -0
  6. data/lib/rubocop/cop/performance/ancestors_include.rb +49 -0
  7. data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +74 -0
  8. data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +46 -0
  9. data/lib/rubocop/cop/performance/bind_call.rb +9 -18
  10. data/lib/rubocop/cop/performance/block_given_with_explicit_block.rb +52 -0
  11. data/lib/rubocop/cop/performance/caller.rb +14 -15
  12. data/lib/rubocop/cop/performance/case_when_splat.rb +18 -11
  13. data/lib/rubocop/cop/performance/casecmp.rb +13 -20
  14. data/lib/rubocop/cop/performance/chain_array_allocation.rb +4 -10
  15. data/lib/rubocop/cop/performance/collection_literal_in_loop.rb +140 -0
  16. data/lib/rubocop/cop/performance/compare_with_block.rb +10 -21
  17. data/lib/rubocop/cop/performance/constant_regexp.rb +68 -0
  18. data/lib/rubocop/cop/performance/count.rb +14 -16
  19. data/lib/rubocop/cop/performance/delete_prefix.rb +14 -22
  20. data/lib/rubocop/cop/performance/delete_suffix.rb +14 -22
  21. data/lib/rubocop/cop/performance/detect.rb +65 -32
  22. data/lib/rubocop/cop/performance/double_start_end_with.rb +16 -24
  23. data/lib/rubocop/cop/performance/end_with.rb +9 -13
  24. data/lib/rubocop/cop/performance/fixed_size.rb +2 -1
  25. data/lib/rubocop/cop/performance/flat_map.rb +21 -22
  26. data/lib/rubocop/cop/performance/inefficient_hash_search.rb +15 -14
  27. data/lib/rubocop/cop/performance/io_readlines.rb +112 -0
  28. data/lib/rubocop/cop/performance/method_object_as_block.rb +32 -0
  29. data/lib/rubocop/cop/performance/open_struct.rb +3 -2
  30. data/lib/rubocop/cop/performance/range_include.rb +15 -11
  31. data/lib/rubocop/cop/performance/redundant_block_call.rb +15 -10
  32. data/lib/rubocop/cop/performance/redundant_match.rb +12 -6
  33. data/lib/rubocop/cop/performance/redundant_merge.rb +19 -17
  34. data/lib/rubocop/cop/performance/redundant_sort_block.rb +43 -0
  35. data/lib/rubocop/cop/performance/redundant_string_chars.rb +129 -0
  36. data/lib/rubocop/cop/performance/regexp_match.rb +20 -20
  37. data/lib/rubocop/cop/performance/reverse_each.rb +10 -5
  38. data/lib/rubocop/cop/performance/reverse_first.rb +73 -0
  39. data/lib/rubocop/cop/performance/size.rb +42 -43
  40. data/lib/rubocop/cop/performance/sort_reverse.rb +45 -0
  41. data/lib/rubocop/cop/performance/squeeze.rb +67 -0
  42. data/lib/rubocop/cop/performance/start_with.rb +9 -13
  43. data/lib/rubocop/cop/performance/string_include.rb +56 -0
  44. data/lib/rubocop/cop/performance/string_replacement.rb +24 -27
  45. data/lib/rubocop/cop/performance/sum.rb +236 -0
  46. data/lib/rubocop/cop/performance/times_map.rb +12 -18
  47. data/lib/rubocop/cop/performance/unfreeze_string.rb +20 -2
  48. data/lib/rubocop/cop/performance/uri_default_parser.rb +7 -12
  49. data/lib/rubocop/cop/performance_cops.rb +16 -0
  50. data/lib/rubocop/performance/version.rb +6 -1
  51. metadata +35 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 111d420207542c8522d9f34b5b8bf24356572b5fbcf0c11dfcb1e7f738a4c76f
4
- data.tar.gz: 97632031f51e154320bc3d585da448740596436882b67277f1b5d26ddfe55fba
3
+ metadata.gz: 9b44c147120a9f64f16a0bf21782f1dbe0a51c64170c3a5c217e548eded4e106
4
+ data.tar.gz: 7b4e6e464ee3631071f3bd3f447acde2a59763d326a86658412f4ec9527850a6
5
5
  SHA512:
6
- metadata.gz: a36e6950e6fe7847303c87862df76767d32c4f68640c229ad4ceb6115d4ae2093be18a8296c2e49324c67e8eb06dd99db42f8823586f1b572e10a74693b831d1
7
- data.tar.gz: 782352b1a7c420ac3c5498aeff749577e6280fb35d6e36844ae875511e9b6b44becfd9a2789d1b4c672cb71a91b8ab1cc63c89ec41abda8d1f34f1dacd26a07c
6
+ metadata.gz: e450740a348bd17e276af8393f4e8225521afc4c9fac5816c9a3bbd9883d16a15f28a1044e24b89c9037593f4d2931cf3dc900385d42d7ad035dbb1dd461a306
7
+ data.tar.gz: feef1ae1d9735d3abadf17799ecfb4840ce359fa932902387633e67dc15e1eeb62573ae0a2832c050a8722e004f614c109483a9d8857143f28c866dbd65bc5bf
data/README.md CHANGED
@@ -76,6 +76,14 @@ Performance/Size:
76
76
 
77
77
  You can read a lot more about RuboCop Performance in its [official docs](https://docs.rubocop.org/rubocop-performance/).
78
78
 
79
+ ## Compatibility
80
+
81
+ RuboCop Performance complies with the RuboCop core compatibility.
82
+
83
+ See the [compatibility documentation](https://docs.rubocop.org/rubocop/compatibility.html) for further details.
84
+
85
+ **Note:** Performance cops are all MRI focused and are highly dependent of the version of MRI you're using.
86
+
79
87
  ## Contributing
80
88
 
81
89
  Checkout the [contribution guidelines](CONTRIBUTING.md).
@@ -1,15 +1,38 @@
1
1
  # This is the default configuration file.
2
2
 
3
+ Performance/AncestorsInclude:
4
+ Description: 'Use `A <= B` instead of `A.ancestors.include?(B)`.'
5
+ Reference: 'https://github.com/JuanitoFatas/fast-ruby#ancestorsinclude-vs--code'
6
+ Enabled: 'pending'
7
+ Safe: false
8
+ VersionAdded: '1.7'
9
+
10
+ Performance/ArraySemiInfiniteRangeSlice:
11
+ Description: 'Identifies places where slicing arrays with semi-infinite ranges can be replaced by `Array#take` and `Array#drop`.'
12
+ Enabled: pending
13
+ VersionAdded: '1.9'
14
+
15
+ Performance/BigDecimalWithNumericArgument:
16
+ Description: 'Convert numeric argument to string before passing to BigDecimal.'
17
+ Enabled: 'pending'
18
+ VersionAdded: '1.7'
19
+
3
20
  Performance/BindCall:
4
21
  Description: 'Use `bind_call(obj, args, ...)` instead of `bind(obj).call(args, ...)`.'
5
22
  Enabled: true
6
23
  VersionAdded: '1.6'
7
24
 
25
+ Performance/BlockGivenWithExplicitBlock:
26
+ Description: 'Check block argument explicitly instead of using `block_given?`.'
27
+ Enabled: pending
28
+ VersionAdded: '1.9'
29
+
8
30
  Performance/Caller:
9
31
  Description: >-
10
32
  Use `caller(n..n)` instead of `caller`.
11
33
  Enabled: true
12
34
  VersionAdded: '0.49'
35
+ VersionChanged: '1.9'
13
36
 
14
37
  Performance/CaseWhenSplat:
15
38
  Description: >-
@@ -37,23 +60,33 @@ Performance/ChainArrayAllocation:
37
60
  Enabled: false
38
61
  VersionAdded: '0.59'
39
62
 
63
+ Performance/CollectionLiteralInLoop:
64
+ Description: 'Extract Array and Hash literals outside of loops into local variables or constants.'
65
+ Enabled: 'pending'
66
+ VersionAdded: '1.8'
67
+ # Min number of elements to consider an offense
68
+ MinSize: 1
69
+
40
70
  Performance/CompareWithBlock:
41
71
  Description: 'Use `sort_by(&:foo)` instead of `sort { |a, b| a.foo <=> b.foo }`.'
42
72
  Enabled: true
43
73
  VersionAdded: '0.46'
44
74
 
75
+ Performance/ConstantRegexp:
76
+ Description: 'Finds regular expressions with dynamic components that are all constants.'
77
+ Enabled: pending
78
+ VersionAdded: '1.9'
79
+
45
80
  Performance/Count:
46
81
  Description: >-
47
- Use `count` instead of `select...size`, `reject...size`,
48
- `select...count`, `reject...count`, `select...length`,
49
- and `reject...length`.
82
+ Use `count` instead of `{select,find_all,filter,reject}...{size,count,length}`.
50
83
  # This cop has known compatibility issues with `ActiveRecord` and other
51
84
  # frameworks. ActiveRecord's `count` ignores the block that is passed to it.
52
85
  # For more information, see the documentation in the cop itself.
53
86
  SafeAutoCorrect: false
54
87
  Enabled: true
55
88
  VersionAdded: '0.31'
56
- VersionChanged: '1.5'
89
+ VersionChanged: '1.8'
57
90
 
58
91
  Performance/DeletePrefix:
59
92
  Description: 'Use `delete_prefix` instead of `gsub`.'
@@ -69,8 +102,8 @@ Performance/DeleteSuffix:
69
102
 
70
103
  Performance/Detect:
71
104
  Description: >-
72
- Use `detect` instead of `select.first`, `find_all.first`,
73
- `select.last`, and `find_all.last`.
105
+ Use `detect` instead of `select.first`, `find_all.first`, `filter.first`,
106
+ `select.last`, `find_all.last`, and `filter.last`.
74
107
  Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code'
75
108
  # This cop has known compatibility issues with `ActiveRecord` and other
76
109
  # frameworks. `ActiveRecord` does not implement a `detect` method and `find`
@@ -79,7 +112,7 @@ Performance/Detect:
79
112
  SafeAutoCorrect: false
80
113
  Enabled: true
81
114
  VersionAdded: '0.30'
82
- VersionChanged: '1.5'
115
+ VersionChanged: '1.8'
83
116
 
84
117
  Performance/DoubleStartEndWith:
85
118
  Description: >-
@@ -131,6 +164,18 @@ Performance/InefficientHashSearch:
131
164
  VersionAdded: '0.56'
132
165
  Safe: false
133
166
 
167
+ Performance/IoReadlines:
168
+ Description: 'Use `IO.each_line` (`IO#each_line`) instead of `IO.readlines` (`IO#readlines`).'
169
+ Reference: 'https://docs.gitlab.com/ee/development/performance.html#reading-from-files-and-other-data-sources'
170
+ Enabled: false
171
+ VersionAdded: '1.7'
172
+
173
+ Performance/MethodObjectAsBlock:
174
+ Description: 'Use block explicitly instead of block-passing a method object.'
175
+ Reference: 'https://github.com/JuanitoFatas/fast-ruby#normal-way-to-apply-method-vs-method-code'
176
+ Enabled: pending
177
+ VersionAdded: '1.9'
178
+
134
179
  Performance/OpenStruct:
135
180
  Description: 'Use `Struct` instead of `OpenStruct`.'
136
181
  Enabled: false
@@ -138,10 +183,11 @@ Performance/OpenStruct:
138
183
  Safe: false
139
184
 
140
185
  Performance/RangeInclude:
141
- Description: 'Use `Range#cover?` instead of `Range#include?`.'
186
+ Description: 'Use `Range#cover?` instead of `Range#include?` (or `Range#member?`).'
142
187
  Reference: 'https://github.com/JuanitoFatas/fast-ruby#cover-vs-include-code'
143
188
  Enabled: true
144
189
  VersionAdded: '0.36'
190
+ VersionChanged: '1.7'
145
191
  Safe: false
146
192
 
147
193
  Performance/RedundantBlockCall:
@@ -165,6 +211,16 @@ Performance/RedundantMerge:
165
211
  # Max number of key-value pairs to consider an offense
166
212
  MaxKeyValuePairs: 2
167
213
 
214
+ Performance/RedundantSortBlock:
215
+ Description: 'Use `sort` instead of `sort { |a, b| a <=> b }`.'
216
+ Enabled: 'pending'
217
+ VersionAdded: '1.7'
218
+
219
+ Performance/RedundantStringChars:
220
+ Description: 'Checks for redundant `String#chars`.'
221
+ Enabled: 'pending'
222
+ VersionAdded: '1.7'
223
+
168
224
  Performance/RegexpMatch:
169
225
  Description: >-
170
226
  Use `match?` instead of `Regexp#match`, `String#match`, `Symbol#match`,
@@ -179,6 +235,11 @@ Performance/ReverseEach:
179
235
  Enabled: true
180
236
  VersionAdded: '0.30'
181
237
 
238
+ Performance/ReverseFirst:
239
+ Description: 'Use `last(n).reverse` instead of `reverse.first(n)`.'
240
+ Enabled: 'pending'
241
+ VersionAdded: '1.7'
242
+
182
243
  Performance/Size:
183
244
  Description: >-
184
245
  Use `size` instead of `count` for counting
@@ -187,6 +248,17 @@ Performance/Size:
187
248
  Enabled: true
188
249
  VersionAdded: '0.30'
189
250
 
251
+ Performance/SortReverse:
252
+ Description: 'Use `sort.reverse` instead of `sort { |a, b| b <=> a }`.'
253
+ Enabled: 'pending'
254
+ VersionAdded: '1.7'
255
+
256
+ Performance/Squeeze:
257
+ Description: "Use `squeeze('a')` instead of `gsub(/a+/, 'a')`."
258
+ Reference: 'https://github.com/JuanitoFatas/fast-ruby#remove-extra-spaces-or-other-contiguous-characters-code'
259
+ Enabled: 'pending'
260
+ VersionAdded: '1.7'
261
+
190
262
  Performance/StartWith:
191
263
  Description: 'Use `start_with?` instead of a regex match anchored to the beginning of a string.'
192
264
  Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringmatch-vs-stringstart_withstringend_with-code-start-code-end'
@@ -200,6 +272,13 @@ Performance/StartWith:
200
272
  VersionAdded: '0.36'
201
273
  VersionChanged: '1.6'
202
274
 
275
+ Performance/StringInclude:
276
+ Description: 'Use `String#include?` instead of a regex match with literal-only pattern.'
277
+ Enabled: 'pending'
278
+ AutoCorrect: false
279
+ SafeAutoCorrect: false
280
+ VersionAdded: '1.7'
281
+
203
282
  Performance/StringReplacement:
204
283
  Description: >-
205
284
  Use `tr` instead of `gsub` when you are replacing the same
@@ -209,6 +288,12 @@ Performance/StringReplacement:
209
288
  Enabled: true
210
289
  VersionAdded: '0.33'
211
290
 
291
+ Performance/Sum:
292
+ Description: 'Use `sum` instead of a custom array summation.'
293
+ Reference: 'https://blog.bigbinary.com/2016/11/02/ruby-2-4-introduces-enumerable-sum.html'
294
+ Enabled: 'pending'
295
+ VersionAdded: '1.8'
296
+
212
297
  Performance/TimesMap:
213
298
  Description: 'Checks for .times.map calls.'
214
299
  AutoCorrect: false
@@ -220,7 +305,9 @@ Performance/TimesMap:
220
305
  Performance/UnfreezeString:
221
306
  Description: 'Use unary plus to get an unfrozen string literal.'
222
307
  Enabled: true
308
+ SafeAutoCorrect: false
223
309
  VersionAdded: '0.50'
310
+ VersionChanged: '1.9'
224
311
 
225
312
  Performance/UriDefaultParser:
226
313
  Description: 'Use `URI::DEFAULT_PARSER` instead of `URI::Parser.new`.'
@@ -25,7 +25,7 @@ module RuboCop
25
25
  # (tricky: \s, \d, and so on are metacharacters, but other characters
26
26
  # escaped with a slash are just literals. LITERAL_REGEX takes all
27
27
  # that into account.)
28
- /\A\\A(?:#{Util::LITERAL_REGEX})+\z/.match?(regex_str)
28
+ /\A\\A(?:#{Util::LITERAL_REGEX})+\z/o.match?(regex_str)
29
29
  end
30
30
 
31
31
  def literal_at_start_with_caret?(regex_str)
@@ -35,21 +35,21 @@ module RuboCop
35
35
  # (tricky: \s, \d, and so on are metacharacters, but other characters
36
36
  # escaped with a slash are just literals. LITERAL_REGEX takes all
37
37
  # that into account.)
38
- /\A\^(?:#{Util::LITERAL_REGEX})+\z/.match?(regex_str)
38
+ /\A\^(?:#{Util::LITERAL_REGEX})+\z/o.match?(regex_str)
39
39
  end
40
40
 
41
41
  def literal_at_end_with_backslash_z?(regex_str)
42
42
  # is this regexp 'literal' in the sense of only matching literal
43
43
  # chars, rather than using metachars like . and * and so on?
44
44
  # also, is it anchored at the end of the string?
45
- /\A(?:#{Util::LITERAL_REGEX})+\\z\z/.match?(regex_str)
45
+ /\A(?:#{Util::LITERAL_REGEX})+\\z\z/o.match?(regex_str)
46
46
  end
47
47
 
48
48
  def literal_at_end_with_dollar?(regex_str)
49
49
  # is this regexp 'literal' in the sense of only matching literal
50
50
  # chars, rather than using metachars like . and * and so on?
51
51
  # also, is it anchored at the end of the string?
52
- /\A(?:#{Util::LITERAL_REGEX})+\$\z/.match?(regex_str)
52
+ /\A(?:#{Util::LITERAL_REGEX})+\$\z/o.match?(regex_str)
53
53
  end
54
54
 
55
55
  def drop_start_metacharacter(regexp_string)
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for cops checking `Enumerable#sort` blocks.
6
+ module SortBlock
7
+ extend NodePattern::Macros
8
+ include RangeHelp
9
+
10
+ def_node_matcher :sort_with_block?, <<~PATTERN
11
+ (block
12
+ $(send _ :sort)
13
+ (args (arg $_a) (arg $_b))
14
+ $send)
15
+ PATTERN
16
+
17
+ def_node_matcher :replaceable_body?, <<~PATTERN
18
+ (send (lvar %1) :<=> (lvar %2))
19
+ PATTERN
20
+
21
+ private
22
+
23
+ def sort_range(send, node)
24
+ range_between(send.loc.selector.begin_pos, node.loc.end.end_pos)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Performance
6
+ # This cop is used to identify usages of `ancestors.include?` and
7
+ # change them to use `<=` instead.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # A.ancestors.include?(B)
12
+ #
13
+ # # good
14
+ # A <= B
15
+ #
16
+ class AncestorsInclude < Base
17
+ include RangeHelp
18
+ extend AutoCorrector
19
+
20
+ MSG = 'Use `<=` instead of `ancestors.include?`.'
21
+ RESTRICT_ON_SEND = %i[include?].freeze
22
+
23
+ def_node_matcher :ancestors_include_candidate?, <<~PATTERN
24
+ (send (send $_subclass :ancestors) :include? $_superclass)
25
+ PATTERN
26
+
27
+ def on_send(node)
28
+ return unless (subclass, superclass = ancestors_include_candidate?(node))
29
+ return if subclass && !subclass.const_type?
30
+
31
+ add_offense(range(node)) do |corrector|
32
+ subclass_source = subclass ? subclass.source : 'self'
33
+
34
+ corrector.replace(node, "#{subclass_source} <= #{superclass.source}")
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def range(node)
41
+ location_of_ancestors = node.children[0].loc.selector.begin_pos
42
+ end_location = node.loc.selector.end_pos
43
+
44
+ range_between(location_of_ancestors, end_location)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Performance
6
+ # This cop identifies places where slicing arrays with semi-infinite ranges
7
+ # can be replaced by `Array#take` and `Array#drop`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # # array[..2]
12
+ # # array[...2]
13
+ # # array[2..]
14
+ # # array[2...]
15
+ # # array.slice(..2)
16
+ #
17
+ # # good
18
+ # array.take(3)
19
+ # array.take(2)
20
+ # array.drop(2)
21
+ # array.drop(2)
22
+ # array.take(3)
23
+ #
24
+ class ArraySemiInfiniteRangeSlice < Base
25
+ include RangeHelp
26
+ extend AutoCorrector
27
+ extend TargetRubyVersion
28
+
29
+ minimum_target_ruby_version 2.7
30
+
31
+ MSG = 'Use `%<prefer>s` instead of `%<current>s` with semi-infinite range.'
32
+
33
+ SLICE_METHODS = Set[:[], :slice].freeze
34
+ RESTRICT_ON_SEND = SLICE_METHODS
35
+
36
+ def_node_matcher :endless_range_slice?, <<~PATTERN
37
+ (send $_ $%SLICE_METHODS $#endless_range?)
38
+ PATTERN
39
+
40
+ def_node_matcher :endless_range?, <<~PATTERN
41
+ {
42
+ ({irange erange} nil? (int positive?))
43
+ ({irange erange} (int positive?) nil?)
44
+ }
45
+ PATTERN
46
+
47
+ def on_send(node)
48
+ endless_range_slice?(node) do |receiver, method_name, range_node|
49
+ prefer = range_node.begin ? :drop : :take
50
+ message = format(MSG, prefer: prefer, current: method_name)
51
+
52
+ add_offense(node, message: message) do |corrector|
53
+ corrector.replace(node, correction(receiver, range_node))
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def correction(receiver, range_node)
61
+ method_call = if range_node.begin
62
+ "drop(#{range_node.begin.value})"
63
+ elsif range_node.irange_type?
64
+ "take(#{range_node.end.value + 1})"
65
+ else
66
+ "take(#{range_node.end.value})"
67
+ end
68
+
69
+ "#{receiver.source}.#{method_call}"
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,46 @@
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
+ # # bad
12
+ # BigDecimal(1, 2)
13
+ # BigDecimal(1.2, 3, exception: true)
14
+ #
15
+ # # good
16
+ # BigDecimal('1', 2)
17
+ # BigDecimal('1.2', 3, exception: true)
18
+ #
19
+ class BigDecimalWithNumericArgument < Base
20
+ extend AutoCorrector
21
+
22
+ MSG = 'Convert numeric argument to string before passing to `BigDecimal`.'
23
+ RESTRICT_ON_SEND = %i[BigDecimal].freeze
24
+
25
+ def_node_matcher :big_decimal_with_numeric_argument?, <<~PATTERN
26
+ (send nil? :BigDecimal $numeric_type? ...)
27
+ PATTERN
28
+
29
+ def on_send(node)
30
+ return unless (numeric = big_decimal_with_numeric_argument?(node))
31
+ return if numeric.float_type? && specifies_precision?(node)
32
+
33
+ add_offense(numeric.source_range) do |corrector|
34
+ corrector.wrap(numeric, "'", "'")
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def specifies_precision?(node)
41
+ node.arguments.size > 1 && !node.arguments[1].hash_type?
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end