code: func NewWithCache(file string, cache Cache, errors func(Error) bool) GitIgnore {
  	// do we have an error handler?
  	_errors := errors
  	if _errors == nil {
  		_errors = func(e Error) bool { return true }
  	}
  
  	// use the file absolute path as its key into the cache
  	_abs, _err := filepath.Abs(file)
  	if _err != nil {
  		_errors(NewError(_err, Position{}))
  		return nil
  	}
  
  	var _ignore GitIgnore
  	if cache != nil {
  		_ignore = cache.Get(_abs)
  	}
  	if _ignore == nil {
  		_ignore = NewWithErrors(file, _errors)
  		if _ignore == nil {
  			// if the load failed, cache an empty GitIgnore to prevent
  			// further attempts to load this file
  			_ignore = empty
  		}
  		if cache != nil {
  			cache.Set(_abs, _ignore)
  		}
  	}
  
  	// return the ignore (if we have it)
  	if _ignore == empty {
  		return nil
  	} else {
  		return _ignore
  	}
  }
docs: // NewWithCache returns a GitIgnore instance (using NewWithErrors)
  // for the given file. If the file has been loaded before, its GitIgnore
  // instance will be returned from the cache rather than being reloaded. If
  // cache is not defined, NewWithCache will behave as NewWithErrors
  //
  // If NewWithErrors returns nil, NewWithCache will store an empty
  // GitIgnore (i.e. no patterns) against the file to prevent repeated parse
  // attempts on subsequent requests for the same file. Subsequent calls to
  // NewWithCache for a file that could not be loaded due to an error will
  // return nil.
  //
  // If errors is given, it will be invoked for every error encountered when
  // parsing the .gitignore patterns. Parsing will terminate if errors is called
  // and returns false, otherwise, parsing will continue until end of file has
  // been reached.