Module: ArchUnit::Extraction

Defined in:
lib/archunit/extraction/extract_graph.rb,
lib/archunit/extraction/locate_project.rb,
lib/archunit/extraction/resolve_import.rb,
lib/archunit/extraction/extract_imports.rb,
lib/archunit/extraction/resolved_import.rb,
lib/archunit/extraction/extract_dependencies.rb,
lib/archunit/extraction/enumerate_source_files.rb

Overview

Ruby-specific project discovery and source extraction.

Defined Under Namespace

Classes: 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_cacheObject



33
34
35
36
# File 'lib/archunit/extraction/extract_graph.rb', line 33

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) ⇒ Object



13
14
15
16
17
# File 'lib/archunit/extraction/extract_dependencies.rb', line 13

def extract_dependencies(project_root, exclude_patterns: nil)
  source_files = enumerate_source_files(project_root, exclude_patterns:)
  root = Pathname.new(path_value(project_root)).expand_path.realpath
  extract_dependencies_from(root, source_files)
end

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



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

def extract_graph(
  locator = nil, exclude_patterns: nil, options: nil, working_directory: Dir.pwd
)
  options = Common::FluentApi::CheckOptions.resolve(options)
  root = Pathname.new(locate_project(locator, working_directory:))
  patterns = resolve_exclude_patterns(exclude_patterns)
  cache_key = graph_cache_key(root, exclude_patterns: patterns, options:)

  GRAPH_CACHE_MUTEX.synchronize do
    graph_cache.delete(cache_key) if options.clear_cache?
    graph_cache[cache_key] ||= extract_graph_uncached(root, patterns)
  end
end

.extract_imports(source_file, project_root:) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
# File 'lib/archunit/extraction/extract_imports.rb', line 88

def extract_imports(source_file, project_root:)
  source_path = import_source_path(source_file)
  root = import_project_root(project_root)
  parsed_imports(source_path).map do |located_import|
    resolved_import(located_import, source_path, root)
  end.freeze
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:) ⇒ 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:)
  roots = import_search_roots(source_file, project_root, import_kind)
  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