Skip to main content

Jump statements (return, break and next) move control flow out of the current code block. So any statements that come after a jump are dead code.

def foo(a)
i = 10
return a + i    # Noncompliant 
i += 1          # dead code
end

This rule applies whenever an `if statement is followed by one or more elsif statements; the final elsif should be followed by an else statement.

The requirement for a final else statement is defensive programming.

The else statement should either take appropriate action or contain a suitable comment as to why no action is taken. This is consistent with the requirement to have a final else clause in a case` statement.

if x == 0                                      
doSomething
elsif x == 1
doSomethingElse
end

Shared naming conventions allow teams to collaborate efficiently.

This rule raises an issue when a method name does not match a provided regular expression.

For example, with the default provided regular expression, the following method:

def methodName # Noncompliant
expr..
end

The case statement should be used only to clearly define some new branches in the control flow. As soon as a when clause contains too many statements this highly decreases the readability of the overall control flow statement. In such case, the content of the case clause should be extracted into a dedicated function.

case myVariable
when 0 then # Noncompliant: 6 lines till next "when"
methodCall1("")
methodCall2("")
methodCall3("")
methodCall4("")
methodCall5("")
methodCall6("")
when 1
# ...
end

Having all branches of a case or if chain with the same implementation indicates a problem.

In the following code:

if b == 0  # Noncompliant
doOneMoreThing()
else
doOneMoreThing()
end

b = a > 12 ? 4 : 4;  # Noncompliant

case i  # Noncompliant
when 1
doSomething()
when 2
doSomething()
when 3
doSomething()
else 
doSomething()
end

The requirement for a final else clause is defensive programming. The clause should either take appropriate action, or contain a suitable comment as to why no action is taken.

case param
when 1
do_something()
when 2
do_something_else()
end

Nested `case structures are difficult to understand because you can easily confuse the cases of an inner case as belonging to an outer statement. Therefore nested case statements should be avoided.

Specifically, you should structure your code to avoid the need for nested case statements, but if you cannot, then consider moving the inner case` to another function.

def foo(n, m)
case n
when 0
  case m  # Noncompliant; nested case
  when 0 then puts "0"
    # ...
  end
when 1 then puts "1"
else puts "2"
end
end

It is needlessly complex to invert the result of a boolean comparison. The opposite comparison should be made instead.

if  !(a == 2)  # Noncompliant
# ...
end

b = !(a < 10) # Noncompliant

Putting multiple statements on a single line lowers the code readability and makes debugging the code more complex.

Unresolved directive in <stdin> - include::{noncompliant}[]

Write one statement per line to improve readability.

Unresolved directive in <stdin> - include::{compliant}[]

if someCondition; puts "hello"; end # Noncompliant

The complexity of an expression is defined by the number of &&, || and condition ? ifTrue : ifFalse operators it contains.

A single expression’s complexity should not become too high to keep the code readable.

if ((condition1 && condition2) || (condition3 && condition4)) && condition5
...
end

Integer literals starting with a zero are octal rather than decimal values. While using octal values is fully supported, most developers do not have experience with them. They may not recognize octal values as such, mistaking them instead for decimal values.

my_number = 023 # Noncompliant. my_number will hold 19, not 23 - was this really expected?

Nested code - blocks of code inside blocks of code - is eventually necessary, but increases complexity. This is why keeping the code as flat as possible, by avoiding unnecessary nesting, is considered a good practice.

Merging if statements when possible will decrease the nesting of the code and improve its readability.

if a then
unless b then  # Noncompliant
# ...
end
end

An empty {operationName} is generally considered bad practice and can lead to confusion, readability, and maintenance issues. Empty {operationName}s bring no functionality and are misleading to others as they might think the {operationName} implementation fulfills a specific and identified requirement.

There are several reasons for a {operationName} not to have a body:

  • It is an unintentional omission, and should be fixed to prevent an unexpected behavior in production.

  • It is not yet, or never will be, supported. In this case an exception should be thrown.

  • The method is an intentionally-blank override. In this case a nested comment should explain the reason for the blank override.

def shouldNotBeEmpty()  # Noncompliant - method is empty
end

def notImplemented()  # Noncompliant - method is empty
end

def emptyOnPurpose()  # Noncompliant - method is empty
end

The use of parentheses, even those not required to enforce a desired order of operations, can clarify the intent behind a piece of code. However, redundant pairs of parentheses could be misleading and should be removed.

