module RuboCop::Cop::FactoryBotUsage
Helpers for detecting FactoryBot usage. rubocop:disable Metrics/ModuleLength
Constants
- FACTORY_BOT_METHODS
- Factory
Public Class Methods
factories_cache()
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 37 def self.factories_cache @@factories end
factories_cache=(factories)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 41 def self.factories_cache=(factories) @@factories = factories end
Public Instance Methods
engines_path()
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 73 def engines_path raise NotImplementedError end
factory_files()
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 69 def factory_files @factory_files ||= Dir['spec/factories/**/*.rb'] + Dir["#{engines_path}*/spec/factories/**/*.rb"] end
find_factories()
click to toggle source
Parses factory definition files, returning a hash mapping factory names to model class names for each file.
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 52 def find_factories RuboCop::Cop::FactoryBotUsage.factories_cache ||= begin # We'll add factories here as we parse the factory files. @factories = {} # We'll add factories that specify a parent here, so we can resolve the # reference to the parent after we have finished parsing all the files. @parents = {} # Parse the factory files, then resolve any parent references. traverse_factory_files resolve_parents @factories end end
spec_file?()
click to toggle source
rubocop:enable Style/ClassVars
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 46 def spec_file? processed_source&.path&.match?(/_spec\.rb$/) || false end
Private Instance Methods
determine_model_class_name(factory, model_class_name_from_surrounding_block)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 200 def determine_model_class_name(factory, model_class_name_from_surrounding_block) factory.model_class_name || model_class_name_from_surrounding_block || ActiveSupport::Inflector.camelize(factory.name) end
determine_parent(factory, parent_from_surrounding_block)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 192 def determine_parent(factory, parent_from_surrounding_block) # If the factory specifies an explicit model class name, we don't need # to resolve the parent to determine the model class name. return nil if factory.model_class_name factory.parent || parent_from_surrounding_block end
extract_aliases(factory_config_hash_node)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 157 def extract_aliases(factory_config_hash_node) aliases_array = extract_hash_value(factory_config_hash_node, :aliases) return [] if aliases_array&.type != :array aliases_array.children.map(&:value) end
extract_factory_node(node)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 121 def extract_factory_node(node) return node.children[0] if factory_block?(node) return node if factory_node?(node) end
extract_hash_value(node, hash_key)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 180 def extract_hash_value(node, hash_key) return nil if node&.type != :hash pairs = node.children.select { |child| child.type == :pair } pairs.each do |pair| key, value = pair.children return value if key.value == hash_key end nil end
extract_model_class_name(factory_config_hash_node)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 169 def extract_model_class_name(factory_config_hash_node) model_class_name_node = extract_hash_value(factory_config_hash_node, :class) case model_class_name_node&.type when :const model_class_name_node.source.sub(/^::/, '') when :str model_class_name_node.value.sub(/^::/, '') end end
extract_parent(factory_config_hash_node)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 164 def extract_parent(factory_config_hash_node) parent_node = extract_hash_value(factory_config_hash_node, :parent) parent_node&.value end
factory_block?(node)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 136 def factory_block?(node) return false if node&.type != :block factory_node?(node.children[0]) end
factory_node?(node)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 142 def factory_node?(node) node&.type == :send && node.children[1] == :factory end
parse_factory_node(node)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 146 def parse_factory_node(node) factory_name_node, factory_config_node = node.children[2..3] name = factory_name_node.children[0] aliases = extract_aliases(factory_config_node) parent = extract_parent(factory_config_node) model_class_name = extract_model_class_name(factory_config_node) Factory.new(name, aliases, parent, model_class_name) end
register_factory(path, factory_name, aliases, parent, model_class_name)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 126 def register_factory(path, factory_name, aliases, parent, model_class_name) ([factory_name] + aliases).each do |name| if parent @parents[path][name] = parent else @factories[path][name] = model_class_name end end end
resolve_parents()
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 90 def resolve_parents all_factories = @factories.values.reduce(:merge) all_parents = @parents.values.reduce(:merge) @parents.each do |path, parents| parents.each do |factory, parent| parent = all_parents[parent] while all_parents[parent] model_class_name = all_factories[parent] next unless model_class_name @factories[path][factory] = model_class_name end end end
traverse_factory_files()
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 79 def traverse_factory_files factory_files.each do |path| @factories[path] = {} @parents[path] = {} source_code = File.read(path) source = RuboCop::ProcessedSource.new(source_code, RUBY_VERSION.to_f) traverse_node(source.ast, path) end end
traverse_node(node, path, parent = nil, model_class_name = nil)
click to toggle source
# File lib/rubocop/cop/mixin/factory_bot_usage.rb, line 104 def traverse_node(node, path, parent = nil, model_class_name = nil) return unless node.is_a?(Parser::AST::Node) factory_node = extract_factory_node(node) if factory_node factory = parse_factory_node(factory_node) parent = determine_parent(factory, parent) model_class_name = determine_model_class_name(factory, model_class_name) if factory_node?(node) register_factory(path, factory.name, factory.aliases, parent, model_class_name) return end end node.children.each { |child| traverse_node(child, path, parent, model_class_name) } end