TracksApp/tracks

View on GitHub
app/models/recurring_todos/abstract_recurrence_pattern.rb

Summary

Maintainability
B
4 hrs
Test Coverage

Class AbstractRecurrencePattern has 33 methods (exceeds 20 allowed). Consider refactoring.
Open

  class AbstractRecurrencePattern
    attr_accessor :attributes

    def initialize(user)
      @user = user
Severity: Minor
Found in app/models/recurring_todos/abstract_recurrence_pattern.rb - About 4 hrs to fix

    RecurringTodos::AbstractRecurrencePattern#determine_start has approx 6 statements
    Open

        def determine_start(previous, offset = 0.day)

    A method with Too Many Statements is any method that has a large number of lines.

    Too Many Statements warns about any method that has more than 5 statements. Reek's smell detector for Too Many Statements counts +1 for every simple statement in a method and +1 for every statement within a control structure (if, else, case, when, for, while, until, begin, rescue) but it doesn't count the control structure itself.

    So the following method would score +6 in Reek's statement-counting algorithm:

    def parse(arg, argv, &error)
      if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
        return nil, block, nil                                         # +1
      end
      opt = (val = parse_arg(val, &error))[1]                          # +2
      val = conv_arg(*val)                                             # +3
      if opt and !arg
        argv.shift                                                     # +4
      else
        val[0] = nil                                                   # +5
      end
      val                                                              # +6
    end

    (You might argue that the two assigments within the first @if@ should count as statements, and that perhaps the nested assignment should count as +2.)

    RecurringTodos::AbstractRecurrencePattern#find_xth_day_of_month has 4 parameters
    Open

        def find_xth_day_of_month(x, weekday, month, year)

    A Long Parameter List occurs when a method has a lot of parameters.

    Example

    Given

    class Dummy
      def long_list(foo,bar,baz,fling,flung)
        puts foo,bar,baz,fling,flung
      end
    end

    Reek would report the following warning:

    test.rb -- 1 warning:
      [2]:Dummy#long_list has 5 parameters (LongParameterList)

    A common solution to this problem would be the introduction of parameter objects.

    RecurringTodos::AbstractRecurrencePattern#get_xth_day_of_month has 4 parameters
    Open

        def get_xth_day_of_month(x, weekday, month, year)

    A Long Parameter List occurs when a method has a lot of parameters.

    Example

    Given

    class Dummy
      def long_list(foo,bar,baz,fling,flung)
        puts foo,bar,baz,fling,flung
      end
    end

    Reek would report the following warning:

    test.rb -- 1 warning:
      [2]:Dummy#long_list has 5 parameters (LongParameterList)

    A common solution to this problem would be the introduction of parameter objects.

    RecurringTodos::AbstractRecurrencePattern#find_xth_day_of_month has approx 6 statements
    Open

        def find_xth_day_of_month(x, weekday, month, year)

    A method with Too Many Statements is any method that has a large number of lines.

    Too Many Statements warns about any method that has more than 5 statements. Reek's smell detector for Too Many Statements counts +1 for every simple statement in a method and +1 for every statement within a control structure (if, else, case, when, for, while, until, begin, rescue) but it doesn't count the control structure itself.

    So the following method would score +6 in Reek's statement-counting algorithm:

    def parse(arg, argv, &error)
      if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
        return nil, block, nil                                         # +1
      end
      opt = (val = parse_arg(val, &error))[1]                          # +2
      val = conv_arg(*val)                                             # +3
      if opt and !arg
        argv.shift                                                     # +4
      else
        val[0] = nil                                                   # +5
      end
      val                                                              # +6
    end

    (You might argue that the two assigments within the first @if@ should count as statements, and that perhaps the nested assignment should count as +2.)

    RecurringTodos::AbstractRecurrencePattern#determine_start refers to 'start' more than self (maybe move it to another class?)
    Open

            start > previous ? start : previous + offset
          else
            # skip to present
            now = Time.zone.now
            start > now ? start : now

    Feature Envy occurs when a code fragment references another object more often than it references itself, or when several clients do the same series of manipulations on a particular type of object.

    Feature Envy reduces the code's ability to communicate intent: code that "belongs" on one class but which is located in another can be hard to find, and may upset the "System of Names" in the host class.

    Feature Envy also affects the design's flexibility: A code fragment that is in the wrong class creates couplings that may not be natural within the application's domain, and creates a loss of cohesion in the unwilling host class.

    Feature Envy often arises because it must manipulate other objects (usually its arguments) to get them into a useful form, and one force preventing them (the arguments) doing this themselves is that the common knowledge lives outside the arguments, or the arguments are of too basic a type to justify extending that type. Therefore there must be something which 'knows' about the contents or purposes of the arguments. That thing would have to be more than just a basic type, because the basic types are either containers which don't know about their contents, or they are single objects which can't capture their relationship with their fellows of the same type. So, this thing with the extra knowledge should be reified into a class, and the utility method will most likely belong there.

    Example

    Running Reek on:

    class Warehouse
      def sale_price(item)
        (item.price - item.rebate) * @vat
      end
    end

    would report:

    Warehouse#total_price refers to item more than self (FeatureEnvy)

    since this:

    (item.price - item.rebate)

    belongs to the Item class, not the Warehouse.

    RecurringTodos::AbstractRecurrencePattern has at least 33 methods
    Open

      class AbstractRecurrencePattern

    Too Many Methods is a special case of LargeClass.

    Example

    Given this configuration

    TooManyMethods:
      max_methods: 3

    and this code:

    class TooManyMethods
      def one; end
      def two; end
      def three; end
      def four; end
    end

    Reek would emit the following warning:

    test.rb -- 1 warning:
      [1]:TooManyMethods has at least 4 methods (TooManyMethods)

    RecurringTodos::AbstractRecurrencePattern tests 'target' at least 4 times
    Open

          case target
          when 'show_from_date'
            # no validations
          when 'due_date'
            validate_not_nil(show_always?, "Please select when to show the action")

    Repeated Conditional is a special case of Simulated Polymorphism. Basically it means you are checking the same value throughout a single class and take decisions based on this.

    Example

    Given

    class RepeatedConditionals
      attr_accessor :switch
    
      def repeat_1
        puts "Repeat 1!" if switch
      end
    
      def repeat_2
        puts "Repeat 2!" if switch
      end
    
      def repeat_3
        puts "Repeat 3!" if switch
      end
    end

    Reek would emit the following warning:

    test.rb -- 4 warnings:
      [5, 9, 13]:RepeatedConditionals tests switch at least 3 times (RepeatedConditional)

    If you get this warning then you are probably not using the right abstraction or even more probable, missing an additional abstraction.

    RecurringTodos::AbstractRecurrencePattern assumes too much for instance variable '@recurring_todo'
    Open

      class AbstractRecurrencePattern

    Classes should not assume that instance variables are set or present outside of the current class definition.

    Good:

    class Foo
      def initialize
        @bar = :foo
      end
    
      def foo?
        @bar == :foo
      end
    end

    Good as well:

    class Foo
      def foo?
        bar == :foo
      end
    
      def bar
        @bar ||= :foo
      end
    end

    Bad:

    class Foo
      def go_foo!
        @bar = :foo
      end
    
      def foo?
        @bar == :foo
      end
    end

    Example

    Running Reek on:

    class Dummy
      def test
        @ivar
      end
    end

    would report:

    [1]:InstanceVariableAssumption: Dummy assumes too much for instance variable @ivar

    Note that this example would trigger this smell warning as well:

    class Parent
      def initialize(omg)
        @omg = omg
      end
    end
    
    class Child < Parent
      def foo
        @omg
      end
    end

    The way to address the smell warning is that you should create an attr_reader to use @omg in the subclass and not access @omg directly like this:

    class Parent
      attr_reader :omg
    
      def initialize(omg)
        @omg = omg
      end
    end
    
    class Child < Parent
      def foo
        omg
      end
    end

    Directly accessing instance variables is considered a smell because it breaks encapsulation and makes it harder to reason about code.

    If you don't want to expose those methods as public API just make them private like this:

    class Parent
      def initialize(omg)
        @omg = omg
      end
    
      private
      attr_reader :omg
    end
    
    class Child < Parent
      def foo
        omg
      end
    end

    Current Support in Reek

    An instance variable must:

    • be set in the constructor
    • or be accessed through a method with lazy initialization / memoization.

    If not, Instance Variable Assumption will be reported.

    RecurringTodos::AbstractRecurrencePattern has no descriptive comment
    Open

      class AbstractRecurrencePattern

    Classes and modules are the units of reuse and release. It is therefore considered good practice to annotate every class and module with a brief comment outlining its responsibilities.

    Example

    Given

    class Dummy
      # Do things...
    end

    Reek would emit the following warning:

    test.rb -- 1 warning:
      [1]:Dummy has no descriptive comment (IrresponsibleModule)

    Fixing this is simple - just an explaining comment:

    # The Dummy class is responsible for ...
    class Dummy
      # Do things...
    end

    RecurringTodos::AbstractRecurrencePattern#continues_recurring? calls '@recurring_todo.number_of_occurrences' 2 times
    Open

          return @recurring_todo.occurrences_count < @recurring_todo.number_of_occurrences unless @recurring_todo.number_of_occurrences.nil?

    Duplication occurs when two fragments of code look nearly identical, or when two fragments of code have nearly identical effects at some conceptual level.

    Reek implements a check for Duplicate Method Call.

    Example

    Here's a very much simplified and contrived example. The following method will report a warning:

    def double_thing()
      @other.thing + @other.thing
    end

    One quick approach to silence Reek would be to refactor the code thus:

    def double_thing()
      thing = @other.thing
      thing + thing
    end

    A slightly different approach would be to replace all calls of double_thing by calls to @other.double_thing:

    class Other
      def double_thing()
        thing + thing
      end
    end

    The approach you take will depend on balancing other factors in your code.

    RecurringTodos::AbstractRecurrencePattern#find_xth_day_of_month calls '1.day' 2 times
    Open

              start += 1.day
            end
            n -= 1
            start += 1.day unless n == 0

    Duplication occurs when two fragments of code look nearly identical, or when two fragments of code have nearly identical effects at some conceptual level.

    Reek implements a check for Duplicate Method Call.

    Example

    Here's a very much simplified and contrived example. The following method will report a warning:

    def double_thing()
      @other.thing + @other.thing
    end

    One quick approach to silence Reek would be to refactor the code thus:

    def double_thing()
      thing = @other.thing
      thing + thing
    end

    A slightly different approach would be to replace all calls of double_thing by calls to @other.double_thing:

    class Other
      def double_thing()
        thing + thing
      end
    end

    The approach you take will depend on balancing other factors in your code.

    RecurringTodos::AbstractRecurrencePattern assumes too much for instance variable '@attributes'
    Open

      class AbstractRecurrencePattern

    Classes should not assume that instance variables are set or present outside of the current class definition.

    Good:

    class Foo
      def initialize
        @bar = :foo
      end
    
      def foo?
        @bar == :foo
      end
    end

    Good as well:

    class Foo
      def foo?
        bar == :foo
      end
    
      def bar
        @bar ||= :foo
      end
    end

    Bad:

    class Foo
      def go_foo!
        @bar = :foo
      end
    
      def foo?
        @bar == :foo
      end
    end

    Example

    Running Reek on:

    class Dummy
      def test
        @ivar
      end
    end

    would report:

    [1]:InstanceVariableAssumption: Dummy assumes too much for instance variable @ivar

    Note that this example would trigger this smell warning as well:

    class Parent
      def initialize(omg)
        @omg = omg
      end
    end
    
    class Child < Parent
      def foo
        @omg
      end
    end

    The way to address the smell warning is that you should create an attr_reader to use @omg in the subclass and not access @omg directly like this:

    class Parent
      attr_reader :omg
    
      def initialize(omg)
        @omg = omg
      end
    end
    
    class Child < Parent
      def foo
        omg
      end
    end

    Directly accessing instance variables is considered a smell because it breaks encapsulation and makes it harder to reason about code.

    If you don't want to expose those methods as public API just make them private like this:

    class Parent
      def initialize(omg)
        @omg = omg
      end
    
      private
      attr_reader :omg
    end
    
    class Child < Parent
      def foo
        omg
      end
    end

    Current Support in Reek

    An instance variable must:

    • be set in the constructor
    • or be accessed through a method with lazy initialization / memoization.

    If not, Instance Variable Assumption will be reported.

    RecurringTodos::AbstractRecurrencePattern#put_in_tickler? performs a nil-check
    Open

          !(show_always? || show_from_delta.nil?)

    A NilCheck is a type check. Failures of NilCheck violate the "tell, don't ask" principle.

    Additionally, type checks often mask bigger problems in your source code like not using OOP and / or polymorphism when you should.

    Example

    Given

    class Klass
      def nil_checker(argument)
        if argument.nil?
          puts "argument isn't nil!"
        end
      end
    end

    Reek would emit the following warning:

    test.rb -- 1 warning:
      [3]:Klass#nil_checker performs a nil-check. (NilCheck)

    RecurringTodos::AbstractRecurrencePattern#validate_not_nil performs a nil-check
    Open

          errors[:base] << msg if object.nil?

    A NilCheck is a type check. Failures of NilCheck violate the "tell, don't ask" principle.

    Additionally, type checks often mask bigger problems in your source code like not using OOP and / or polymorphism when you should.

    Example

    Given

    class Klass
      def nil_checker(argument)
        if argument.nil?
          puts "argument isn't nil!"
        end
      end
    end

    Reek would emit the following warning:

    test.rb -- 1 warning:
      [3]:Klass#nil_checker performs a nil-check. (NilCheck)

    RecurringTodos::AbstractRecurrencePattern#xth doesn't depend on instance state (maybe move it to another class?)
    Open

        def xth(x)

    A Utility Function is any instance method that has no dependency on the state of the instance.

    RecurringTodos::AbstractRecurrencePattern#find_last_day_x_of_month doesn't depend on instance state (maybe move it to another class?)
    Open

        def find_last_day_x_of_month(weekday, month, year)

    A Utility Function is any instance method that has no dependency on the state of the instance.

    RecurringTodos::AbstractRecurrencePattern#day_of_week_as_text doesn't depend on instance state (maybe move it to another class?)
    Open

        def day_of_week_as_text(day)

    A Utility Function is any instance method that has no dependency on the state of the instance.

    RecurringTodos::AbstractRecurrencePattern#month_of_year_as_text doesn't depend on instance state (maybe move it to another class?)
    Open

        def month_of_year_as_text(month)

    A Utility Function is any instance method that has no dependency on the state of the instance.

    RecurringTodos::AbstractRecurrencePattern#update_recurring_todo doesn't depend on instance state (maybe move it to another class?)
    Open

        def update_recurring_todo(recurring_todo, attribute_handler)

    A Utility Function is any instance method that has no dependency on the state of the instance.

    RecurringTodos::AbstractRecurrencePattern#attributes is a writable attribute
    Open

        attr_accessor :attributes

    A class that publishes a setter for an instance variable invites client classes to become too intimate with its inner workings, and in particular with its representation of state.

    The same holds to a lesser extent for getters, but Reek doesn't flag those.

    Example

    Given:

    class Klass
      attr_accessor :dummy
    end

    Reek would emit the following warning:

    reek test.rb
    
    test.rb -- 1 warning:
      [2]:Klass declares the writable attribute dummy (Attribute)

    RecurringTodos::AbstractRecurrencePattern#xth performs a nil-check
    Open

          x.nil? ? '??' : xth_day[x - 1]

    A NilCheck is a type check. Failures of NilCheck violate the "tell, don't ask" principle.

    Additionally, type checks often mask bigger problems in your source code like not using OOP and / or polymorphism when you should.

    Example

    Given

    class Klass
      def nil_checker(argument)
        if argument.nil?
          puts "argument isn't nil!"
        end
      end
    end

    Reek would emit the following warning:

    test.rb -- 1 warning:
      [3]:Klass#nil_checker performs a nil-check. (NilCheck)

    RecurringTodos::AbstractRecurrencePattern#continues_recurring? performs a nil-check
    Open

          return @recurring_todo.occurrences_count < @recurring_todo.number_of_occurrences unless @recurring_todo.number_of_occurrences.nil?
          return true if end_date.nil? || ends_on == 'no_end_date'

    A NilCheck is a type check. Failures of NilCheck violate the "tell, don't ask" principle.

    Additionally, type checks often mask bigger problems in your source code like not using OOP and / or polymorphism when you should.

    Example

    Given

    class Klass
      def nil_checker(argument)
        if argument.nil?
          puts "argument isn't nil!"
        end
      end
    end

    Reek would emit the following warning:

    test.rb -- 1 warning:
      [3]:Klass#nil_checker performs a nil-check. (NilCheck)

    RecurringTodos::AbstractRecurrencePattern takes parameters ['month', 'weekday', 'year'] to 3 methods
    Open

        def get_xth_day_of_month(x, weekday, month, year)
          raise "Weekday should be between 0 and 6 with 0=sunday. You supplied #{weekday}" unless (0..6).cover?(weekday)
          raise "x should be 1-4 for first-fourth or 5 for last. You supplied #{x}" unless (0..5).cover?(x)
    
          if x == 5

    In general, a Data Clump occurs when the same two or three items frequently appear together in classes and parameter lists, or when a group of instance variable names start or end with similar substrings.

    The recurrence of the items often means there is duplicate code spread around to handle them. There may be an abstraction missing from the code, making the system harder to understand.

    Example

    Given

    class Dummy
      def x(y1,y2); end
      def y(y1,y2); end
      def z(y1,y2); end
    end

    Reek would emit the following warning:

    test.rb -- 1 warning:
      [2, 3, 4]:Dummy takes parameters [y1, y2] to 3 methods (DataClump)

    A possible way to fix this problem (quoting from Martin Fowler):

    The first step is to replace data clumps with objects and use the objects whenever you see them. An immediate benefit is that you'll shrink some parameter lists. The interesting stuff happens as you begin to look for behavior to move into the new objects.

    RecurringTodos::AbstractRecurrencePattern#month_of_year_as_text performs a nil-check
    Open

          month.nil? ? '??' : I18n.t('todos.recurrence.pattern.month_names')[month]

    A NilCheck is a type check. Failures of NilCheck violate the "tell, don't ask" principle.

    Additionally, type checks often mask bigger problems in your source code like not using OOP and / or polymorphism when you should.

    Example

    Given

    class Klass
      def nil_checker(argument)
        if argument.nil?
          puts "argument isn't nil!"
        end
      end
    end

    Reek would emit the following warning:

    test.rb -- 1 warning:
      [3]:Klass#nil_checker performs a nil-check. (NilCheck)

    RecurringTodos::AbstractRecurrencePattern#find_xth_day_of_month doesn't depend on instance state (maybe move it to another class?)
    Open

        def find_xth_day_of_month(x, weekday, month, year)

    A Utility Function is any instance method that has no dependency on the state of the instance.

    RecurringTodos::AbstractRecurrencePattern#day_of_week_as_text performs a nil-check
    Open

          day.nil? ? '??' : I18n.t('todos.recurrence.pattern.day_names')[day]

    A NilCheck is a type check. Failures of NilCheck violate the "tell, don't ask" principle.

    Additionally, type checks often mask bigger problems in your source code like not using OOP and / or polymorphism when you should.

    Example

    Given

    class Klass
      def nil_checker(argument)
        if argument.nil?
          puts "argument isn't nil!"
        end
      end
    end

    Reek would emit the following warning:

    test.rb -- 1 warning:
      [3]:Klass#nil_checker performs a nil-check. (NilCheck)

    Complex method RecurringTodos::AbstractRecurrencePattern#continues_recurring? (20.7)
    Open

        def continues_recurring?(previous)
          return @recurring_todo.occurrences_count < @recurring_todo.number_of_occurrences unless @recurring_todo.number_of_occurrences.nil?
          return true if end_date.nil? || ends_on == 'no_end_date'
    
          case target

    Flog calculates the ABC score for methods. The ABC score is based on assignments, branches (method calls), and conditions.

    You can read more about ABC metrics or the flog tool

    RecurringTodos::AbstractRecurrencePattern#get_next_date has unused parameter 'previous'
    Open

        def get_next_date(previous)

    Unused Parameter refers to methods with parameters that are unused in scope of the method.

    Having unused parameters in a method is code smell because leaving dead code in a method can never improve the method and it makes the code confusing to read.

    Example

    Given:

    class Klass
      def unused_parameters(x,y,z)
        puts x,y # but not z
      end
    end

    Reek would emit the following warning:

    [2]:Klass#unused_parameters has unused parameter 'z' (UnusedParameters)

    RecurringTodos::AbstractRecurrencePattern#xth has the parameter name 'x'
    Open

        def xth(x)

    An Uncommunicative Parameter Name is a parameter name that doesn't communicate its intent well enough.

    Poor names make it hard for the reader to build a mental picture of what's going on in the code. They can also be mis-interpreted; and they hurt the flow of reading, because the reader must slow down to interpret the names.

    RecurringTodos::AbstractRecurrencePattern#get_xth_day_of_month has the parameter name 'x'
    Open

        def get_xth_day_of_month(x, weekday, month, year)

    An Uncommunicative Parameter Name is a parameter name that doesn't communicate its intent well enough.

    Poor names make it hard for the reader to build a mental picture of what's going on in the code. They can also be mis-interpreted; and they hurt the flow of reading, because the reader must slow down to interpret the names.

    RecurringTodos::AbstractRecurrencePattern#find_xth_day_of_month has the parameter name 'x'
    Open

        def find_xth_day_of_month(x, weekday, month, year)

    An Uncommunicative Parameter Name is a parameter name that doesn't communicate its intent well enough.

    Poor names make it hard for the reader to build a mental picture of what's going on in the code. They can also be mis-interpreted; and they hurt the flow of reading, because the reader must slow down to interpret the names.

    RecurringTodos::AbstractRecurrencePattern#find_xth_day_of_month has the variable name 'n'
    Open

          n = x
          while n > 0
            while start.wday() != weekday
              start += 1.day
            end

    An Uncommunicative Variable Name is a variable name that doesn't communicate its intent well enough.

    Poor names make it hard for the reader to build a mental picture of what's going on in the code. They can also be mis-interpreted; and they hurt the flow of reading, because the reader must slow down to interpret the names.

    Prefer 0.days.
    Open

        def determine_start(previous, offset = 0.day)

    This cop checks for correct grammar when using ActiveSupport's core extensions to the numeric classes.

    Example:

    # bad
    3.day.ago
    1.months.ago
    
    # good
    3.days.ago
    1.month.ago

    Avoid when branches without a body.
    Open

          when 'show_from_date'

    This cop checks for the presence of when branches without a body.

    Example:

    # bad
    
    case foo
    when bar then 1
    when baz then # nothing
    end

    Example:

    # good
    
    case foo
    when bar then 1
    when baz then 2
    end

    Do not use Time.local without zone. Use one of Time.zone.local, Time.current, Time.local.in_time_zone, Time.local.utc, Time.local.getlocal, Time.local.iso8601, Time.local.jisx0301, Time.local.rfc3339, Time.local.to_i, Time.local.to_f instead.
    Open

          last_day = Time.zone.local(year, month, Time.days_in_month(month))

    This cop checks for the use of Time methods without zone.

    Built on top of Ruby on Rails style guide (https://github.com/bbatsov/rails-style-guide#time) and the article http://danilenko.org/2012/7/6/rails_timezones/ .

    Two styles are supported for this cop. When EnforcedStyle is 'strict' then only use of Time.zone is allowed.

    When EnforcedStyle is 'flexible' then it's also allowed to use Time.intimezone.

    Example:

    # always offense
    Time.now
    Time.parse('2015-03-02 19:05:37')
    
    # no offense
    Time.zone.now
    Time.zone.parse('2015-03-02 19:05:37')
    
    # no offense only if style is 'flexible'
    Time.current
    DateTime.strptime(str, "%Y-%m-%d %H:%M %Z").in_time_zone
    Time.at(timestamp).in_time_zone

    Use n.positive? instead of n > 0.
    Open

          while n > 0

    This cop checks for usage of comparison operators (==, >, <) to test numbers as zero, positive, or negative. These can be replaced by their respective predicate methods. The cop can also be configured to do the reverse.

    The cop disregards #nonzero? as it its value is truthy or falsey, but not true and false, and thus not always interchangeable with != 0.

    The cop ignores comparisons to global variables, since they are often populated with objects which can be compared with integers, but are not themselves Interger polymorphic.

    Example: EnforcedStyle: predicate (default)

    # bad
    
    foo == 0
    0 > foo
    bar.baz > 0
    
    # good
    
    foo.zero?
    foo.negative?
    bar.baz.positive?

    Example: EnforcedStyle: comparison

    # bad
    
    foo.zero?
    foo.negative?
    bar.baz.positive?
    
    # good
    
    foo == 0
    0 > foo
    bar.baz > 0

    Line is too long. [137/120]
    Open

            validate_not_blank(show_from_delta, "Please fill in the number of days to show the todo before the due date") unless show_always?

    Favor modifier while usage when having a single-line body.
    Open

          while last_day.wday != weekday

    Checks for while and until statements that would fit on one line if written as a modifier while/until. The maximum line length is configured in the Metrics/LineLength cop.

    Example:

    # bad
    while x < 10
      x += 1
    end
    
    # good
    x += 1 while x < 10

    Example:

    # bad
    until x > 10
      x += 1
    end
    
    # good
    x += 1 until x > 10

    Unused method argument - previous. If it's necessary, use _ or _previous as an argument name to indicate that it won't be used. You can also write as get_next_date(*) if you want the method to accept any arguments but don't care about them.
    Open

        def get_next_date(previous)

    This cop checks for unused method arguments.

    Example:

    # bad
    
    def some_method(used, unused, _unused_but_allowed)
      puts used
    end

    Example:

    # good
    
    def some_method(used, _unused, _unused_but_allowed)
      puts used
    end

    Do not use parentheses for method calls with no arguments.
    Open

            while start.wday() != weekday

    This cop checks for unwanted parentheses in parameterless method calls.

    Example:

    # bad
    object.some_method()
    
    # good
    object.some_method

    Missing magic comment # frozen_string_literal: true.
    Open

    module RecurringTodos

    This cop is designed to help upgrade to Ruby 3.0. It will add the comment # frozen_string_literal: true to the top of files to enable frozen string literals. Frozen string literals may be default in Ruby 3.0. The comment will be added below a shebang and encoding comment. The frozen string literal comment is only valid in Ruby 2.3+.

    Example: EnforcedStyle: when_needed (default)

    # The `when_needed` style will add the frozen string literal comment
    # to files only when the `TargetRubyVersion` is set to 2.3+.
    # bad
    module Foo
      # ...
    end
    
    # good
    # frozen_string_literal: true
    
    module Foo
      # ...
    end

    Example: EnforcedStyle: always

    # The `always` style will always add the frozen string literal comment
    # to a file, regardless of the Ruby version or if `freeze` or `<<` are
    # called on a string literal.
    # bad
    module Bar
      # ...
    end
    
    # good
    # frozen_string_literal: true
    
    module Bar
      # ...
    end

    Example: EnforcedStyle: never

    # The `never` will enforce that the frozen string literal comment does
    # not exist in a file.
    # bad
    # frozen_string_literal: true
    
    module Baz
      # ...
    end
    
    # good
    module Baz
      # ...
    end

    Favor modifier while usage when having a single-line body.
    Open

            while start.wday() != weekday

    Checks for while and until statements that would fit on one line if written as a modifier while/until. The maximum line length is configured in the Metrics/LineLength cop.

    Example:

    # bad
    while x < 10
      x += 1
    end
    
    # good
    x += 1 while x < 10

    Example:

    # bad
    until x > 10
      x += 1
    end
    
    # good
    x += 1 until x > 10

    Line is too long. [136/120]
    Open

          return @recurring_todo.occurrences_count < @recurring_todo.number_of_occurrences unless @recurring_todo.number_of_occurrences.nil?

    Use n.zero? instead of n == 0.
    Open

            start += 1.day unless n == 0

    This cop checks for usage of comparison operators (==, >, <) to test numbers as zero, positive, or negative. These can be replaced by their respective predicate methods. The cop can also be configured to do the reverse.

    The cop disregards #nonzero? as it its value is truthy or falsey, but not true and false, and thus not always interchangeable with != 0.

    The cop ignores comparisons to global variables, since they are often populated with objects which can be compared with integers, but are not themselves Interger polymorphic.

    Example: EnforcedStyle: predicate (default)

    # bad
    
    foo == 0
    0 > foo
    bar.baz > 0
    
    # good
    
    foo.zero?
    foo.negative?
    bar.baz.positive?

    Example: EnforcedStyle: comparison

    # bad
    
    foo.zero?
    foo.negative?
    bar.baz.positive?
    
    # good
    
    foo == 0
    0 > foo
    bar.baz > 0

    Use a guard clause instead of wrapping the code inside a conditional expression.
    Open

          if x == 5

    Use a guard clause instead of wrapping the code inside a conditional expression

    Example:

    # bad
    def test
      if something
        work
      end
    end
    
    # good
    def test
      return unless something
      work
    end
    
    # also good
    def test
      work if something
    end
    
    # bad
    if something
      raise 'exception'
    else
      ok
    end
    
    # good
    raise 'exception' if something
    ok

    There are no issues that match your filters.

    Category
    Status