Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new Style/ExponentialNotation cop #7851

Merged
merged 1 commit into from Apr 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,7 @@
* [#7862](https://github.com/rubocop-hq/rubocop/issues/7862): Corrector now has a `wrap` method. ([@marcandre][])
* [#7850](https://github.com/rubocop-hq/rubocop/issues/7850): Make it possible to enable/disable pending cops. ([@koic][])
* [#7861](https://github.com/rubocop-hq/rubocop/issues/7861): Make it to allow `Style/CaseEquality` when the receiver is a constant. ([@rafaelfranca][])
* Add a new `Style/ExponentialNotation` cop. ([@tdeo][])

### Bug fixes

Expand Down
11 changes: 11 additions & 0 deletions config/default.yml
Expand Up @@ -2757,6 +2757,17 @@ Style/ExpandPathArguments:
Enabled: true
VersionAdded: '0.53'

Style/ExponentialNotation:
Description: 'When using exponential notation, favor a mantissa between 1 (inclusive) and 10 (exclusive).'
StyleGuide: '#exponential-notation'
Enabled: pending
VersionAdded: '0.82'
EnforcedStyle: scientific
SupportedStyles:
- scientific
- engineering
- integral

Style/FloatDivision:
Description: 'For performing float division, coerce one side only.'
StyleGuide: '#float-division'
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Expand Up @@ -441,6 +441,7 @@
require_relative 'rubocop/cop/style/eval_with_location'
require_relative 'rubocop/cop/style/even_odd'
require_relative 'rubocop/cop/style/expand_path_arguments'
require_relative 'rubocop/cop/style/exponential_notation'
require_relative 'rubocop/cop/style/float_division'
require_relative 'rubocop/cop/style/for'
require_relative 'rubocop/cop/style/format_string'
Expand Down
119 changes: 119 additions & 0 deletions lib/rubocop/cop/style/exponential_notation.rb
@@ -0,0 +1,119 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Style
# This cop enforces consistency when using exponential notation
# for numbers in the code (eg 1.2e4). Different styles are supported:
# - `scientific` which enforces a mantissa between 1 (inclusive)
# and 10 (exclusive).
# - `engineering` which enforces the exponent to be a multiple of 3
# and the mantissa to be between 0.1 (inclusive)
# and 10 (exclusive).
# - `integral` which enforces the mantissa to always be a whole number
# without trailing zeroes.
#
# @example EnforcedStyle: scientific (default)
# # Enforces a mantissa between 1 (inclusive) and 10 (exclusive).
#
# # bad
# 10e6
# 0.3e4
# 11.7e5
# 3.14e0
#
# # good
# 1e7
# 3e3
# 1.17e6
# 3.14
#
# @example EnforcedStyle: engineering
# # Enforces using multiple of 3 exponents,
# # mantissa should be between 0.1 (inclusive) and 1000 (exclusive)
#
# # bad
# 3.2e7
# 0.1e5
# 12e5
# 1232e6
#
# # good
# 32e6
# 10e3
# 1.2e6
# 1.232e9
#
# @example EnforcedStyle: integral
# # Enforces the mantissa to have no decimal part and no
# # trailing zeroes.
#
# # bad
# 3.2e7
# 0.1e5
# 120e4
#
# # good
# 32e6
# 1e4
# 12e5
#
class ExponentialNotation < Cop
include ConfigurableEnforcedStyle

def on_float(node)
add_offense(node) if offense?(node)
end

private

def scientific?(node)
mantissa, = node.source.split('e')
mantissa =~ /^-?[1-9](\.\d*[0-9])?$/
end

def engineering?(node)
mantissa, exponent = node.source.split('e')
return false unless exponent =~ /^-?\d+$/
return false unless (exponent.to_i % 3).zero?
return false if mantissa =~ /^-?\d{4}/
return false if mantissa =~ /^-?0\d/
return false if mantissa =~ /^-?0.0/

true
end

def integral(node)
mantissa, = node.source.split('e')
mantissa =~ /^-?[1-9](\d*[1-9])?$/
end

def offense?(node)
return false unless node.source['e']

case style
when :scientific
!scientific?(node)
when :engineering
!engineering?(node)
when :integral
!integral(node)
else
false
end
end

def message(_node)
case style
when :scientific
'Use a mantissa in [1, 10[.'
when :engineering
'Use an exponent divisible by 3 and a mantissa in [0.1, 1000[.'
when :integral
'Use an integer as mantissa, without trailing zero.'
end
end
end
end
end
end
1 change: 1 addition & 0 deletions manual/cops.md
Expand Up @@ -352,6 +352,7 @@ In the following section you find all available cops:
* [Style/EvalWithLocation](cops_style.md#styleevalwithlocation)
* [Style/EvenOdd](cops_style.md#styleevenodd)
* [Style/ExpandPathArguments](cops_style.md#styleexpandpatharguments)
* [Style/ExponentialNotation](cops_style.md#styleexponentialnotation)
* [Style/FloatDivision](cops_style.md#stylefloatdivision)
* [Style/For](cops_style.md#stylefor)
* [Style/FormatString](cops_style.md#styleformatstring)
Expand Down
80 changes: 80 additions & 0 deletions manual/cops_style.md
Expand Up @@ -2101,6 +2101,86 @@ Pathname.new(__FILE__).parent.expand_path
Pathname.new(__dir__).expand_path
```

## Style/ExponentialNotation

Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
--- | --- | --- | --- | ---
Pending | Yes | No | 0.82 | -

This cop enforces consistency when using exponential notation
for numbers in the code (eg 1.2e4). Different styles are supported:
- `scientific` which enforces a mantissa between 1 (inclusive)
and 10 (exclusive).
- `engineering` which enforces the exponent to be a multiple of 3
and the mantissa to be between 0.1 (inclusive)
and 10 (exclusive).
- `integral` which enforces the mantissa to always be a whole number
without trailing zeroes.

### Examples

#### EnforcedStyle: scientific (default)

```ruby
# Enforces a mantissa between 1 (inclusive) and 10 (exclusive).
# bad
10e6
0.3e4
11.7e5
3.14e0
# good
1e7
3e3
1.17e6
3.14
```
#### EnforcedStyle: engineering

```ruby
# Enforces using multiple of 3 exponents,
# mantissa should be between 0.1 (inclusive) and 1000 (exclusive)
# bad
3.2e7
0.1e5
12e5
1232e6
# good
32e6
10e3
1.2e6
1.232e9
```
#### EnforcedStyle: integral

```ruby
# Enforces the mantissa to have no decimal part and no
# trailing zeroes.
# bad
3.2e7
0.1e5
120e4
# good
32e6
1e4
12e5
```

### Configurable attributes

Name | Default value | Configurable values
--- | --- | ---
EnforcedStyle | `scientific` | `scientific`, `engineering`, `integral`

### References

* [https://rubystyle.guide#exponential-notation](https://rubystyle.guide#exponential-notation)

## Style/FloatDivision

Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
Expand Down