# File lib/asciidoctor/cli/invoker.rb, line 30
      def invoke!
        old_verbose = -1
        return unless @options

        old_verbose = $VERBOSE
        case @options[:verbose]
        when 0
          $VERBOSE = nil
        when 1
          $VERBOSE = false
        when 2
          $VERBOSE = true
        end

        opts = {}
        infiles = []
        outfile = nil
        tofile = nil
        @options.map do |key, val|
          case key
          when :input_files
            infiles = val
          when :output_file
            outfile = val
          when :destination_dir
            opts[:to_dir] = val if val
          when :attributes
            # NOTE processor will dup attributes internally
            opts[:attributes] = val
          when :trace
            # currently, nothing
          else
            opts[key] = val unless val.nil?
          end
        end

        if infiles.size == 1 && infiles[0] == '-'
          # allows use of block to supply stdin, particularly useful for tests
          inputs = [block_given? ? yield : STDIN]
        else
          inputs = infiles.map {|infile| ::File.new infile, 'r'}
        end

        # NOTE if infile is stdin, default to outfile as stout
        if outfile == '-' || (!outfile && infiles.size == 1 && infiles[0] == '-')
          tofile = (@out || $stdout)
        elsif outfile
          tofile = outfile
          opts[:mkdirs] = true
        else
          # automatically calculate outfile based on infile unless to_dir is set
          tofile = nil
          opts[:mkdirs] = true
        end

        show_timings = @options[:timings]
        inputs.each do |input|
          # NOTE processor will dup options and attributes internally
          input_opts = tofile.nil? ? opts : opts.merge(:to_file => tofile)
          if show_timings
            timings = Timings.new
            @documents << ::Asciidoctor.convert(input, input_opts.merge(:timings => timings))
            timings.print_report((@err || $stderr), ((input.respond_to? :path) ? input.path : '-'))
          else
            @documents << ::Asciidoctor.convert(input, input_opts)
          end
        end
      rescue ::Exception => e
        if ::SignalException === e
          @code = e.signo
          # add extra endline if Ctrl+C is used
          (@err || $stderr).puts if ::Interrupt === e
        else
          @code = (e.respond_to? :status) ? e.status : 1
          if @options[:trace]
            raise e
          else
            err = (@err || $stderr)
            if ::RuntimeError === e
              err.puts %(#{e.message} (#{e.class}))
            else
              err.puts e.message
            end
            err.puts '  Use --trace for backtrace'
          end
        end
        nil
      ensure
        $VERBOSE = old_verbose unless old_verbose == -1
      end