Class: Lexy::SpecFinder

Inherits:
Object
  • Object
show all
Defined in:
lib/lexy/spec_finder.rb

Instance Method Summary collapse

Instance Method Details

#build_dirs_stack(path) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/lexy/spec_finder.rb', line 15

def build_dirs_stack(path)
  current_path = path.split('/')
  dirs_stack = []
  dir_found = false

  until dir_found
    if specs_dir?(File.join(*current_path))
      dir_found = true
    else
      dirs_stack << current_path[-1]

      current_path = current_path[0...-1]

      raise 'No specs folder in given tree' if current_path.length.zero?
    end
  end

  dirs_stack + ['spec']
end

#build_spec_path(path, dirs_stack) ⇒ Object



39
40
41
42
43
44
45
# File 'lib/lexy/spec_finder.rb', line 39

def build_spec_path(path, dirs_stack)
  base_path = path.split('/') - dirs_stack
  spec_name = dirs_stack[0].split('.')[0] + '_spec.rb'
  spec_path = dirs_stack[1..-1].reverse

  base_path + spec_path + [spec_name]
end

#call(path) ⇒ Object



7
8
9
10
11
12
13
# File 'lib/lexy/spec_finder.rb', line 7

def call(path)
  stack = build_dirs_stack(path)
  spec_path = build_spec_path(path, stack)
  const = extract_constant_name(path)
  ensure_folder_created(spec_path)
  create_spec_file(spec_path, const)
end

#create_spec_file(path, const) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/lexy/spec_finder.rb', line 83

def create_spec_file(path, const)
  path = File.join(path)

  return path if File.exist?(path)

  template = <<~SPEC
    # frozen_string_literal: true

    RSpec.describe #{const.join('::')} do
      subject { described_class.new }
    end
  SPEC

  File.open(path, 'a+') { |file| file.write(template) }
  path
end

#ensure_folder_created(path) ⇒ Object



79
80
81
# File 'lib/lexy/spec_finder.rb', line 79

def ensure_folder_created(path)
  FileUtils.mkdir_p(File.join(path[0...-1]))
end

#extract_constant_name(path) ⇒ Object



47
48
49
50
51
52
53
54
55
56
# File 'lib/lexy/spec_finder.rb', line 47

def extract_constant_name(path)
  file_contents = File.read(path)

  ast = Parser::CurrentRuby.parse(file_contents)

  const = process_scope(ast)
  raise 'No constants definitions' if const.nil?

  const
end

#node_name(ast) ⇒ Object



100
101
102
# File 'lib/lexy/spec_finder.rb', line 100

def node_name(ast)
  ast.to_a.first.to_a[1]
end

#process_scope(ast, const = []) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/lexy/spec_finder.rb', line 58

def process_scope(ast, const = [])
  return unless ast.is_a?(Parser::AST::Node)

  names = []
  local_const = const.dup

  if %i[module class].include?(ast.type)
    name = node_name(ast)

    local_const << name
    names << local_const
  end

  nodes_names = ast.to_a.flat_map { |node| process_scope(node, local_const) }.reject(&:nil?)
  names.push(*nodes_names)

  return if names.empty?

  names
end

#specs_dir?(dir) ⇒ Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/lexy/spec_finder.rb', line 35

def specs_dir?(dir)
  Dir.glob('spec', base: dir).any?
end