Skip to content

Commit

Permalink
Merge pull request #202 from r7kamura/rails-route-ordered
Browse files Browse the repository at this point in the history
Add `Sevencop/RailsRouteOrdered` cop
  • Loading branch information
r7kamura committed May 13, 2024
2 parents c1def86 + 19a2d51 commit edcde6d
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Note that all cops are `Enabled: false` by default.
- [Sevencop/RailsDateAndTimeCalculation](lib/rubocop/cop/sevencop/rails_date_and_time_calculation.rb)
- [Sevencop/RailsOrderFieldArelSql](lib/rubocop/cop/sevencop/rails_order_field_arel_sql.rb)
- [Sevencop/RailsOrderFieldInOrderOf](lib/rubocop/cop/sevencop/rails_order_field_in_order_of.rb)
- [Sevencop/RailsRouteOrdered](lib/rubocop/cop/sevencop/rails_route_ordered.rb)
- [Sevencop/RailsSpecificActionName](lib/rubocop/cop/sevencop/rails_specific_action_name.rb)
- [Sevencop/RailsUniquenessValidatorExplicitCaseSensitivity](lib/rubocop/cop/sevencop/rails_uniqueness_validator_explicit_case_sensitivity.rb)
- [Sevencop/RailsWhereNot](lib/rubocop/cop/sevencop/rails_where_not.rb)
Expand Down
6 changes: 6 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ Sevencop/RailsOrderFieldInOrderOf:
Enabled: false
Safe: false

Sevencop/RailsRouteOrdered:
Description: |
Sort routes by path and HTTP method.
Enabled: false
Safe: false

Sevencop/RailsSpecificActionName:
Description: |
Use only specific action names.
Expand Down
90 changes: 90 additions & 0 deletions lib/rubocop/cop/sevencop/rails_route_ordered.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Sevencop
# Sort routes by path and HTTP method.
#
# @example
# # bad
# get "/users/:id" => "users#show"
# get "/users" => "users#index"
#
# # good
# get "/users" => "users#index"
# get "/users/:id" => "users#show"
#
# # bad
# post "/users" => "users#create"
# get "/users" => "users#index"
#
# # good
# get "/users" => "users#index"
# post "/users" => "users#create"
class RailsRouteOrdered < Base
extend AutoCorrector

include RangeHelp

MSG = 'Sort routes by path and HTTP method.'

RESTRICT_ON_SEND = %i[
delete
get
head
options
patch
post
put
].freeze

# @param [RuboCop::AST::SendNode] node
# @return [void]
def on_send(node)
previous_older_sibling = find_previous_older_sibling(node)
return unless previous_older_sibling

add_offense(node) do |corrector|
corrector.swap(
range_with_comments_and_lines(previous_older_sibling),
range_with_comments_and_lines(node)
)
end
end

private

# @param [RuboCop::AST::SendNode] node
# @return [Array<String>]
def convert_to_comparison_key(node)
[
find_path_node(node).source.tr(':', '~'),
node.method_name
]
end

# Find path node from both of the following styles:
# `get "/users" => "users#index`
# `get "/users", to: "users#index`
# @param [RuboCop::AST::SendNode] node
# @return [RuboCop::AST::Node, nil]
def find_path_node(node)
if node.first_argument.hash_type?
node.first_argument.keys.first
else
node.first_argument
end
end

# @param [RuboCop::AST::SendNode] node
# @return [RuboCop::AST::SendNode, nil]
def find_previous_older_sibling(node)
node.left_siblings.grep(::RuboCop::AST::SendNode).reverse.find do |sibling|
RESTRICT_ON_SEND.include?(sibling.method_name) &&
(convert_to_comparison_key(sibling) <=> convert_to_comparison_key(node)).positive?
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/sevencop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
require_relative 'rubocop/cop/sevencop/rails_date_and_time_calculation'
require_relative 'rubocop/cop/sevencop/rails_order_field_arel_sql'
require_relative 'rubocop/cop/sevencop/rails_order_field_in_order_of'
require_relative 'rubocop/cop/sevencop/rails_route_ordered'
require_relative 'rubocop/cop/sevencop/rails_specific_action_name'
require_relative 'rubocop/cop/sevencop/rails_uniqueness_validator_explicit_case_sensitivity'
require_relative 'rubocop/cop/sevencop/rails_where_not'
Expand Down
44 changes: 44 additions & 0 deletions spec/rubocop/cop/sevencop/rails_route_ordered_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe RuboCop::Cop::Sevencop::RailsRouteOrdered, :config do
context 'when routes are ordered' do
it 'registers no offense' do
expect_no_offenses(<<~RUBY)
get "/users" => "users#index"
get "/users/:id" => "users#show"
RUBY
end
end

context 'when routes are not ordered by path' do
it 'registers an offense' do
expect_offense(<<~RUBY)
get "/users/:id" => "users#show"
get "/users" => "users#index"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Sort routes by path and HTTP method.
RUBY

expect_correction(<<~RUBY)
get "/users" => "users#index"
get "/users/:id" => "users#show"
RUBY
end
end

context 'when routes are not ordered by HTTP method' do
it 'registers an offense' do
expect_offense(<<~RUBY)
post "/users" => "users#create"
get "/users" => "users#index"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Sort routes by path and HTTP method.
RUBY

expect_correction(<<~RUBY)
get "/users" => "users#index"
post "/users" => "users#create"
RUBY
end
end
end

0 comments on commit edcde6d

Please sign in to comment.