Friday, September 20, 2024 2:57:38 AM
> settings

Customize


Authenticate

> cache.rb
# frozen_string_literal: true

class Project
  class Cache
    DISALLOWED_EXTENSIONS = %w[.exe]

    attr_writer :cache

    def initialize(os_path, allowed_paths, disallowed_paths)
      @os_path = os_path
      @allowed_paths = allowed_paths
      @disallowed_paths = disallowed_paths
      @top_level_index = 0
    end

    def cache
      @cache ||= initialize_cache(@allowed_paths, @disallowed_paths)
    end

    alias_method :entries, :cache

    def top_level_entries
      entries.select { |key, _| key.size == @top_level_index }
        .values
        # Sort directories first, then files. Both sorted alphabetically (case-insensitive).
        .sort_by { |entry| [(entry.directory? ? 0 : 1), entry.name.downcase] }
    end

    def find(*key)
      entries[key]
    end

    def find_by_path(path)
      return if path.blank?

      find(*path_to_array(path))
    end

    def children(parent_or_key, level: 1)
      parent =
        if parent_or_key.is_a?(Entry)
          parent_or_key
        else
          find(*parent_or_key)
        end

      return [] if parent.nil?

      level += parent.key.size
      entries.select do |key, entry|
        next if key.size != level
        next if entry == parent

        parent.child?(entry)
      end
    end

    private

    def path_to_array(path)
      path.split("/")
        .reject(&:blank?)
        .map(&:to_sym)
    end

    def os_path_to_array(path)
      return [] if path.blank?

      path_to_array(path.to_s.sub(@os_path.to_s, ""))
    end

    def initialize_cache(allowed_paths, disallowed_paths)
      allowed_paths = Trie.new(allowed_paths.map { |p| os_path_to_array(p) })
      disallowed_paths = Trie.new(disallowed_paths.map { |p| os_path_to_array(p) })

      # If the only path is an asterisk, allow all files
      # Perf: We only need to check this once
      allow_all_files = allowed_paths.exists?([:*])

      cache =
        Dir["#{@os_path}/**/*"].each_with_object({}) do |path, cache|
          path = Pathname.new(path)

          # Convert the file path into an array of symbols
          #   "lib/directory/file.txt" => [:lib, :directory, :"file.txt"]
          path_array = path_to_array(path.to_s.sub(@os_path.to_s, ""))

          entry =
            if ::File.directory?(path)
              Project::Directory.new(self, path_array, path)
            else
              Project::File.new(path_array, path)
            end

          next if DISALLOWED_EXTENSIONS.include?(entry.type)
          next unless allow_all_files || allowed_paths.exists?(entry.key)
          next if disallowed_paths.exists?(entry.key)

          cache[path_array] = entry
        end

      # Not every project's top level entries will have 1 path element
      @top_level_index = cache.keys.map(&:count).min

      cache
    end
  end
end
All opinions represented herein are my own
- © 2024 itsthedevman
- build 340fbb8