x = (y / 2 + 1)  # Compliant even if the parenthesis are ignored by the compiler

if a && ((x+y > 0))  # Noncompliant
# ...
end

return ((x + 1)) # Noncompliant

Shared naming conventions allow teams to collaborate efficiently.

This rule raises an issue when a class name does not match a provided regular expression.

class my_class # Noncompliant
...
end

There is no reason to re-assign a variable to itself. Either this statement is redundant and should be removed, or the re-assignment is a mistake and some other value or variable was intended for the assignment instead.

def set_name(name)
name = name
end

Duplicated string literals make the process of refactoring complex and error-prone, as any change would need to be propagated on all occurrences.

def foo()
prepare('action random1')    #Noncompliant - "action random1" is duplicated 3 times
execute('action random1')
release('action random1')
end

Two {func_name}s having the same implementation are suspicious. It might be that something else was intended. Or the duplication is intentional, which becomes a maintenance burden.

class Circle
def initialize(radius)
@radius = radius
end

def width=(size)
@radius = size / 2
update_shape()
end

def height=(size) # Noncompliant: duplicates width
@radius = size / 2
update_shape()
end

def updateShape()
...
end
end

Hardcoding IP addresses is security-sensitive. It has led in the past to the following vulnerabilities:

Today’s services have an ever-changing architecture due to their scaling and redundancy needs. It is a mistake to think that a service will always have the same IP address. When it does change, the hardcoded IP will have to be modified too. This will have an impact on the product development, delivery, and deployment:

  • The developers will have to do a rapid fix every time this happens, instead of having an operation team change a configuration file.

  • It misleads to use the same address in every environment (dev, sys, qa, prod).

Last but not least it has an effect on application security. Attackers might be able to decompile the code and thereby discover a potentially sensitive address. They can perform a Denial of Service attack on the service, try to get access to the system, or try to spoof the IP address to bypass security checks. Such attacks can always be possible, but in the case of a hardcoded IP address solving the issue will take more time, which will increase an attack’s impact.

ip = IP_ADDRESS; // Compliant

Developers often use TODO tags to mark areas in the code where additional work or improvements are needed but are not implemented immediately. However, these TODO tags sometimes get overlooked or forgotten, leading to incomplete or unfinished code. This rule aims to identify and address unattended TODO tags to ensure a clean and maintainable codebase. This description explores why this is a problem and how it can be fixed to improve the overall code quality.

def do_something()
# TODO
end

`if statements with conditions that are always false have the effect of making blocks of code non-functional. if statements with conditions that are always true are completely redundant, and make the code less readable.

There are three possible causes for the presence of such code:

  • An if statement was changed during debugging and that debug code has been committed.

  • Some value was left unset.

  • Some logic is not doing what the programmer thought it did.

In any of these cases, unconditional if` statements should be removed.

if true 
doSomething()
end
...
if false 
doSomethingElse()
end

An empty code block is confusing. It will require some effort from maintainers to determine if it is intentional or indicates the implementation is incomplete.

Unresolved directive in <stdin> - include::{example}[]

Removing or filling the empty code blocks takes away ambiguity and generally results in a more straightforward and less surprising code.

while @order.process_next; end # Compliant by exception

An unused local variable is a variable that has been declared but is not used anywhere in the block of code where it is defined. It is dead code, contributing to unnecessary complexity and leading to confusion when reading the code. Therefore, it should be removed from your code to maintain clarity and efficiency.

def number_of_minutes(hours)
seconds = 0 # Noncompliant - seconds is unused
hours * 60
end

A naming convention in software development is a set of guidelines for naming code elements like variables, functions, and classes. {identifier_capital_plural} hold the meaning of the written code. Their names should be meaningful and follow a consistent and easily recognizable pattern. Adhering to a consistent naming convention helps to make the code more readable and understandable, which makes it easier to maintain and debug. It also ensures consistency in the code, especially when multiple developers are working on the same project.

This rule checks that {identifier} names match a provided regular expression.

def show_something(text_Param) # Noncompliant
localVar = "" # Noncompliant
puts text_Param + localVar
end

Having two when clauses in a case statement or two branches in an if chain with the same implementation is at best duplicate code, and at worst a coding error.

if a >= 0 && a < 10
doFirstThing()
doTheThing()
elsif a >= 10 && a < 20
doTheOtherThing()
elsif a >= 20 && a < 50
doFirstThing()
doTheThing()   # Noncompliant; duplicates first condition
else
doTheRest()
end
I