class FolderStash::FolderTree

A FolderTree represents a nested directory path.

Attributes

folder_limit[R]

The maximum number of itmes that may be stored in any folder in folders.

folders[RW]

An array with instances of Folder, one for each directory in a nested directory path from the root to the terminal.

path_length[R]

The number of items (directories) in a nested directory path, from the root (base directory) to the terminal.

tree_limit[R]

Public Class Methods

empty(root, levels:, limit:) click to toggle source
# File lib/folder_stash/folder_tree.rb, line 34
def self.empty(root, levels:, limit:)
  folders = [Folder.new(root)]
  tree = new(folders, levels, limit)
  tree.new_branch_in tree.root, levels
  tree
end
for_path(path, root:, limit:) click to toggle source
# File lib/folder_stash/folder_tree.rb, line 41
def self.for_path(path, root:, limit:)
  path_items = path_segment path, root
  folders = Folder.folders_for_path_segment root, path_items
  new folders, path_items.count, limit
end
new(folders, levels, limit) click to toggle source

Returns a new instance.

Arguments
  • folders (String) - Array of Folder instances.

  • levels (Integer) - Number of nested subdirectories in a path.

  • limit (Integer) - Number of items allowed in any folder in the tree's directory path.

# File lib/folder_stash/folder_tree.rb, line 27
def initialize(folders, levels, limit)
  @folders = folders
  @path_length = levels ? levels + 1 : nil
  @folder_limit = limit
  @tree_limit = folder_limit ? folder_limit**(path_length) : nil
end
path_segment(terminal, root) click to toggle source
# File lib/folder_stash/folder_tree.rb, line 47
def self.path_segment(terminal, root)
  File.expand_path(terminal).split('/') - File.expand_path(root).split('/')
end

Public Instance Methods

actual_path_length() click to toggle source

Returns the number of folder in the nested path currently available.

# File lib/folder_stash/folder_tree.rb, line 52
def actual_path_length
  folders.count
end
available_folder() click to toggle source

Returns the next available folder, searching upstream from the terminal folder to the root.

Returns root if root is the only folder.

# File lib/folder_stash/folder_tree.rb, line 60
def available_folder
  return root if flat?

  folders.reverse.find { |folder| folder.count < folder_limit }
end
branch_path() click to toggle source
# File lib/folder_stash/folder_tree.rb, line 66
def branch_path
  folders.map(&:basename)
end
flat?() click to toggle source
# File lib/folder_stash/folder_tree.rb, line 70
def flat?
  actual_path_length == 1 && path_length.nil?
end
levels_below(folder) click to toggle source

Returns the number of levels of folders nested in folder.

# File lib/folder_stash/folder_tree.rb, line 75
def levels_below(folder)
  return if flat?

  subdirectories - folders.index(folder)
end
new_branch_in(folder, levels = nil) click to toggle source

Creates a new branch of folders in folder and updates folders to the new branch.

Returns an array with the full path for the terminal folder in the branch created.

# File lib/folder_stash/folder_tree.rb, line 91
def new_branch_in(folder, levels = nil)
  return if flat?

  raise Errors::BranchError.new(dir: folder.path) if folder == terminal

  raise TreeLimitExceededError.new(tree: self) if folder.count >= folder_limit

  levels ||= levels_below folder
  new_branch = new_paths_in folder, levels
  @folders = folders[0..folders.index(folder)].concat new_branch
  folders.last.create!
end
root() click to toggle source

Returns the root folder.

# File lib/folder_stash/folder_tree.rb, line 105
def root
  folders.first
end
subdirectories() click to toggle source

The nesting depth (Integer) of subdirectories in the base directory.

# File lib/folder_stash/folder_tree.rb, line 82
def subdirectories
  path_length - 1
end
terminal() click to toggle source

Returns the terminal (most deeply nested) folder.

Returns nil if the tree has not been fully initialized with a branch.

# File lib/folder_stash/folder_tree.rb, line 112
def terminal
  return root if flat?

  return if actual_path_length < path_length

  folders.last
end

Private Instance Methods

ensure_unique_node(path, name) click to toggle source

If the file path/name exists, randomize the name until a new random is found that does not exist.

Returns the new unique path name.

This only needs to be called for the first new directory to be created, all others will be created in empty directories and therefroe always be unique.

# File lib/folder_stash/folder_tree.rb, line 130
def ensure_unique_node(path, name)
  name = SecureRandom.hex(8) while File.exist? File.join(path, name)
  Folder.new File.join(path, name)
end
new_paths_in(folder, count) click to toggle source

Returns an array of new Folder instances.

# File lib/folder_stash/folder_tree.rb, line 136
def new_paths_in(folder, count)
  first_node = ensure_unique_node(folder.path, SecureRandom.hex(8))
  remainder = count - 1
  remainder.times.inject([first_node]) do |nodes|
    path = File.join nodes.last.path, SecureRandom.hex(8)
    nodes << Folder.new(path)
  end
end