Skip to content

Commit

Permalink
Introduce Default Settings and Configurations for RuboCop-Sequel (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
numbata authored May 14, 2024
1 parent 2b27022 commit bcc0def
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 1 deletion.
46 changes: 46 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This is the default configuration file.

Sequel:
Enabled: true
DocumentationBaseURL: https://github.com/rubocop/rubocop-sequel/blob/master/README.md

Sequel/ConcurrentIndex:
Description: Encourages the creation of indexes with the `NOT VALID` option to avoid locking tables.
Reference: https://www.rubydoc.info/gems/rubocop-sequel/RuboCop/Cop/Sequel/ConcurrentIndex
Enabled: true
VersionAdded: 0.0.1
VersionChanged: 0.3.3

Sequel/JSONColumn:
Description: >-
Advocates the use of the `jsonb` column type over `json` or `hstore` for performance
benefits and additional functionality.
Reference: https://www.rubydoc.info/gems/rubocop-sequel/RuboCop/Cop/Sequel/JSONColumn
Enabled: true
Safe: false
VersionAdded: 0.0.1
VersionChanged: 0.3.3

Sequel/MigrationName:
Description: >-
Helps to name migration files descriptively in order to avoid the use of default or generic names.
Reference: https://www.rubydoc.info/gems/rubocop-sequel/RuboCop/Cop/Sequel/MigrationName
Enabled: true
VersionAdded: '0.0.1'
VersionChanged: '0.3.3'
DefaultName: new_migration

Sequel/PartialConstraint:
Description: Advises on the correct use of partial indexes by specifying the `where' argument.
Reference: https://www.rubydoc.info/gems/rubocop-sequel/RuboCop/Cop/Sequel/PartialConstraint
Enabled: true
VersionAdded: '0.3.0'
VersionChanged: '0.3.3'

Sequel/SaveChanges:
Description: Ensures the use of save_changes instead of save to persist changes to models.
Reference: https://www.rubydoc.info/gems/rubocop-sequel/RuboCop/Cop/Sequel/SaveChanges
Enabled: true
SafeAutoCorrect: false
VersionAdded: '0.0.1'
VersionChanged: '0.3.3'
14 changes: 14 additions & 0 deletions config/obsoletion.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#
# Configuration for obsoletion.
#
# See: https://docs.rubocop.org/rubocop/extensions.html#config-obsoletions
#
extracted:
Sequel/*: ~

removed:
Sequel/ColumnDefault:
reason: >-
ColumnDefault cop since it's mostly outdated advice.
Details [#33](https://github.com/rubocop/rubocop-sequel/issues/32)
6 changes: 5 additions & 1 deletion lib/rubocop-sequel.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# frozen_string_literal: true

require 'rubocop'

require 'rubocop/sequel'
require 'rubocop/sequel/version'
require 'rubocop/sequel/inject'

RuboCop::Sequel::Inject.defaults!

require 'rubocop/cop/sequel/concurrent_index'
require 'rubocop/cop/sequel/json_column'
require 'rubocop/cop/sequel/migration_name'
Expand Down
9 changes: 9 additions & 0 deletions lib/rubocop/sequel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,14 @@
module RuboCop
# RuboCop Sequel project namespace
module Sequel
PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze

private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)

if ::RuboCop.const_defined?(:ConfigObsoletion)
::RuboCop::ConfigObsoletion.files << PROJECT_ROOT.join('config', 'obsoletion.yml')
end
end
end
18 changes: 18 additions & 0 deletions lib/rubocop/sequel/inject.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

module RuboCop
module Sequel
# Because RuboCop doesn't yet support plugins, we have to monkey patch in a
# bit of our configuration.
module Inject
def self.defaults!
path = CONFIG_DEFAULT.to_s
hash = ConfigLoader.send(:load_yaml_configuration, path)
config = Config.new(hash, path).tap(&:make_excludes_absolute)
puts "configuration from #{path}" if ConfigLoader.debug?
config = ConfigLoader.merge_with_default(config, path, unset_nil: false)
ConfigLoader.instance_variable_set(:@default_configuration, config)
end
end
end
end
111 changes: 111 additions & 0 deletions spec/project_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'config/default.yml', type: :feature do
subject(:config) { RuboCop::ConfigLoader.load_file('config/default.yml') }

let(:configuration_keys) { config.tap { |c| c.delete('inherit_mode') }.keys }
let(:version_regexp) { /\A\d+\.\d+(?:\.\d+)?\z|\A<<next>>\z/ }

shared_examples 'has a nicely formatted description' do |cop_name|
it 'does not contain new lines' do
description = config.dig(cop_name, 'Description')

expect(description.include?("\n")).to be(false)
end

it 'stars from a verb' do # rubocop:disable RSpec/ExampleLength
description = config.dig(cop_name, 'Description')
start_with_subject = description.match(/\AThis cop (?<verb>.+?) .*/)
suggestion = start_with_subject[:verb]&.capitalize if start_with_subject
suggestion ||= 'a verb'

expect(start_with_subject).to(
be_nil, "should be started with `#{suggestion}` instead of `This cop ...`."
)
end

it 'has a period at EOL of description' do
description = config.dig(cop_name, 'Description')

expect(description).to match(/\.\z/)
end
end

shared_examples 'has metadata' do |cop_name|
context 'with VersionAdded' do
it 'required' do
version = config.dig(cop_name, 'VersionAdded')
expect(version).not_to be_nil
end

it 'nicely formatted' do
version = config.dig(cop_name, 'VersionAdded')
expect(version).to match(version_regexp), "should be format ('X.Y' or 'X.Y.Z' or '<<next>>')"
end
end

context 'with VersionChanged' do
it 'nicely formatted' do
version = config.dig(cop_name, 'VersionChanged')
next unless version

expect(version).to match(version_regexp), "should be format ('X.Y' or 'X.Y.Z' or '<<next>>')"
end
end

context 'with VersionRemoved' do
it 'nicely formatted' do
version = config.dig(cop_name, 'VersionRemoved')
next unless version

expect(version).to match(version_regexp), "should be format ('X.Y' or 'X.Y.Z' or '<<next>>')"
end
end

context 'with Safe' do
it 'does not include `true`' do
safe = config.dig(cop_name, 'Safe')
expect(safe).not_to be(true), 'has unnecessary `Safe: true` config.'
end
end

context 'with SafeAutoCorrect' do
it 'does not include unnecessary `false`' do
next unless config.dig(cop_name, 'Safe') == false

safe_autocorrect = config.dig(cop_name, 'SafeAutoCorrect')

expect(safe_autocorrect).not_to be(false), 'has unnecessary `SafeAutoCorrect: false` config.'
end
end
end

cop_names = RuboCop::Cop::Registry.global.with_department(:Sequel).cops.map(&:cop_name)
cop_names.each do |cop_name|
describe "Cop #{cop_name}" do
include_examples 'has a nicely formatted description', cop_name
include_examples 'has metadata', cop_name
end
end

it 'sorts configuration keys alphabetically' do
expected = configuration_keys.sort
configuration_keys.each_with_index do |key, idx|
expect(key).to eq expected[idx]
end
end

it 'sorts cop names alphabetically' do # rubocop:disable RSpec/ExampleLength
previous_key = ''
config_default = YAML.load_file('config/default.yml')

config_default.each_key do |key|
next if %w[inherit_mode AllCops].include?(key)

expect(previous_key <= key).to be(true), "Cops should be sorted alphabetically. Please sort #{key}."
previous_key = key
end
end
end

0 comments on commit bcc0def

Please sign in to comment.