Class: RuboCop::Cop::Hatchet::RbsSignatureExists

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/hatchet/rbs_signature_exists.rb

Overview

Ensures every hand-written β€˜.rb` file under `lib/` has a corresponding `.rbs` type signature file under `sig/`.

The mapping replaces β€˜lib/` with `sig/` and `.rb` with `.rbs`. For example:

lib/hatchet/config.rb  ->  sig/hatchet/config.rbs
lib/hatchet-sdk.rb     ->  sig/hatchet-sdk.rbs

Generated directories (clients/rest, contracts) should be excluded via the RuboCop configuration rather than hard-coded here.

Examples:

# bad – missing sig/hatchet/my_class.rbs
# lib/hatchet/my_class.rb exists without a corresponding .rbs

# good – sig/hatchet/my_class.rbs exists
# lib/hatchet/my_class.rb has a matching .rbs file

Constant Summary collapse

MSG =
"Missing RBS signature file: `%<expected_path>s`"

Instance Method Summary collapse

Instance Method Details

#on_new_investigationObject



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/rubocop/cop/hatchet/rbs_signature_exists.rb', line 26

def on_new_investigation
  # Only inspect files under lib/
  source_path = processed_source.file_path
  return unless source_path&.include?("/lib/")

  # Extract the relative path from lib/ onward
  lib_index = source_path.index("/lib/")
  return unless lib_index

  relative = source_path[(lib_index + 1)..]

  # Compute expected .rbs path
  rbs_relative = relative.sub(%r{^lib/}, "sig/").sub(/\.rb\z/, ".rbs")

  # Resolve to absolute path based on project root (parent of lib/)
  project_root = source_path[0...lib_index]
  expected_rbs = File.join(project_root, rbs_relative)

  return if File.exist?(expected_rbs)

  add_offense(
    processed_source.ast || processed_source.buffer,
    message: format(MSG, expected_path: rbs_relative),
  )
end