Module: ArchUnit::Extraction

Defined in:
lib/archunit/extraction/extract_graph.rb,
lib/archunit/extraction/import_visitor.rb,
lib/archunit/extraction/locate_project.rb,
lib/archunit/extraction/resolve_import.rb,
lib/archunit/extraction/extract_imports.rb,
lib/archunit/extraction/import_resolver.rb,
lib/archunit/extraction/resolved_import.rb,
lib/archunit/extraction/extraction_profile.rb,
lib/archunit/extraction/resolve_load_paths.rb,
lib/archunit/extraction/extract_dependencies.rb,
lib/archunit/extraction/enumerate_source_files.rb,
lib/archunit/extraction/validate_extraction_paths.rb,
lib/archunit/extraction/discover_gemspec_load_paths.rb

Overview

Ruby-specific project discovery and source extraction.

Defined Under Namespace

Modules: ExtractionPaths, GemspecLoadPaths, LoadPaths Classes: ExtractionProfile, ImportResolver, ResolvedImport

Constant Summary collapse

GRAPH_CACHE_MUTEX =
Mutex.new
GRAPH_INDEPENDENT_CHECK_OPTIONS =
%i[allow_empty_tests logging clear_cache].freeze
IGNORE_DIRECTIVE =
/\A#\s*archunit:\s*ignore(?:\s+(?<modules>.+?))?\s*\z/
DEFAULT_EXCLUDED_DIRECTORIES =
%w[
  .bundle
  .cache
  .git
  .hg
  .ruby-lsp
  .svn
  .yardoc
  build
  coverage
  dist
  log
  node_modules
  pkg
  tmp
  vendor
].freeze

Class Method Summary collapse

Class Method Details

.clear_graph_cache ⇒ Object



38
39
40
41
# File 'lib/archunit/extraction/extract_graph.rb', line 38

def clear_graph_cache
  GRAPH_CACHE_MUTEX.synchronize { graph_cache.clear }
  nil
end

.enumerate_source_files(project_root, exclude_patterns: nil) ⇒ Object



31
32
33
34
35
36
37
38
39
# File 'lib/archunit/extraction/enumerate_source_files.rb', line 31

def enumerate_source_files(project_root, exclude_patterns: nil)
  root = source_root(project_root)
  patterns = resolve_exclude_patterns(exclude_patterns)
  source_files_under(root, patterns).sort.freeze
rescue UserError, TechnicalError
  raise
rescue SystemCallError => e
  raise TechnicalError, "could not enumerate Ruby source files: #{e.message}"
end

.extract_dependencies(project_root, exclude_patterns: nil, options: nil) ⇒ Object



18
19
20
21
22
23
24
25
26
# File 'lib/archunit/extraction/extract_dependencies.rb', line 18

def extract_dependencies(project_root, exclude_patterns: nil, options: nil)
  options = Common::FluentApi::CheckOptions.resolve(options)
  source_files = enumerate_source_files(project_root, exclude_patterns:)
  root = Pathname.new(path_value(project_root)).expand_path.realpath
  load_paths = LoadPaths.resolve(
    root, explicit_paths: options.load_paths, source_files:
  )
  extract_dependencies_from(root, source_files, load_paths:)
end

.extract_graph(locator = nil, exclude_patterns: nil, options: nil, working_directory: Dir.pwd, profile: nil) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/archunit/extraction/extract_graph.rb', line 21

def extract_graph(
  locator = nil, exclude_patterns: nil, options: nil, working_directory: Dir.pwd,
  profile: nil
)
  ExtractionProfile.validate(profile)
  options = Common::FluentApi::CheckOptions.resolve(options)
  ExtractionProfile.measure(profile, :total) do
    root = ExtractionProfile.measure(profile, :project_discovery) do
      Pathname.new(locate_project(locator, working_directory:))
    end
    patterns = resolve_exclude_patterns(exclude_patterns)
    cache_key = graph_cache_key(root, exclude_patterns: patterns, options:)

    fetch_graph(root, patterns, options, cache_key, profile)
  end
end

.extract_imports(source_file, project_root:, load_paths: nil, profile: nil, resolution_cache: nil) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/archunit/extraction/extract_imports.rb', line 19

def extract_imports(
  source_file, project_root:, load_paths: nil, profile: nil, resolution_cache: nil
)
  source_path = ExtractionPaths.source_file(source_file)
  root = ExtractionPaths.project_root(project_root)
  extract_imports_from(
    source_path, project_root: root, load_paths:, profile:, resolution_cache:
  )
rescue UserError
  raise
rescue SystemCallError => e
  raise TechnicalError, "could not parse Ruby source file: #{e.message}"
end

.locate_project(locator = nil, working_directory: Dir.pwd) ⇒ Object



12
13
14
15
16
17
18
19
20
# File 'lib/archunit/extraction/locate_project.rb', line 12

def locate_project(locator = nil, working_directory: Dir.pwd)
  working_root = existing_directory(working_directory, :working_directory)
  root = project_root(locator, working_root)
  normalize_path(root.realpath)
rescue UserError, TechnicalError
  raise
rescue SystemCallError => e
  raise TechnicalError, "could not locate project: #{e.message}"
end

.resolve_import(module_name, source_file:, project_root:, import_kind:, load_paths: nil) ⇒ Object



11
12
13
14
15
16
17
18
19
20
# File 'lib/archunit/extraction/resolve_import.rb', line 11

def resolve_import(module_name, source_file:, project_root:, import_kind:, load_paths: nil)
  roots = import_search_roots(source_file, project_root, import_kind, load_paths)
  resolved = if import_kind == Common::Extraction::ImportKind::LOAD
               resolve_load(module_name, roots, import_kind)
             else
               resolve_feature(module_name, roots, import_kind)
             end

  resolved&.tr('\\', '/')&.freeze
end