Class: RspecSprint::Fixers::LetItBe::Detector

Inherits:
Object
  • Object
show all
Defined in:
lib/rspec_sprint/fixers/let_it_be/detector.rb

Overview

spec ソースを AST で走査し、本体が「単一の create(:factory) 呼び出し」だけの‘let(:x) { … }` を候補として返す純粋関数。挙動を変える変換なので、安全性は後段(verify/revert, 本プラン対象外)に委ね、ここでは確定パターンだけ拾う。

Constant Summary collapse

PATTERN =

block:

レシーバ無し let に sym 引数 1 つ($ で let 名を捕捉)
引数なしブロック (args)
本体は レシーバが無 or FactoryBot の create、第1引数は sym($ で factory 名を捕捉)
::RuboCop::AST::NodePattern.new(<<~PAT)
  (block
    (send nil? :let (sym $_))
    (args)
    (send {nil? (const nil? :FactoryBot)} :create (sym $_) ...))
PAT
LET_BANG_PATTERN =

同形だが ‘let!`。eager → once でセマンティクスが変わるため安全変換の対象外。「対象外だが隣接する let{create} がどれだけあるか」を提示するために数えるだけ。

::RuboCop::AST::NodePattern.new(<<~PAT)
  (block
    (send nil? :let! (sym $_))
    (args)
    (send {nil? (const nil? :FactoryBot)} :create (sym $_) ...))
PAT

Class Method Summary collapse

Class Method Details

.count_let_bang_create(source) ⇒ Object

安全変換できない let{single create} の件数(lazy/let! 比を示すため)。



66
67
68
# File 'lib/rspec_sprint/fixers/let_it_be/detector.rb', line 66

def self.count_let_bang_create(source)
  each_match(source, LET_BANG_PATTERN).size
end

.scan(source, file_path: nil) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/rspec_sprint/fixers/let_it_be/detector.rb', line 40

def self.scan(source, file_path: nil)
  each_match(source, PATTERN).map do |let_name, factory_name, node|
    Candidate.new(
      let_name: let_name,
      factory_name: factory_name,
      line: node.loc.line,
      file_path: file_path,
      kind: :let
    )
  end
end

.scan_all(source, file_path: nil) ⇒ Object

let と let! の両方を候補として返す(apply モード用)。line 昇順。



53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rspec_sprint/fixers/let_it_be/detector.rb', line 53

def self.scan_all(source, file_path: nil)
  let_cands = each_match(source, PATTERN).map do |let_name, factory_name, node|
    Candidate.new(let_name: let_name, factory_name: factory_name,
                  line: node.loc.line, file_path: file_path, kind: :let)
  end
  let_bang_cands = each_match(source, LET_BANG_PATTERN).map do |let_name, factory_name, node|
    Candidate.new(let_name: let_name, factory_name: factory_name,
                  line: node.loc.line, file_path: file_path, kind: :let_bang)
  end
  (let_cands + let_bang_cands).sort_by(&:line)
end