lib/em-systemcommand/pipe.rb in em-systemcommand-2.0.0 vs lib/em-systemcommand/pipe.rb in em-systemcommand-2.0.1

- old
+ new

@@ -1,27 +1,36 @@ +# -*- coding: utf-8 -*- module EventMachine class SystemCommand class Pipe < EM::Connection - def initialize(master, name) + def initialize master, name @master = master @name = name @master.pipes[name] = self begin - @outputbuffer = StringIO.new() + @outputbuffer = StringIO.new rescue Exception => e puts "Uninitialized constant StringIO. This may happen when you forgot to use bundler. Use `bundle exec`." end end + ## + # The content of the output buffer as string. + # + # @return [String] The connections output def output @outputbuffer.string end ## # Convenience method to create a callback that matches a regular # expression + # + # @param [Regexp] regexp The regular expression that should be matched + # @option opt [Symbol] :in Match either in `:line` or `:output` + # @option opt [Symbol] :match Match either `:first` or `:last` def match regexp, opt = {}, &block opt = { in: :line, match: :first }.merge opt (opt[:in] == :output ? receive_update_callbacks : receive_line_callbacks) << lambda do |data| matches = data.scan regexp if matches.length > 0 @@ -33,72 +42,119 @@ end end end end + ## # Invoked when line was received + # + # @param [String] line The line that´s received def receive_line line receive_line_callbacks.each do |callback| callback.call line.dup end end + ## # Adds a callback for `receive_line` events. + # + # @yield The callback that should be added to callback array for line events + # @yieldparam [String] line The line that has been received def line &block receive_line_callbacks << block end + ## # Invoked when a line was written, but `\r` was received without # a line-break in the end. + # + # @param [String] buffer The complete buffer content of this connection def receive_update buffer receive_update_callbacks.each do |callback| callback.call buffer.dup end end + ## # Adds a callback for `receive_update` events. + # + # @yield The callback that should be added to callback array for update events + # @yieldparam [String] buffer The complete buffer content of this connection def update &block receive_update_callbacks << block end + ## # Invoked when data was received. + # + # @param [String] data The received data def receive_data data, recursive = false + # if recursive is true we already invoked the receive data callbacks! unless recursive receive_data_callbacks.each do |callback| callback.call data.dup end end @linebuffer ||= [] - @cr_offset = 0 + @lf_offset ||= 0 parse_crlf data receive_update @outputbuffer.string unless recursive end + ## + # Parses carriage return when data is received. + # + # @param [String] data The received data + # @param [Integer] ix The index of the carriage return def parse_cr data, ix ln = (@linebuffer << data[0...ix]).join @linebuffer.clear + receive_line ln @outputbuffer.print ln - @outputbuffer.pos = @cr_offset - parse_crlf data[(ix+1)..-1] # receive rest data + + # jump back to the last line feed + @outputbuffer.pos = @lf_offset + + # parse rest of the data + parse_crlf data[(ix+1)..-1] end + ## + # Parses line feed when data is received. + # + # @param [String] data The received data + # @param [Integer] ix The index of the line feed def parse_lf data, ix ln = (@linebuffer << data[0...ix]).join @linebuffer.clear ln.chomp! + receive_line ln @outputbuffer.print ln + + # jump to the end of the buffer to keep the characters, that + # may already have been written @outputbuffer.pos = @outputbuffer.length + # print the line feed @outputbuffer.puts - @cr_offset = @outputbuffer.pos - parse_crlf data[(ix+1)..-1] # receive rest data + # set last line feed to the current cursor position, so we + # know where we have to jump back, when a carriage return occurs + @lf_offset = @outputbuffer.pos + + # parse rest of the data + parse_crlf data[(ix+1)..-1] end + ## + # Parse received data for line feeds or carriage returns. + # + # @param [String] data The received data def parse_crlf data + return if data == '' if ilf = data.index("\n") # if we find a LF and that LF is after a CR we first handle # the CR if icr = data.index("\r") and ilf != (icr+1) and icr < ilf parse_cr data, icr @@ -113,14 +169,19 @@ @outputbuffer.print data end end end + ## # Adds a callback for `receive_data` events. + # + # @yield The callback that´s to be added to the data callback array + # @yieldparam [String] data The data that´s received def data &block receive_data_callbacks << block end + ## # Close the attached IO object. def close begin @io.close unless @io.closed? detach