|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +module RuboCop |
| 4 | + module Cop |
| 5 | + module Rails |
| 6 | + # Checks whether the word orders of relative dates are grammatically easy to understand. |
| 7 | + # |
| 8 | + # @safety |
| 9 | + # This cop is unsafe because it avoids strict checking of receivers' types, |
| 10 | + # ActiveSupport::Duration and Date(Time) respectively. |
| 11 | + # |
| 12 | + # @example |
| 13 | + # # bad |
| 14 | + # tomorrow = Time.current.since(1.day) |
| 15 | + # |
| 16 | + # # good |
| 17 | + # tomorrow = 1.day.since(Time.current) |
| 18 | + class RelativeDateGrammar < Base |
| 19 | + extend AutoCorrector |
| 20 | + |
| 21 | + MSG = 'Prefer ActiveSupport::Duration#%<relation>s as a receiver ' \ |
| 22 | + 'for relative date like `%<duration>s.%<relation>s(%<date>s)`.' |
| 23 | + |
| 24 | + RELATIVE_DATE_METHODS = %i[since from_now after ago until before].to_set.freeze |
| 25 | + DURATION_METHODS = %i[second seconds minute minutes hour hours |
| 26 | + day days week weeks month months year years].to_set.freeze |
| 27 | + |
| 28 | + RESTRICT_ON_SEND = RELATIVE_DATE_METHODS.to_a.freeze |
| 29 | + |
| 30 | + def_node_matcher :inverted_relative_date?, <<~PATTERN |
| 31 | + (send |
| 32 | + $!nil? |
| 33 | + $RELATIVE_DATE_METHODS |
| 34 | + $(send |
| 35 | + !nil? |
| 36 | + $DURATION_METHODS |
| 37 | + ) |
| 38 | + ) |
| 39 | + PATTERN |
| 40 | + |
| 41 | + def on_send(node) |
| 42 | + inverted_relative_date?(node) do |date, relation, duration| |
| 43 | + message = format(MSG, date: date.source, relation: relation.to_s, duration: duration.source) |
| 44 | + add_offense(node, message: message) do |corrector| |
| 45 | + autocorrect(corrector, node, date, relation, duration) |
| 46 | + end |
| 47 | + end |
| 48 | + end |
| 49 | + |
| 50 | + private |
| 51 | + |
| 52 | + def autocorrect(corrector, node, date, relation, duration) |
| 53 | + new_code = ["#{duration.source}.#{relation}(#{date.source})"] |
| 54 | + corrector.replace(node, new_code) |
| 55 | + end |
| 56 | + end |
| 57 | + end |
| 58 | + end |
| 59 | +end |
0 commit comments