class Lexy::SpecFinder

Public Instance Methods

build_dirs_stack(path) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# File lib/lexy/spec_finder.rb, line 100
def node_name(ast)
  ast.to_a.first.to_a[1]
end
process_scope(ast, const = []) click to toggle source
# 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) click to toggle source
# File lib/lexy/spec_finder.rb, line 35
def specs_dir?(dir)
  Dir.glob('spec', base: dir).any?
end