lib/rubocop/rspec/language.rb in rubocop-rspec-2.0.0.pre vs lib/rubocop/rspec/language.rb in rubocop-rspec-2.0.0

- old
+ new

@@ -1,153 +1,187 @@ # frozen_string_literal: true module RuboCop module RSpec - # RSpec public API methods that are commonly used in cops + # Contains node matchers for common RSpec DSL. + # + # RSpec allows for configuring aliases for commonly used DSL elements, e.g. + # example groups and hooks. It is possible to configure RuboCop RSpec to + # be able to properly detect these elements in the `RSpec/Language` section + # of the RuboCop YAML configuration file. + # + # In addition to providing useful matchers, this class is responsible for + # using the configured aliases. module Language - # Set of method selectors - class SelectorSet - def initialize(selectors) - @selectors = selectors.freeze - freeze - end + extend RuboCop::NodePattern::Macros + extend NodePattern - def ==(other) - selectors.eql?(other.selectors) - end + class << self + attr_accessor :config + end - def +(other) - self.class.new(selectors + other.selectors) - end + def_node_matcher :rspec?, '{(const {nil? cbase} :RSpec) nil?}' - def include?(selector) - selectors.include?(selector) - end + def_node_matcher :example_group?, block_pattern('#ExampleGroups.all') - def block_pattern - "(block #{send_pattern} ...)" - end + def_node_matcher :shared_group?, block_pattern('#SharedGroups.all') - def block_pass_pattern - "(send #rspec? #{node_pattern_union} _ block_pass)" - end + def_node_matcher :spec_group?, + block_pattern('{#SharedGroups.all #ExampleGroups.all}') - def block_or_block_pass_pattern - "{#{block_pattern} #{block_pass_pattern}}" - end + def_node_matcher :example_group_with_body?, <<-PATTERN + (block #{send_pattern('#ExampleGroups.all')} args !nil?) + PATTERN - def send_pattern - "(send #rspec? #{node_pattern_union} ...)" - end + def_node_matcher :example?, block_pattern('#Examples.all') - def send_or_block_or_block_pass_pattern - "{#{send_pattern} #{block_pattern} #{block_pass_pattern}}" - end + def_node_matcher :hook?, block_pattern('#Hooks.all') - def node_pattern_union - "{#{node_pattern}}" - end + def_node_matcher :let?, <<-PATTERN + { + #{block_pattern('#Helpers.all')} + (send #rspec? #Helpers.all _ block_pass) + } + PATTERN - def node_pattern - selectors.map(&:inspect).join(' ') - end + def_node_matcher :include?, <<-PATTERN + { + #{send_pattern('#Includes.all')} + #{block_pattern('#Includes.all')} + } + PATTERN - def to_a - selectors - end + def_node_matcher :subject?, block_pattern('#Subjects.all') - protected + module ExampleGroups # :nodoc: + class << self + def all(element) + regular(element) || + skipped(element) || + focused(element) + end - attr_reader :selectors - end + def regular(element) + Language.config['ExampleGroups']['Regular'].include?(element.to_s) + end - module ExampleGroups - GROUPS = SelectorSet.new(%i[describe context feature example_group]) - SKIPPED = SelectorSet.new(%i[xdescribe xcontext xfeature]) - FOCUSED = SelectorSet.new(%i[fdescribe fcontext ffeature]) + def focused(element) + Language.config['ExampleGroups']['Focused'].include?(element.to_s) + end - ALL = GROUPS + SKIPPED + FOCUSED + def skipped(element) + Language.config['ExampleGroups']['Skipped'].include?(element.to_s) + end + end end - module SharedGroups - EXAMPLES = SelectorSet.new(%i[shared_examples shared_examples_for]) - CONTEXT = SelectorSet.new(%i[shared_context]) + module Examples # :nodoc: + class << self + def all(element) + regular(element) || + focused(element) || + skipped(element) || + pending(element) + end - ALL = EXAMPLES + CONTEXT + def regular(element) + Language.config['Examples']['Regular'].include?(element.to_s) + end + + def focused(element) + Language.config['Examples']['Focused'].include?(element.to_s) + end + + def skipped(element) + Language.config['Examples']['Skipped'].include?(element.to_s) + end + + def pending(element) + Language.config['Examples']['Pending'].include?(element.to_s) + end + end end - module Includes - EXAMPLES = SelectorSet.new( - %i[ - it_behaves_like - it_should_behave_like - include_examples - ] - ) - CONTEXT = SelectorSet.new(%i[include_context]) + module Expectations # :nodoc: + def self.all(element) + Language.config['Expectations'].include?(element.to_s) + end + end - ALL = EXAMPLES + CONTEXT + module Helpers # :nodoc: + def self.all(element) + Language.config['Helpers'].include?(element.to_s) + end end - module Examples - EXAMPLES = SelectorSet.new(%i[it specify example scenario its]) - FOCUSED = SelectorSet.new(%i[fit fspecify fexample fscenario focus]) - SKIPPED = SelectorSet.new(%i[xit xspecify xexample xscenario skip]) - PENDING = SelectorSet.new(%i[pending]) + module Hooks # :nodoc: + def self.all(element) + Language.config['Hooks'].include?(element.to_s) + end + end - ALL = EXAMPLES + FOCUSED + SKIPPED + PENDING + module HookScopes # :nodoc: + def self.all(element) + Language.config['HookScopes'].include?(element.to_s) + end end - module Hooks - ALL = SelectorSet.new( - %i[ - prepend_before - before - append_before - around - prepend_after - after - append_after - ] - ) + module Includes # :nodoc: + class << self + def all(element) + examples(element) || + context(element) + end - module Scopes - ALL = SelectorSet.new( - %i[ - each - example - context - all - suite - ] - ) + def examples(element) + Language.config['Includes']['Examples'].include?(element.to_s) + end + + def context(element) + Language.config['Includes']['Context'].include?(element.to_s) + end end end - module Helpers - ALL = SelectorSet.new(%i[let let!]) + module Runners # :nodoc: + def self.all(element) + Language.config['Runners'].include?(element.to_s) + end end - module Subject - ALL = SelectorSet.new(%i[subject subject!]) + module SharedGroups # :nodoc: + class << self + def all(element) + examples(element) || + context(element) + end + + def examples(element) + Language.config['SharedGroups']['Examples'].include?(element.to_s) + end + + def context(element) + Language.config['SharedGroups']['Context'].include?(element.to_s) + end + end end - module Expectations - ALL = SelectorSet.new(%i[expect is_expected expect_any_instance_of]) + module Subjects # :nodoc: + def self.all(element) + Language.config['Subjects'].include?(element.to_s) + end end - module Runners - ALL = SelectorSet.new(%i[to to_not not_to]) + # This is used in Dialect and DescribeClass cops to detect RSpec blocks. + module ALL # :nodoc: + def self.all(element) + [ExampleGroups, Examples, Expectations, Helpers, Hooks, Includes, + Runners, SharedGroups, Subjects] + .find { |concept| concept.all(element) } + end end - ALL = - ExampleGroups::ALL + - SharedGroups::ALL + - Examples::ALL + - Hooks::ALL + - Helpers::ALL + - Subject::ALL + - Expectations::ALL + - Runners::ALL + private_constant :ExampleGroups, :Examples, :Expectations, :Hooks, + :Includes, :Runners, :SharedGroups, :ALL end end end