Der TextReader ist eine klassische Datenquelle. Er liest eine oder mehrere Dateien und gibt sie Zeilenweise in den Ausgabekanal. Der Start bzw. Wechsel einer Datei wird dabei über den Kommandokanal angekündigt, ebenso wie das Ende.
Der TextReader kann ebenfalls ein spezielles Dateiformat verarbeiten, welches zum Austausch mit dem LIR-System dient. Dabei enthält die Datei Record-basierte Informationen, die wie mehrere Dateien verarbeitet werden.
Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung). Alle anderen Parameter müssen zwingend angegeben werden.
siehe allgemeine Beschreibung des Attendee
Es können eine oder mehrere Dateien angegeben werden, die nacheinander eingelesen und zeilenweise weitergeleitet werden. Die Dateien werden mit Komma voneinander getrennt, z.B.
files: 'readme.txt' files: 'readme.txt,lingo.cfg'
Mit diesem Parameter wird angegeben, woran der Anfang eines neuen Records erkannt werden kann und wie die Record-Nummer identifiziert wird. Das Format einer LIR-Datei ist z.B.
[00001.] 020: ¬Die Aufgabenteilung zwischen Wortschatz und Grammatik. [00002.] 020: Nicht-konventionelle Thesaurusrelationen als Orientierungshilfen.
Mit der Angabe von
records: "^\[(\d+)\.\]"
werden die Record-Zeilen erkannt und jeweils die Record-Nummer
00001, bzw. 00002 erkannt.
Damit der nachfolgende Datenstrom einwandfrei verarbeitet werden kann, generiert der TextReader Kommandos, die mit in den Datenstrom eingefügt werden.
Kennzeichnet den Beginn der Datei <dateiname>
Kennzeichnet das Ende der Datei <dateiname>
Kennzeichnet die Verarbeitung einer Datei im LIR-Format (nur bei LIR-Format).
Kennzeichnet den Beginn eines neuen Records (nur bei LIR-Format).
Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration
t1.cfg
meeting:
attendees:
- text_reader: { out: lines, files: '$(files)' }
- debugger: { in: lines, prompt: 'out>' }
ergibt die Ausgabe über den Debugger: lingo -c t1 test.txt
out> *FILE('test.txt')
out> "Dies ist eine Zeile."
out> "Dies ist noch eine."
out> *EOF('test.txt')
Bei der Verarbeitung einer LIR-Datei mit der Ablaufkonfiguration
t2.cfg
meeting:
attendees:
- text_reader: { out: lines, files: '$(files)', records: "^\[(\d+)\.\]" }
- debugger: { in: lines, prompt: 'out>'}
ergibt die Ausgabe mit lingo -c t2 lir.txt
out> *LIR-FORMAT('')
out> *FILE('lir.txt')
out> *RECORD('00001')
out> "020: \254Die Aufgabenteilung zwischen Wortschatz und Grammatik."
out> *RECORD('00002')
out> "020: Nicht-konventionelle Thesaurusrelationen als Orientierungshilfen."
out> *EOF('lir.txt')
# File lib/lingo/attendee/text_reader.rb, line 122 def control(cmd, param) if cmd == STR_CMD_TALK forward(STR_CMD_LIR, '') if @lir @files.each(&method(:spool)) end end
TODO: FILE und LIR-FILE (?)
# File lib/lingo/attendee/text_reader.rb, line 110 def init get_files @chomp = get_key('chomp', true) @filter = get_key('filter', false) @progress = get_key('progress', false) if @lir = get_key('records', get_key('lir-record-pattern', nil)) # DEPRECATE lir-record-pattern @lir = @lir == true ? %r{^\[(\d+)\.\]} : Regexp.new(@lir) end end
# File lib/lingo/attendee/text_reader.rb, line 227 def add_files(path, glob, recursive = false) Dir[path].sort!.each { |match| File.directory?(match) ? recursive ? Find.find(match) { |entry| @files << entry if File.file?(entry) && File.fnmatch?(glob, entry) } : add_files(File.join(match, glob), glob) : @files << match }.empty? and raise FileNotFoundError.new(path) end
# File lib/lingo/attendee/text_reader.rb, line 195 def file_type(path, io) if Object.const_defined?(:FileMagic) && io.respond_to?(:rewind) FileMagic.fm(:mime, simplified: true).buffer(io.read(256)).tap { io.rewind } elsif Object.const_defined?(:MIME) && MIME.const_defined?(:Types) MIME::Types.of(path).first.tap { |type| type ? type.content_type : warn('Filters not available. File type could not be determined.') } else warn "Filters not available. Please install `ruby-filemagic' or `mime-types'." nil end end
# File lib/lingo/attendee/text_reader.rb, line 160 def filter(path, stdin = stdin?(path)) io, block = stdin ? [ @lingo.config.stdin.set_encoding(ENC), lambda { |line| yield line, 0 } ] : [ File.open(path, 'rb', encoding: ENC), lambda { |line| yield line, io.pos } ] case @filter == true ? file_type(path, io) : @filter.to_s when %rhtml/ then io = filter_html(io) when %rxml/ then io = filter_html(io, true) when %rpdf/ then filter_pdf(io, &block); return end io.each_line(&block) if io end
# File lib/lingo/attendee/text_reader.rb, line 186 def filter_html(io, xml = false) if Object.const_defined?(:Hpricot) Hpricot(io, xml: xml).inner_text else warn "#{xml ? 'X' : 'HT'}ML filter not available. Please install `hpricot'." nil end end
# File lib/lingo/attendee/text_reader.rb, line 178 def filter_pdf(io, &block) if Object.const_defined?(:PDF) && PDF.const_defined?(:Reader) PDFFilter.filter(io, &block) else warn "PDF filter not available. Please install `pdf-reader'." end end
# File lib/lingo/attendee/text_reader.rb, line 214 def get_files args = [get_key('glob', '*.txt'), get_key('recursive', false)] @files = [] Array(get_key('files', '-')).each { |path| stdin?(path) ? @files << path : add_files(path, *args) } @files.map!(&File.method(:expand_path)) @files.uniq! end
Gibt eine Datei zeilenweise in den Ausgabekanal
# File lib/lingo/attendee/text_reader.rb, line 132 def spool(path) unless stdin = stdin?(path) inc('Anzahl Dateien') add('Anzahl Bytes', size = File.size(path)) size = nil unless @progress end forward(STR_CMD_FILE, path) ShowProgress.new(self, size, path) { |progress| filter(path, stdin) { |line, pos| inc('Anzahl Zeilen') progress[pos] line.chomp! if @chomp if line =~ @lir forward(STR_CMD_RECORD, $1) else forward(line) unless line.empty? end } } forward(STR_CMD_EOF, path) end
# File lib/lingo/attendee/text_reader.rb, line 210 def stdin?(path) %w[STDIN -].include?(path) end