Skip to content

Commit

Permalink
FEATURE: Add a cop that checks for potential fabricator shorthand use (
Browse files Browse the repository at this point in the history
…#40)

In discourse/discourse#24314, @danielwaterworth introduced the ability to use #fab! with a shorthand when simply fabricating a vanilla record with the same name as the assigned let. This PR introduces a cop that highlights places where this shorthand can be used.
  • Loading branch information
Drenmi authored Feb 20, 2024
1 parent 30b2930 commit da85422
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
52 changes: 52 additions & 0 deletions lib/rubocop/cop/discourse/fabricator_shorthand.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Discourse
# When fabricating a record without custom attributes, we can use the
# fabricator shorthand as long as the identifier matches the fabricator
# name.
#
# @example
#
# # bad
# fab!(:user) { Fabricate(:user) }
#
# # good
# fab!(:user)
#
# When using custom attributes or the identifier doesn't match, the
# shorthand can't be used.
#
# @example
#
# # good
# fab!(:user) { Fabricate(:user, trust_level: TrustLevel[0]) }
#
# # good
# fab!(:another_user) { Fabricate(:user) }
class FabricatorShorthand < Base
def_node_matcher :offending_fabricator?, <<-MATCHER
(block
(send nil? :fab!
(sym $_identifier))
(args)
(send nil? :Fabricate
(sym $_identifier)))
MATCHER

def on_block(node)
offending_fabricator?(node) do |identifier|
add_offense(node, message: message(identifier))
end
end

private

def message(identifier)
"Use the fabricator shorthand: `fab!(:#{identifier})`"
end
end
end
end
end
34 changes: 34 additions & 0 deletions spec/lib/rubocop/cop/fabricator_shorthand_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

require "spec_helper"

describe RuboCop::Cop::Discourse::FabricatorShorthand, :config do
subject(:cop) { described_class.new(config) }

let(:config) { RuboCop::Config.new }

it "registers an offense when not using the fabricator shorthand" do
expect_offense(<<~RUBY)
RSpec.describe "Foo" do
fab!(:foo) { Fabricate(:foo) }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Discourse/FabricatorShorthand: Use the fabricator shorthand: `fab!(:foo)`
end
RUBY
end

it "does not register an offense when the fabricator has attributes" do
expect_no_offenses(<<~RUBY)
RSpec.describe "Foo" do
fab!(:foo) { Fabricate(:foo, bar: 1) }
end
RUBY
end

it "does not register an offense when the identifier doesn't match" do
expect_no_offenses(<<~RUBY)
RSpec.describe "Foo" do
fab!(:bar) { Fabricate(:foo) }
end
RUBY
end
end
5 changes: 5 additions & 0 deletions stree-compat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ AllCops:

Discourse:
Enabled: true

Discourse/FabricatorShorthand:
Enabled: true
Include:
- 'spec/**/*_spec.rb'

0 comments on commit da85422

Please sign in to comment.