Class: RuboCop::Cop::FactoryBot::CreateList

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Includes:
ConfigurableEnforcedStyle, ConfigurableExplicitOnly, FactoryBot::Language
Defined in:
lib/rubocop/cop/factory_bot/create_list.rb

Overview

Checks for create_list usage.

This cop can be configured using the ‘EnforcedStyle` option

Examples:

‘EnforcedStyle: create_list` (default)

# bad
3.times { create :user }
3.times.map { create :user }
[create(:user), create(:user), create(:user)]
Array.new(3) { create :user }

# good
create_list :user, 3

# bad
3.times { create :user, age: 18 }

# good - index is used to alter the created models attributes
3.times { |n| create :user, age: n }

# good - contains a method call, may return different values
3.times { create :user, age: rand }

‘EnforcedStyle: n_times`

# bad
create_list :user, 3
[create(:user), create(:user), create(:user)]

# good
3.times.map { create :user }

‘ExplicitOnly: false` (default)


# bad - with `EnforcedStyle: create_list`
3.times { FactoryBot.create :user }
3.times { create :user }

# good - with `EnforcedStyle: create_list`
FactoryBot.create_list :user, 3
create_list :user, 3

‘ExplicitOnly: true`


# bad - with `EnforcedStyle: create_list`
3.times { FactoryBot.create :user }

# good - with `EnforcedStyle: create_list`
FactoryBot.create_list :user, 3
create_list :user, 3
3.times { create :user }

Defined Under Namespace

Modules: Corrector Classes: CreateListCorrector, TimesCorrector

Constant Summary collapse

MSG_CREATE_LIST =
'Prefer create_list.'
MSG_N_TIMES =
'Prefer %<number>s.times.map.'
RESTRICT_ON_SEND =
%i[create_list].freeze

Constants included from FactoryBot::Language

FactoryBot::Language::METHODS

Instance Method Summary collapse

Methods included from ConfigurableExplicitOnly

#explicit_only?, #factory_call?

Methods included from FactoryBot::Language

#factory_bot?

Instance Method Details

#arguments_include_method_call?(node) ⇒ Object



92
93
94
# File 'lib/rubocop/cop/factory_bot/create_list.rb', line 92

def_node_matcher :arguments_include_method_call?, <<~PATTERN
  (send #factory_call? :create sym ... `(send ...))
PATTERN

#block_with_arg_and_used?(node) ⇒ Object



83
84
85
86
87
88
89
# File 'lib/rubocop/cop/factory_bot/create_list.rb', line 83

def_node_matcher :block_with_arg_and_used?, <<~PATTERN
  (block
    _
    (args (arg _value))
    `_value
  )
PATTERN

#factory_call(node) ⇒ Object



97
98
99
# File 'lib/rubocop/cop/factory_bot/create_list.rb', line 97

def_node_matcher :factory_call, <<~PATTERN
  (send #factory_call? :create sym ...)
PATTERN

#factory_calls_in_array?(node) ⇒ Object



107
108
109
# File 'lib/rubocop/cop/factory_bot/create_list.rb', line 107

def_node_search :factory_calls_in_array?, <<~PATTERN
  (array #factory_call+)
PATTERN

#factory_list_call(node) ⇒ Object



102
103
104
# File 'lib/rubocop/cop/factory_bot/create_list.rb', line 102

def_node_matcher :factory_list_call, <<~PATTERN
  (send #factory_call? :create_list (sym _) (int $_) ...)
PATTERN

#on_array(node) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
# File 'lib/rubocop/cop/factory_bot/create_list.rb', line 111

def on_array(node)
  return unless same_factory_calls_in_array?(node)
  return if node.values.size < 2

  add_offense(
    node,
    message: preferred_message_for_array(node)
  ) do |corrector|
    autocorrect_same_factory_calls_in_array(corrector, node)
  end
end

#on_block(node) ⇒ Object

rubocop:disable InternalAffairs/NumblockHandler, Metrics/CyclomaticComplexity



123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/rubocop/cop/factory_bot/create_list.rb', line 123

def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, Metrics/CyclomaticComplexity
  return unless style == :create_list
  return unless repeat_multiple_time?(node)
  return if block_with_arg_and_used?(node)
  return unless node.body
  return if arguments_include_method_call?(node.body)
  return unless contains_only_factory?(node.body)

  add_offense(node.send_node, message: MSG_CREATE_LIST) do |corrector|
    CreateListCorrector.new(node.send_node).call(corrector)
  end
end

#on_send(node) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/rubocop/cop/factory_bot/create_list.rb', line 136

def on_send(node)
  return unless style == :n_times

  factory_list_call(node) do |count|
    next if count < 2

    message = format(MSG_N_TIMES, number: count)
    add_offense(node.loc.selector, message: message) do |corrector|
      TimesCorrector.new(node).call(corrector)
    end
  end
end

#repeat_count(node) ⇒ Object



72
73
74
75
76
77
78
79
80
# File 'lib/rubocop/cop/factory_bot/create_list.rb', line 72

def_node_matcher :repeat_count, <<~PATTERN
  (block
    {
      (send (const {nil? cbase} :Array) :new (int $_))  # Array.new(3) { create(:user) }
      (send (int $_) :times)                            # 3.times { create(:user) }
      (send (send (int $_) :times) :map)                # 3.times.map { create(:user) }
    }
  ...)
PATTERN