diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f6711d2..37489fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,18 @@ concurrency: cancel-in-progress: true jobs: + rubocop: + name: Rubocop + runs-on: 'ubuntu-20.04' + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + - run: script/update_rubygems_and_install_bundler + - run: bundle install --standalone + - run: bundle exec rubocop -c .rubocop.yml + test: name: 'Ruby: ${{ matrix.ruby }}, Rails: ${{ matrix.env.RAILS_VERSION }}' runs-on: ubuntu-20.04 diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..4bda7e4 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,64 @@ +inherit_from: + - .rubocop_rspec_base.yml + +AllCops: + NewCops: enable + TargetRubyVersion: 2.0 + SuggestExtensions: false + Exclude: + - bin/**/* + - tmp/**/* + - bundle/**/* + +# TODO: Remove +Gemspec/DevelopmentDependencies: + Enabled: false + +Gemspec/DeprecatedAttributeAssignment: + Enabled: false + +Gemspec/RequiredRubyVersion: + Enabled: false + +# TODO: Remove +Gemspec/RubyVersionGlobalsUsage: + Enabled: false + +Layout/LineLength: + Max: 120 + +# Over time we'd like to get this down, but this is what we're at now. +Metrics/AbcSize: + Max: 28 + +# Over time we'd like to get this down, but this is what we're at now. +Metrics/BlockLength: + Max: 86 + Exclude: + - spec/**/* + +Metrics/ModuleLength: + Max: 140 + +# Over time we'd like to get this down, but this is what we're at now. +Metrics/PerceivedComplexity: + Max: 10 + +Naming/FileName: + Exclude: + - lib/rspec-activemodel-mocks.rb + +Style/ClassAndModuleChildren: + Exclude: + - lib/rspec/active_model/mocks/mocks.rb + +# Still support older Rubies +Style/ExpandPathArguments: + Enabled: false + +Style/NumericLiterals: + Exclude: + - templates/sample/db/* + +Style/OptionalBooleanParameter: + Enabled: false diff --git a/.rubocop_rspec_base.yml b/.rubocop_rspec_base.yml new file mode 100644 index 0000000..82140fa --- /dev/null +++ b/.rubocop_rspec_base.yml @@ -0,0 +1,316 @@ +# This file was generated on 2023-04-11T14:04:36+01:00 from the rspec-dev repo. +# DO NOT modify it by hand as your changes will get lost the next time it is generated. + +# This file contains defaults for RSpec projects. Individual projects +# can customize by inheriting this file and overriding particular settings. + +Layout/AccessModifierIndentation: + Enabled: false + +# "Use alias_method instead of alias" +# We're fine with `alias`. +Style/Alias: + Enabled: false + +# "Avoid the use of the case equality operator ===" +# We prefer using `Class#===` over `Object#is_a?` because `Class#===` +# is less likely to be monkey patched than `is_a?` on a user object. +Style/CaseEquality: + Enabled: false + +# Warns when the class is excessively long. +Metrics/ClassLength: + Max: 100 + +Style/CollectionMethods: + PreferredMethods: + reduce: 'inject' + +# Over time we'd like to get this down, but this is what we're at now. +Metrics/CyclomaticComplexity: + Max: 10 + +# We use YARD to enforce documentation. It works better than rubocop's +# enforcement...rubocop complains about the places we re-open +# `RSpec::Expectations` and `RSpec::Matchers` w/o having doc commments. +Style/Documentation: + Enabled: false + +# We still support 1.8.7 which requires trailing dots +Layout/DotPosition: + EnforcedStyle: trailing + +Style/DoubleNegation: + Enabled: false + +# each_with_object is unavailable on 1.8.7 so we have to disable this one. +Style/EachWithObject: + Enabled: false + +Style/FormatString: + EnforcedStyle: percent + +# As long as we support ruby 1.8.7 we have to use hash rockets. +Style/HashSyntax: + EnforcedStyle: hash_rockets + +# We can't use the new lambda syntax, since we still support 1.8.7. +Style/Lambda: + Enabled: false + +# Over time we'd like to get this down, but this is what we're at now. +Layout/LineLength: + Max: 100 + +# Over time we'd like to get this down, but this is what we're at now. +Metrics/MethodLength: + Max: 15 + +# Who cares what we call the argument for binary operator methods? +Naming/BinaryOperatorParameterName: + Enabled: false + +Style/PercentLiteralDelimiters: + PreferredDelimiters: + '%': () # double-quoted string + '%i': '[]' # array of symbols + '%q': () # single-quoted string + '%Q': () # double-quoted string + '%r': '{}' # regular expression pattern + '%s': () # a symbol + '%w': '[]' # array of single-quoted strings + '%W': '[]' # array of double-quoted strings + '%x': () # a shell command as a string + +# We have too many special cases where we allow generator methods or prefer a +# prefixed predicate due to it's improved readability. +Naming/PredicateName: + Enabled: false + +# On 1.8 `proc` is `lambda`, so we use `Proc.new` to ensure we get real procs on all supported versions. +# http://batsov.com/articles/2014/02/04/the-elements-of-style-in-ruby-number-12-proc-vs-proc-dot-new/ +Style/Proc: + Enabled: false + +# Exceptions should be rescued with `Support::AllExceptionsExceptOnesWeMustNotRescue` +Lint/RescueException: + Enabled: true + +# We haven't adopted the `fail` to signal exceptions vs `raise` for re-raises convention. +Style/SignalException: + Enabled: false + +# We've tended to use no space, so it's less of a change to stick with that. +Layout/SpaceAroundEqualsInParameterDefault: + EnforcedStyle: no_space + +# We don't care about single vs double qoutes. +Style/StringLiterals: + Enabled: false + +# This rule favors constant names from the English standard library which we don't load. +Style/SpecialGlobalVars: + Enabled: false + +Style/TrailingCommaInArrayLiteral: + Enabled: false + +Style/TrailingCommaInHashLiteral: + Enabled: false + +Style/TrailingCommaInArguments: + Enabled: false + +Style/TrivialAccessors: + AllowDSLWriters: true + AllowPredicates: true + ExactNameMatch: true + +Style/ParallelAssignment: + Enabled: false + +Layout/EmptyLineBetweenDefs: + Enabled: false + +Layout/FirstParameterIndentation: + Enabled: false + +Layout/ParameterAlignment: + EnforcedStyle: with_first_parameter + +Layout/SpaceInsideBlockBraces: + Enabled: false + +Layout/SpaceInsideParens: + Enabled: false + +Naming/ConstantName: + Enabled: false + +Style/ClassCheck: + Enabled: false + +Style/ConditionalAssignment: + Enabled: false + +Style/EmptyMethod: + Enabled: false + +Style/FormatStringToken: + Enabled: false + +Style/GuardClause: + Enabled: false + +Style/IdenticalConditionalBranches: + Enabled: false + +Style/IfUnlessModifier: + Enabled: false + +Style/IfUnlessModifierOfIfUnless: + Enabled: false + +Lint/MissingSuper: + Enabled: false + +Style/MissingRespondToMissing: + Enabled: false + +Style/MixinUsage: + Enabled: false + +Style/MultipleComparison: + Enabled: false + +Style/MutableConstant: + Enabled: false + +Style/NestedModifier: + Enabled: false + +Style/NestedParenthesizedCalls: + Enabled: false + +Style/NumericPredicate: + Enabled: false + +Style/RedundantParentheses: + Enabled: false + +Style/StringLiteralsInInterpolation: + Enabled: false + +Style/SymbolArray: + Enabled: false + +Style/SymbolProc: + Enabled: false + +Style/YodaCondition: + Enabled: false + +Style/ZeroLengthPredicate: + Enabled: false + +Layout/ClosingParenthesisIndentation: + Enabled: false + +Layout/ExtraSpacing: + Enabled: false + +Layout/MultilineMethodCallBraceLayout: + Enabled: false + +Layout/MultilineMethodCallIndentation: + Enabled: false + +Layout/MultilineOperationIndentation: + Enabled: false + +Layout/SpaceAroundBlockParameters: + Enabled: false + +Layout/SpaceAroundOperators: + Enabled: false + +Layout/SpaceBeforeComma: + Enabled: false + +Style/BlockDelimiters: + Enabled: false + +Style/EmptyCaseCondition: + Enabled: false + +Style/MultilineIfModifier: + Enabled: false + +Style/RescueStandardError: + Enabled: false + +Style/StderrPuts: + Enabled: false + +Style/TernaryParentheses: + Enabled: false + +Naming/HeredocDelimiterNaming: + Enabled: false + +Layout/AssignmentIndentation: + Enabled: false + +Layout/EmptyLineAfterMagicComment: + Enabled: false + +Layout/FirstArrayElementIndentation: + Enabled: false + +Layout/HeredocIndentation: + Enabled: false + +Layout/SpaceInsidePercentLiteralDelimiters: + Enabled: false + +Style/EmptyElse: + Enabled: false + +Style/IfInsideElse: + Enabled: false + +Style/RedundantReturn: + Enabled: false + +Style/StructInheritance: + Enabled: false + +Naming/VariableNumber: + Enabled: false + +Layout/SpaceInsideStringInterpolation: + Enabled: false + +Style/DateTime: + Enabled: false + +Style/ParenthesesAroundCondition: + Enabled: false + +Layout/EmptyLinesAroundBlockBody: + Enabled: false + +Lint/ImplicitStringConcatenation: + Enabled: false + +Lint/NestedMethodDefinition: + Enabled: false + +Style/RegexpLiteral: + Enabled: false + +Style/TrailingUnderscoreVariable: + Enabled: false + +Layout/EmptyLinesAroundAccessModifier: + Enabled: false diff --git a/Gemfile b/Gemfile index bff91fd..cc6a470 100644 --- a/Gemfile +++ b/Gemfile @@ -12,12 +12,13 @@ gemspec end end +gem 'rubocop' ### deps for rdoc.info group :documentation do - gem 'yard', '~> 0.9', :require => false - gem 'redcarpet', '2.3.0' gem 'github-markup', '1.0.0' + gem 'redcarpet', '2.3.0' + gem 'yard', '~> 0.9', :require => false end version = ENV.fetch('RAILS_VERSION', '6.0.0') @@ -32,12 +33,12 @@ else end if version =~ /stable\z/ - gem "activerecord", :github => "rails/rails", :branch => version gem "activemodel", :github => "rails/rails", :branch => version + gem "activerecord", :github => "rails/rails", :branch => version gem "activesupport", :github => "rails/rails", :branch => version else - gem "activerecord", version gem "activemodel", version + gem "activerecord", version gem "activesupport", version end diff --git a/lib/rspec/active_model/mocks/mocks.rb b/lib/rspec/active_model/mocks/mocks.rb index e99890b..6c42f53 100644 --- a/lib/rspec/active_model/mocks/mocks.rb +++ b/lib/rspec/active_model/mocks/mocks.rb @@ -74,6 +74,8 @@ def association(association_name) end end + # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity + # Creates a test double representing `string_or_model_class` with common # ActiveModel methods stubbed out. Additional methods may be easily # stubbed (via add_stubs) if `stubs` is passed. This is most useful for @@ -194,6 +196,7 @@ def self.param_delimiter; "-"; end yield m if block_given? end end + # rubocop:enable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity module ActiveModelStubExtensions # Stubs `persisted` to return false and `id` to return nil @@ -229,6 +232,8 @@ def connection end end + # rubocop:disable Metrics/AbcSize,Metrics/MethodLength + # Creates an instance of `Model` with `to_param` stubbed using a # generated value that is unique to each object. If `Model` is an # `ActiveRecord` model, it is prohibited from accessing the database. @@ -285,14 +290,17 @@ def stub_model(model_class, stubs={}) yield m if block_given? end end + # rubocop:enable Metrics/AbcSize,Metrics/MethodLength private + # rubocop:disable Style/ClassVars @@model_id = 1000 def next_id @@model_id += 1 end + # rubocop:enable Style/ClassVars end end diff --git a/spec/rspec/active_model/mocks/mock_model_spec.rb b/spec/rspec/active_model/mocks/mock_model_spec.rb index 2177956..1603f6b 100644 --- a/spec/rspec/active_model/mocks/mock_model_spec.rb +++ b/spec/rspec/active_model/mocks/mock_model_spec.rb @@ -470,6 +470,7 @@ def self.===(_other) end describe "ActiveModel Lint tests" do + # rubocop:disable Lint/EmptyExpression,Metrics/BlockNesting begin require 'minitest/assertions' include Minitest::Assertions @@ -525,6 +526,7 @@ def self.===(_other) end end end + # rubocop:enable Lint/EmptyExpression,Metrics/BlockNesting require 'active_model/lint' include ActiveModel::Lint::Tests