/// <summary> /// Extracts words from a document content read with <paramref name="sourceReader"/> and returns them as an observable sequence /// </summary> /// <param name="sourceReader">The reader to read the document content from</param> /// <returns>Observable sequence with a document words, one by one</returns> /// <remarks> /// Reads the content from the <paramref name="sourceReader"/> line by line and extracts words from each line /// with the specified <see cref="ILineParser"/> instance. /// </remarks> public IObservable <string> ExtractWords([NotNull] TextReader sourceReader) { if (sourceReader == null) { throw new ArgumentNullException("sourceReader"); } if (!UseAsync) { return(Observable.Create <string>(obs => { var scheduler = Scheduler.Default; var subscription = new SingleAssignmentDisposable(); subscription.Disposable = scheduler.Schedule(() => { try { while (!subscription.IsDisposed) { var line = sourceReader.ReadLine(); if (line == null) { break; } foreach (var word in lineParser.ExtractWords(line)) { obs.OnNext(word); } } obs.OnCompleted(); } catch (Exception e) { obs.OnError(e); } }); return subscription; })); } else { // async version is much more slower return(Observable.Create <string>(async(obs, cancel) => { try { while (!cancel.IsCancellationRequested) { var line = await sourceReader.ReadLineAsync().ConfigureAwait(false); if (line == null) { break; } foreach (var word in lineParser.ExtractWords(line)) { obs.OnNext(word); } } obs.OnCompleted(); } catch (Exception e) { obs.OnError(e); } }).SubscribeOn(Scheduler.Default)); } }