require 'colored2' module CLIntegracon # A LazyString is constructed by a block, but only evaluated when needed class LazyString # @return [Proc] # the closure which will be used to build the string attr_reader :proc # Initialize a LazyString # # @param [Block () -> (String)] block # the block which returns a string, called by #to_s # def initialize(&block) @proc = block end # Calls the underlying proc to build the string. The result will be # memorized, so subsequent calls of this method will not cause that the # proc will be called again. # # @return [String] # def to_str @string ||= proc.call().to_s end alias :to_s :to_str end # A LazyStringProxy returns a LazyString for each call, which delegates the # call as soon as the result is needed to the underlying formatter. class LazyStringProxy # @return [Formatter] # the formatter used to build the string attr_reader :formatter # Initialize a LazyStringProxy, which returns for each call to an # underlying formatter a new LazyString, whose #to_s method will evaluate # to the result of the original call delegated to the formatter. # # @param [Formatter] formatter # the formatter # def initialize(formatter) @formatter = formatter end # Remember the call delegated to #formatter in a closure on an anonymous # object, defined as method :to_s. # # @return [#to_s] # def method_missing(method, *args, &block) return LazyString.new do @formatter.send(method, *args, &block) end end # Respond to all methods, which are beginning with `describe_` to # which the #formatter also responds. # # @return [Bool] # def respond_to?(method) if /^describe_/.match(method.to_s) && @formatter.respond_to?(method) true else super end end end class Formatter # @return [FileTreeSpec] # the spec attr_reader :spec # Initialize # # @param [FileTreeSpec] spec # the spec # def initialize(spec) super() @spec = spec end # Return a proxy, which returns formatted string, evaluated first # if #to_s is called on this instance. # # @return [LazyStringProxy] # def lazy LazyStringProxy.new(self) end # Return a description text for an expectation that a file path # was expected to exist, but is missing. # # @param [Pathname] file_path # the file path which was expected to exist # # @return [String] # def describe_missing_file(file_path) description = [] description << "Missing file for #{spec.spec_folder}:" description << " * #{file_path.to_s.red}" description * "\n" end # Return a description text for an expectation that certain file paths # were unexpected. # # @param [Array<Pathname>] file_paths # # @return [String] # def describe_unexpected_files(file_paths) description = [] description << "Unexpected files for #{spec.spec_folder}:" description += file_paths.map { |f| " * #{f.to_s.green}" } description * "\n" end # Return a description text for an expectation that two files were # expected to be the same, but are not. # # @param [Diff] diff # the diff which holds the difference # # @param [Integer] max_width # the max width of the terminal to print matching separators # # @return [String] # def describe_file_diff(diff, max_width=80) description = [] description << "File comparison error `#{diff.relative_path}` for #{spec.spec_folder}:" description << "--- DIFF ".ljust(max_width, '-') description += diff.map do |line| case line when /^\+/ then line.green when /^-/ then line.red else line end.gsub("\n",'').gsub("\r", '\r') end description << "--- END ".ljust(max_width, '-') description << '' description * "\n" end end end