Module: OllamaChat::Utils::AnalyzeDirectory

Included in:
Parsing
Defined in:
lib/ollama_chat/utils/analyze_directory.rb

Overview

The OllamaChat::Utils::AnalyzeDirectory module provides a small, dependency‑free helper for walking a directory tree and producing a nested hash representation of the file system.

It supports:

  • Recursive traversal of directories

  • Skipping hidden files/directories and symbolic links

  • Excluding arbitrary paths via glob patterns

  • Limiting the depth of the returned tree

Example

require_relative 'analyze_directory'

include OllamaChat::Utils::AnalyzeDirectory

structure = generate_structure(
  '/path/to/dir',
  exclude: ['tmp', 'vendor'],
  max_depth: 3
)

puts structure.inspect

Instance Method Summary collapse

Instance Method Details

#generate_structure(path = '.', exclude: [], suffix: nil, max_depth: nil) ⇒ Array<Hash>

Generate a nested hash representation of a directory tree.

Examples:

Basic usage

generate_structure(
  '/tmp',
  exclude: ['cache', 'logs'],
  max_depth: 2
)

Parameters:

  • path (String, Pathname) (defaults to: '.')

    The root directory to walk. Defaults to the current working directory (‘“.”`).

  • exclude (Array<String, Pathname>) (defaults to: [])

    Glob patterns (relative to path) that should be ignored during traversal.

  • suffix (String, nil) (defaults to: nil)

    Optional file extension filter (e.g., ‘rb’). If provided, only files with this suffix are included in the result. Pass nil or an empty string to include all files.

  • max_depth (Integer, nil) (defaults to: nil)

    Optional depth limit. If nil, the entire tree is returned. When an integer is supplied, all entries deeper than that depth are pruned.

Returns:

  • (Array<Hash>)

    An array of entry hashes. Each hash contains:

    • :type – “file” or “directory”

    • :name – Base name of the file/directory

    • :path – Absolute path

    • :depth – Depth relative to the root (root = 0)

    • :height – The maximum depth found in the entire tree

    • :children – Array of child entry hashes (only for directories)

Raises:

  • (StandardError)

    Any exception raised during traversal is rescued and returned as a hash with :error and :message keys.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/ollama_chat/utils/analyze_directory.rb', line 63

def generate_structure(path = '.', exclude: [], suffix: nil, max_depth: nil)
  entries = recurse_generate_structure(path, exclude:, suffix:)
  height  = 0

  structure_each_entry(entries) do |e|
    height = e[:depth] if e[:depth] > height
  end

  structure_each_entry(entries) { |e| e[:height] = height }

  if max_depth && max_depth < height
    structure_each_entry(entries) do |e|
      e[:children]&.reject! { |c| c[:depth] > max_depth }
    end
  end

  entries
rescue => e
  { error: e.class, message: e.message }
end

#recurse_generate_structure(path = '.', exclude: [], suffix: nil, depth: 0) ⇒ Array<Hash> (private)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Recursively walk path and build the tree.

Parameters:

  • path (String, Pathname) (defaults to: '.')

    Directory to traverse.

  • exclude (Array<Pathname>) (defaults to: [])

    List of absolute paths to skip.

  • suffix (String, nil) (defaults to: nil)

    Optional file extension filter. If provided, only files with this suffix are included.

  • depth (Integer) (defaults to: 0)

    Current depth (root = 0).

Returns:

  • (Array<Hash>)

    Array of entry hashes.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/ollama_chat/utils/analyze_directory.rb', line 97

def recurse_generate_structure(path = '.', exclude: [], suffix: nil, depth: 0)
  exclude = Array(exclude).map { |p| Pathname.new(p).expand_path }
  extname = suffix&.sub(/\A(?<!.)/, ?.)
  path    = Pathname.new(path).expand_path
  entries = []

  path.children.sort.each do |child|
    # Skip hidden files/directories
    next if child.basename.to_s.start_with?('.')
    # Skip symlinks
    next if child.symlink?
    # Skip user‑excluded paths
    next if exclude.any? { |e| child.fnmatch?(e.to_s, File::FNM_PATHNAME) }

    if child.directory?
      entries << {
        type:     'directory',
        name:     child.basename.to_s,
        path:     child.expand_path.to_s,
        children: recurse_generate_structure(child, exclude:, suffix:, depth: depth + 1),
        depth:
      }
    elsif child.file?
      # Skip unless suffix matches
      next if extname.present? && child.extname != extname
      entries << {
        type:  'file',
        name:  child.basename.to_s,
        path:  child.expand_path.to_s,
        depth:
      }
    end
  end

  entries
end

#structure_each_entry(entries) {|Hash| ... } ⇒ Array<Hash> (private)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Iterate over every entry in entries (depth‑first).

Parameters:

  • entries (Array<Hash>)

    The root array of entries.

Yields:

  • (Hash)

    Yields each entry hash.

Returns:

  • (Array<Hash>)

    The original entries array.



142
143
144
145
146
147
148
149
# File 'lib/ollama_chat/utils/analyze_directory.rb', line 142

def structure_each_entry(entries, &block)
  queue = entries.dup
  while entry = queue.shift
    block.(entry)
    queue.concat(entry[:children]) if entry[:children]
  end
  entries
end