Module: OllamaAgent::Topology::ZeitwerkInflector

Defined in:
lib/ollama_agent/topology/zeitwerk_inflector.rb

Overview

Path ↔ constant guessing aligned with common Zeitwerk / Rails autoload layout.

Constant Summary collapse

DEFAULT_ROOTS =
%w[app/models app/controllers lib].freeze

Class Method Summary collapse

Class Method Details

.camelize(snake_path:, acronyms: {}) ⇒ Object



11
12
13
# File 'lib/ollama_agent/topology/zeitwerk_inflector.rb', line 11

def camelize(snake_path:, acronyms: {})
  snake_path.to_s.split("/").map { |segment| camelize_segment(segment, acronyms) }.join("::")
end

.camelize_piece(piece, acronyms) ⇒ Object



52
53
54
55
56
57
# File 'lib/ollama_agent/topology/zeitwerk_inflector.rb', line 52

def camelize_piece(piece, acronyms)
  key = piece.downcase
  return acronyms[key] if acronyms[key]

  piece.capitalize
end

.camelize_segment(segment, acronyms) ⇒ Object



45
46
47
48
49
50
# File 'lib/ollama_agent/topology/zeitwerk_inflector.rb', line 45

def camelize_segment(segment, acronyms)
  return "" if segment.empty?

  pieces = segment.split("_")
  pieces.map { |piece| camelize_piece(piece, acronyms) }.join
end

.constant_to_file_pattern(fqcn:, root_paths: DEFAULT_ROOTS) ⇒ Object



25
26
27
28
29
30
31
32
# File 'lib/ollama_agent/topology/zeitwerk_inflector.rb', line 25

def constant_to_file_pattern(fqcn:, root_paths: DEFAULT_ROOTS)
  parts = fqcn.to_s.split("::")
  snake_segments = parts.map { |part| underscore(part) }
  root_paths.map do |root|
    joined = File.join(File.expand_path(root.to_s), *snake_segments)
    "#{joined}.rb"
  end
end

.fallback_constant(abs_path, acronyms) ⇒ Object



40
41
42
43
# File 'lib/ollama_agent/topology/zeitwerk_inflector.rb', line 40

def fallback_constant(abs_path, acronyms)
  base = File.basename(abs_path, ".rb")
  camelize(snake_path: base, acronyms: acronyms)
end

.file_to_constant(file_path:, root_paths: DEFAULT_ROOTS, acronyms: {}) ⇒ Object



15
16
17
18
19
20
21
22
23
# File 'lib/ollama_agent/topology/zeitwerk_inflector.rb', line 15

def file_to_constant(file_path:, root_paths: DEFAULT_ROOTS, acronyms: {})
  abs = File.expand_path(file_path.to_s)
  root = matching_root(abs, root_paths.map { |r| File.expand_path(r.to_s) })
  return fallback_constant(abs, acronyms) unless root

  rel = abs.delete_prefix("#{root}#{File::SEPARATOR}")
  rel = rel.sub(/\.rb\z/, "")
  camelize(snake_path: rel.tr(File::SEPARATOR, "/"), acronyms: acronyms)
end

.matching_root(abs_path, expanded_roots) ⇒ Object



34
35
36
37
38
# File 'lib/ollama_agent/topology/zeitwerk_inflector.rb', line 34

def matching_root(abs_path, expanded_roots)
  expanded_roots
    .select { |r| abs_path.start_with?("#{r}#{File::SEPARATOR}") || abs_path == r }
    .max_by(&:length)
end

.underscore(const_part) ⇒ Object



59
60
61
62
63
64
65
66
67
68
# File 'lib/ollama_agent/topology/zeitwerk_inflector.rb', line 59

def underscore(const_part)
  return "" if const_part.to_s.empty?

  const_part
    .gsub("::", "/")
    .gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
    .gsub(/([a-z\d])([A-Z])/, '\1_\2')
    .tr("-", "_")
    .downcase
end