lib/frecli/cache.rb

Summary

Maintainability
A
0 mins
Test Coverage
class Frecli
  class Cache
    class PathNotFoundError < StandardError
      def initialize(message = nil, key: nil)
        message ||= if key
                      "No such cache path found: `#{key}`."
                    else
                      'No such cache path found.'
                    end

        super(message)
      end
    end

    class NotCachedError < StandardError
      def initialize(message = nil, key: nil)
        message ||= if key
                      "No such cache available: `#{key}`."
                    else
                      'No such cache available.'
                    end

        super(message)
      end
    end

    PATHS = {
      projects: '/projects.json'
    }.freeze

    def initialize(cache_path, ttl)
      @cache_path = cache_path.sub(/^~/, Dir.home)
      @ttl = ttl # cache ttl in minutes

      FileUtils.mkdir_p @cache_path
    end

    def cached?(key)
      path = cache_path(key)

      File.exist?(path) && within_ttl?(path)
    end

    def uncached?(key)
      !cached?(key)
    end

    def get(key, as: Hash)
      raise NotCachedError.new(key: key) if uncached?(key)

      File.open(cache_path(key)) do |file|
        collection = JSON.load(file)

        return collection.map do |record|
          record.is_a?(as) ? record : as.new(record)
        end
      end
    end

    def cache!(key, objects)
      File.open(cache_path(key), 'w+') do |file|
        JSON.dump objects, file
      end
    end

    private

    def cache_path(key = nil)
      return @cache_path unless key
      raise PathNotFoundError.new(key: key) unless PATHS.key?(key)

      [@cache_path.sub(%r{/\Z}, ''), PATHS[key]].join '/'
    end

    def within_ttl?(path)
      (Time.now - File.mtime(path)) <= ttl_in_seconds
    end

    def ttl_in_seconds
      @ttl * 60
    end
  end
end