kigster/warp-dir

View on GitHub
lib/warp/dir/app/response.rb

Summary

Maintainability
A
1 hr
Test Coverage
A
90%
require 'singleton'

module Warp
  module Dir
    module App
      class Response

        # Use Case                       exit code       stream
        #----------------------------------------------------------------
        # Information / Help / List              0       STDOUT
        # Error occurred                         1       STDERR
        # Execute Shell Command                  2       STDOUT

        class Type < Struct.new(:exit_code, :stream)
          def print(msg)
            under_shell = ::Warp::Dir.eval_context?
            if msg == ' '
              under_shell ? stream.printf(%Q{printf '\\n'; }) : stream.printf("\n")
            else
              msg.split("\n").each do |line|
                under_shell ? stream.printf(%Q{printf -- '#{line.gsub(/['`]/, '\"')}\\n';}) : stream.printf("#{line}\n")
              end
            end
          end

          def to_s
            "code:#{exit_code}, stream:#{stream == $stdout ? "STDOUT" : "STDERR"}"
          end
        end

        INFO  = Type.new(0, $stdout)
        ERROR = Type.new(1, $stderr)
        SHELL = Type.new(2, $stdout)

        SHELL.instance_eval do
          def print(msg)
            under_shell = ::Warp::Dir.eval_context?
            if under_shell
              stream.printf("#{msg};")
            else
              stream.printf(
                "#{'WARNING: '.red}This functionality is only available within shell eval{} context:\n\n\t#{msg.yellow.bold}\n\nPlease install shell wrapper 'wd' via the 'install' command.\n")
            end
          end

          # can't change exit code in SHELL
          def exit_code=(value)
          end
        end

        RETURN_TYPE = {
          success: INFO,
          error:   ERROR,
          shell:   SHELL
        }

        attr_accessor :messages, :config

        def initialize
          @messages = []
        end

        # Public Methods
        def print
          raise ::ArgumentError.new('No type defined for Response object') unless @type
          @type.print(@messages.shift) until @messages.empty?
          self
        end

        def exit!
          raise ::ArgumentError.new('No type defined for Response object') unless @type
          system_exit!(@type.exit_code)
        end

        # Configure & Accessors
        def configure(&block)
          self.instance_eval(&block)
          self
        end

        def self.configure(&block)
          self.instance.configure(&block)
        end

        def message(message = nil)
          if message
            @messages << message
            self
          else
            @messages.join
          end
        end

        def type(a_type = nil)
          if a_type
            @type = a_type.kind_of?(Warp::Dir::App::Response::Type) ? a_type : RETURN_TYPE[a_type]
            raise(::ArgumentError.new("Can't find response type #{a_type} #{@type}")) unless @type
            self
          else
            @type
          end
        end

        def code(value = nil)
          if value
            @type.exit_code = value
            self
          else
            @type.exit_code
          end
        end

        def inspect
          "#{self.class.name}={#{type.inspect}, #{messages.inspect}}"
        end

        def to_s
          "AppResponse[type: {#{type}}, messages: '#{messages.join(' ')}']"
        end

        private

        def system_exit!(code)
          Kernel.exit(code) unless self.class.instance_variable_defined?(:@exit_disabled) && self.class.exit_disabled?
          self
        end

      end
    end
  end
end