diff --git a/.rubocop.yml b/.rubocop.yml index cc32da4..8aa1dfd 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1 +1,47 @@ -inherit_from: .rubocop_todo.yml +require: + - rubocop-rails + - ./lib/rubocop/init_autoloader + +AllCops: + TargetRubyVersion: 3.3.0 + Exclude: + - "spec/**/*.rb" + - "db/**/*" + - "config/**/*" + - "bin/**/*" +################### +# Custom Cops # +################### +Custom/PrivateMethodStyle: + Enabled: true +################### +# End Custom Cops # +################### +Layout/IndentationWidth: + Enabled: true + Width: 2 +Lint/UnusedMethodArgument: + AutoCorrect: false +Metrics/AbcSize: + Exclude: + - "lib/mixins/**/*" +Metrics/CyclomaticComplexity: + Exclude: + - "lib/rubocop/cop/custom/*.rb" +Metrics/MethodLength: + Exclude: + - "lib/rubocop/cop/custom/*.rb" + - "lib/mixins/**/*" +Metrics/PerceivedComplexity: + Exclude: + - "lib/rubocop/cop/custom/*.rb" +Style/AccessModifierDeclarations: + EnforcedStyle: inline +Style/Documentation: + Enabled: false +Style/Lambda: + EnforcedStyle: literal +Style/RedundantArgument: + AutoCorrect: false +Style/StringLiterals: + EnforcedStyle: double_quotes diff --git a/Gemfile b/Gemfile index ca4d380..f3666a7 100644 --- a/Gemfile +++ b/Gemfile @@ -1,15 +1,17 @@ -source 'https://rubygems.org' +# frozen_string_literal: true -ruby '3.3.0' +source "https://rubygems.org" + +ruby "3.3.0" # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" -gem 'rails', '~> 7.1.3', '>= 7.1.3.4' +gem "rails", "~> 7.1.3", ">= 7.1.3.4" # Use postgresql as the database for Active Record -gem 'pg', '~> 1.1' +gem "pg", "~> 1.1" # Use the Puma web server [https://github.com/puma/puma] -gem 'puma', '>= 5.0' +gem "puma", ">= 5.0" # Build JSON APIs with ease [https://github.com/rails/jbuilder] # gem "jbuilder" @@ -24,14 +26,15 @@ gem 'puma', '>= 5.0' # gem "bcrypt", "~> 3.1.7" # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem 'rubocop', require: false -gem 'tzinfo-data', platforms: %i[windows jruby] +gem "rubocop", require: false +gem "rubocop-rails", require: false +gem "tzinfo-data", platforms: %i[windows jruby] # Reduces boot times through caching; required in config/boot.rb -gem 'bootsnap', require: false -gem 'database_cleaner' -gem 'faraday' -gem 'figaro' +gem "bootsnap", require: false +gem "database_cleaner" +gem "faraday" +gem "figaro" # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] # gem "image_processing", "~> 1.2" @@ -40,13 +43,13 @@ gem 'figaro' group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem - gem 'debug', platforms: %i[mri windows] - gem 'factory_bot_rails', '~> 4.0' - gem 'pry-rails' - gem 'rspec-rails' - gem 'shoulda-matchers' - gem 'vcr' - gem 'webmock' + gem "debug", platforms: %i[mri windows] + gem "factory_bot_rails", "~> 4.0" + gem "pry-rails" + gem "rspec-rails" + gem "shoulda-matchers" + gem "vcr" + gem "webmock" end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 372f3fa..c39eba5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -255,6 +255,11 @@ GEM unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.31.3) parser (>= 3.3.1.0) + rubocop-rails (2.24.1) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.33.0, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (1.13.0) shoulda-matchers (6.2.0) activesupport (>= 5.2.0) @@ -298,6 +303,7 @@ DEPENDENCIES rails (~> 7.1.3, >= 7.1.3.4) rspec-rails rubocop + rubocop-rails shoulda-matchers tzinfo-data vcr diff --git a/Rakefile b/Rakefile index 9a5ea73..d2a78aa 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb index d672697..9aec230 100644 --- a/app/channels/application_cable/channel.rb +++ b/app/channels/application_cable/channel.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Channel < ActionCable::Channel::Base end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index 0ff5442..8d6c2a1 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Connection < ActionCable::Connection::Base end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4ac8823..13c271f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class ApplicationController < ActionController::API end diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index d394c3d..bef3959 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationJob < ActiveJob::Base # Automatically retry jobs that encountered a deadlock # retry_on ActiveRecord::Deadlocked diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 3c34c81..5cc63a0 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationMailer < ActionMailer::Base default from: "from@example.com" layout "mailer" diff --git a/app/models/application_record.rb b/app/models/application_record.rb index b63caeb..08dc537 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationRecord < ActiveRecord::Base primary_abstract_class end diff --git a/config.ru b/config.ru index 4a3c09a..2e03084 100644 --- a/config.ru +++ b/config.ru @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This file is used by Rack-based servers to start the application. require_relative "config/environment" diff --git a/config/environments/development.rb b/config/environments/development.rb index f962d9f..43ff593 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -68,4 +68,12 @@ # Raise error when a before_action's only/except options reference missing actions config.action_controller.raise_on_missing_callback_actions = true + + config.generators.after_generate do |files| + parsable_files = files.filter { |file| file.end_with?('.rb') } + unless parsable_files.empty? + system("bundle exec rubocop -A --fail-level=E #{parsable_files.shelljoin}", exception: true) + end + end + end diff --git a/lib/rubocop/cop/custom/private_method_style.rb b/lib/rubocop/cop/custom/private_method_style.rb new file mode 100644 index 0000000..506e32d --- /dev/null +++ b/lib/rubocop/cop/custom/private_method_style.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true +# typed: false + +require "rubocop" + +module RuboCop + module Cop + module Custom + # This cop enforces that private methods are defined using + # `private def` for instance methods or + # `private_class_method def self` for class methods. + class PrivateMethodStyle < Base + MSG_INSTANCE = "Use `private def` for instance methods." + MSG_CLASS = "Use `private_class_method def self` for class methods." + + def on_def(node) + method_name = node.children[0]&.to_s + + return unless class_method_definition?(node) + + Rails.logger.debug "Checking method: #{method_name}" + add_offense(node, message: MSG_CLASS) + end + + private def class_method_definition?(node) + node.defs_type? && node.children[0]&.to_s == "self.use_collection" + end + + private def instance_method?(node) + return false unless node.def_type? + + method_name, _args, _body = *node + method_name.to_s.start_with?("def") && !node.singleton_method? + end + + private def class_method?(node) + return false unless node.defs_type? + + _scope, method_name, _args, _body = *node + method_name.to_s.start_with?("self.") && !node.arguments? && !node.singleton_method? + end + end + end + end +end diff --git a/lib/rubocop/init_autoloader.rb b/lib/rubocop/init_autoloader.rb new file mode 100644 index 0000000..cd04e6f --- /dev/null +++ b/lib/rubocop/init_autoloader.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +# Load all Ruby files in the custom directory +Dir[File.join(__dir__, "**/*.rb")].each { |file| require file } diff --git a/lib/tasks/rubcop_require.rb b/lib/tasks/rubcop_require.rb new file mode 100644 index 0000000..4ad81a6 --- /dev/null +++ b/lib/tasks/rubcop_require.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require "rubocop/rake_task" + +RuboCop::RakeTask.new do |task| + task.requires << "rubocop-rails" +end