def each_complete_message
      partials = {}  # hash of message type to message-chain-in-progress
      each_message do |msg|
        # don't clutter things up if the message arrives already complete
        if msg.all_messages_received?
          yield msg
          next
        end

        # put message into partials slot (merge if necessary) based on its data type
        slot = msg.data_type
        if partials[slot].nil?                                           # no message in there
          partials[slot] = msg
        elsif 1 != (msg.message_number - partials[slot].message_number)  # broken sequence
          # error! just overwrite what was there
          partials[slot] = msg
        else                                                             # chain on to what's there
          partials[slot].add_message_part(msg)
        end

        # take action if we've completed the chain
        maybe_full = partials[slot]
        if maybe_full.all_messages_received?
          partials[slot] = nil
          yield maybe_full
        end
      end
    end
def each_complete_message
      partials = {}  # hash of message type to message-chain-in-progress
      each_message do |msg|
        # don't clutter things up if the message arrives already complete
        if msg.all_messages_received?
          yield msg
          next
        end

        # put message into partials slot (merge if necessary) based on its data type
        slot = msg.data_type
        if partials[slot].nil?                                           # no message in there
          partials[slot] = msg
        elsif 1 != (msg.message_number - partials[slot].message_number)  # broken sequence
          # error! just overwrite what was there
          partials[slot] = msg
        else                                                             # chain on to what's there
          partials[slot].add_message_part(msg)
        end

        # take action if we've completed the chain
        maybe_full = partials[slot]
        if maybe_full.all_messages_received?
          partials[slot] = nil
          yield maybe_full
        end
      end
    end
Attempts to group multipart NMEA messages into chains, and executes the block once for every complete chain.
 To limit memory use (and be realistic about our ability to match up messages), only 1 message of chain of
 each NMEA message type can be in progress at any one time.

 @yield [NMEAPlus::Message] A parsed message that may contain subsequent parts
 @return [void]
 @example
   input1 = "!AIVDM,2,1,0,A,58wt8Ui`g??r21`7S=:22058<v05Htp000000015>8OA;0sk,0*7B"
   input2 = "!AIVDM,2,2,0,A,eQ8823mDm3kP00000000000,2*5D"
   io_source = StringIO.new("#{input1}\n#{input2}")  # source decoder works on any IO object
   source_decoder = NMEAPlus::SourceDecoder.new(io_source)
   source_decoder.each_complete_message do |message|
     if message.ais && message.ais.message_type == 5
       ais = message.ais  # ais payload shortcut
       puts "Ship with MMSI #{ais.source_mmsi} (#{ais.name.strip}) is going to #{ais.destination.strip}"
       # prints "Ship with MMSI 603916439 (ARCO AVON) is going to HOUSTON"
     end
   end