Module: Woods::FilenameUtils

Included in:
Extractor, Resilience::IndexValidator
Defined in:
lib/woods/filename_utils.rb

Overview

Shared filename helpers for converting unit identifiers to safe filenames.

Used by Extractor (writing) and IndexValidator (reading) to ensure filename generation is consistent across both sides.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.flow_filename(controller_id, action) ⇒ String

Filename for a precomputed request-flow document, combining the controller identifier and action name — each normalized via safe_segment. Used by both Woods::FlowPrecomputer (writing) and the MCP server's trace_flow (reading) so a name containing an out-of-charset character is written and looked up under the SAME file (the writer previously left the action raw while the reader allow-listed it, so such flows were written under one name and never found).

Parameters:

  • controller_id (String)

    e.g. "Admin::UsersController"

  • action (String)

    e.g. "index"

Returns:

  • (String)

    e.g. "Admin__UsersController_index.json"



36
37
38
# File 'lib/woods/filename_utils.rb', line 36

def self.flow_filename(controller_id, action)
  "#{safe_segment(controller_id)}_#{safe_segment(action)}.json"
end

.safe_segment(identifier) ⇒ String

Normalize a single identifier segment for use in a filename: replace :: with __ and every other non-[a-zA-Z0-9_-] character with _. This is the one character transform shared by #safe_filename, #collision_safe_filename, and the precomputed-flow reader/writer (via flow_filename) so the sides of each filename contract cannot drift. Also usable as a module method (FilenameUtils.safe_segment) for callers that don't mix the module in.

Parameters:

  • identifier (String)

Returns:

  • (String)


21
22
23
# File 'lib/woods/filename_utils.rb', line 21

def self.safe_segment(identifier)
  identifier.to_s.gsub('::', '__').gsub(/[^a-zA-Z0-9_-]/, '_')
end

Instance Method Details

#collision_safe_filename(identifier) ⇒ String

Convert an identifier to a collision-safe filename (current format).

Appends a short SHA256 digest to disambiguate identifiers that normalize to the same safe_filename.

Parameters:

  • identifier (String)

    The unit identifier

Returns:

  • (String)

    Collision-safe filename (e.g., "Admin__UsersController_a1b2c3d4.json")



55
56
57
58
59
# File 'lib/woods/filename_utils.rb', line 55

def collision_safe_filename(identifier)
  base = FilenameUtils.safe_segment(identifier)
  digest = Digest::SHA256.hexdigest(identifier)[0, 8]
  "#{base}_#{digest}.json"
end

#safe_filename(identifier) ⇒ String

Convert an identifier to a safe filename (legacy format).

Parameters:

  • identifier (String)

    The unit identifier (e.g., "Admin::UsersController")

Returns:

  • (String)

    A filesystem-safe filename (e.g., "Admin__UsersController.json")



44
45
46
# File 'lib/woods/filename_utils.rb', line 44

def safe_filename(identifier)
  "#{FilenameUtils.safe_segment(identifier)}.json"
end