tex_log_parser 1.0.0.pre.10 → 1.0.0.pre.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,101 +1,105 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Matches messages of these forms:
4
- #
5
- # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
6
- # !
7
- # ./plain.tex:5: fontspec error: "font-not-found"
8
- # !
9
- # ! The font "NoSuchFont" cannot be found.
10
- # !
11
- # ! See the fontspec documentation for further information.
12
- # !
13
- # ! For immediate help type H <return>.
14
- # !...............................................
15
- #
16
- # l.5 \setmainfont{NoSuchFont}
17
- #
18
- # and
19
- #
20
- # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21
- # !
22
- # ! fontspec error: "font-not-found"
23
- # !
24
- # ! The font "NoSuchFont" cannot be found.
25
- # !
26
- # ! See the fontspec documentation for further information.
27
- # !
28
- # ! For immediate help type H <return>.
29
- # !...............................................
30
- #
31
- # l.5 \setmainfont{NoSuchFont}
32
- #
33
- # and
34
- #
35
- # .................................................
36
- # . LaTeX info: "xparse/define-command"
37
- # .
38
- # . Defining command \fontspec with sig. 'O{}mO{}' on line 472.
39
- # .................................................
40
- class HighlightedMessages
41
- include RegExpPattern
3
+ class TexLogParser
4
+ # Matches messages of these forms:
5
+ #
6
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7
+ # !
8
+ # ./plain.tex:5: fontspec error: "font-not-found"
9
+ # !
10
+ # ! The font "NoSuchFont" cannot be found.
11
+ # !
12
+ # ! See the fontspec documentation for further information.
13
+ # !
14
+ # ! For immediate help type H <return>.
15
+ # !...............................................
16
+ #
17
+ # l.5 \setmainfont{NoSuchFont}
18
+ #
19
+ # and
20
+ #
21
+ # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
22
+ # !
23
+ # ! fontspec error: "font-not-found"
24
+ # !
25
+ # ! The font "NoSuchFont" cannot be found.
26
+ # !
27
+ # ! See the fontspec documentation for further information.
28
+ # !
29
+ # ! For immediate help type H <return>.
30
+ # !...............................................
31
+ #
32
+ # l.5 \setmainfont{NoSuchFont}
33
+ #
34
+ # and
35
+ #
36
+ # .................................................
37
+ # . LaTeX info: "xparse/define-command"
38
+ # .
39
+ # . Defining command \fontspec with sig. 'O{}mO{}' on line 472.
40
+ # .................................................
41
+ class HighlightedMessages
42
+ include LogParser::RegExpPattern
42
43
 
43
- def initialize
44
- super(/^(\!{3,}|\.{3,})$/,
45
- { pattern: lambda { |m|
46
- if m[1][0] == '!'
47
- /^l\.(\d+)/
48
- else
49
- /^\.{3,}\s*$/
50
- end
51
- },
52
- until: :match,
53
- inclusive: true })
54
- end
44
+ # Creates a new instance.
45
+ def initialize
46
+ super(/^(!{3,}|\.{3,})$/,
47
+ { pattern: lambda { |m|
48
+ if m[1][0] == '!'
49
+ /^l\.(\d+)/
50
+ else
51
+ /^\.{3,}\s*$/
52
+ end
53
+ },
54
+ until: :match,
55
+ inclusive: true })
56
+ end
55
57
 
56
- def read(lines)
57
- # @type [LogMessage] msg
58
- msg, consumed = super(lines)
58
+ # (see LogParser::RegExpPattern#read)
59
+ def read(lines)
60
+ # @type [Message] msg
61
+ msg, consumed = super(lines)
59
62
 
60
- is_error = @start_match[1][0] == '!'
63
+ is_error = @start_match[1][0] == '!'
61
64
 
62
- if is_error
63
- file_line_match = %r{^(/?(?:.*?/)*[^/]+):(\d+):\s*}.match(msg.message)
64
- line = nil
65
- if !file_line_match.nil? # if file-line active
66
- msg.source_file = file_line_match[1]
67
- line = file_line_match[2].to_i
68
- msg.message.gsub!(file_line_match[0], '')
69
- elsif !@end_match[1].nil?
70
- # No file-line format, so use line number from end match
71
- line = @end_match[1].to_i
72
- end
73
- msg.source_lines = { from: line, to: line } unless line.nil?
65
+ if is_error
66
+ file_line_match = %r{^(/?(?:.*?/)*[^/]+):(\d+):\s*}.match(msg.message)
67
+ line = nil
68
+ if !file_line_match.nil? # if file-line active
69
+ msg.source_file = file_line_match[1]
70
+ line = file_line_match[2].to_i
71
+ msg.message.gsub!(file_line_match[0], '')
72
+ elsif !@end_match[1].nil?
73
+ # No file-line format, so use line number from end match
74
+ line = @end_match[1].to_i
75
+ end
76
+ msg.source_lines = { from: line, to: line } unless line.nil?
74
77
 
75
- msg.level = :error
78
+ msg.level = :error
76
79
 
77
- msg.message.gsub!(/^.*?For immediate help type.*$/, '')
78
- msg.message.gsub!(/^\!\.+\s*$/, '')
79
- msg.message.gsub!(/^l\.\d+\s+.*$/, '')
80
- else
81
- # BROKEN_BY_LINEBREAKS
82
- # TODO: may be split across lines --> remove whitespace before extracting
83
- line_match = /on line\s+(\d+)\.$/.match(msg.message)
84
- unless line_match.nil?
85
- line = line_match[1].to_i
86
- msg.source_lines = { from: line, to: line }
87
- end
80
+ msg.message.gsub!(/^.*?For immediate help type.*$/, '')
81
+ msg.message.gsub!(/^!\.+\s*$/, '')
82
+ msg.message.gsub!(/^l\.\d+\s+.*$/, '')
83
+ else
84
+ # BROKEN_BY_LINEBREAKS
85
+ # TODO: may be split across lines --> remove whitespace before extracting
86
+ line_match = /on line\s+(\d+)\.$/.match(msg.message)
87
+ unless line_match.nil?
88
+ line = line_match[1].to_i
89
+ msg.source_lines = { from: line, to: line }
90
+ end
88
91
 
89
- msg.level = :info
92
+ msg.level = :info
90
93
 
91
- msg.message.gsub!(@end_match[0], '')
92
- end
94
+ msg.message.gsub!(@end_match[0], '')
95
+ end
93
96
 
94
- msg.preformatted = true
95
- msg.message.gsub!(@start, '')
96
- msg.message.gsub!(/^#{@start_match[1][0]}\s+/, '')
97
- msg.message.strip!
97
+ msg.preformatted = true
98
+ msg.message.gsub!(@start, '')
99
+ msg.message.gsub!(/^#{@start_match[1][0]}\s+/, '')
100
+ msg.message.strip!
98
101
 
99
- [msg, consumed]
102
+ [msg, consumed]
103
+ end
100
104
  end
101
- end
105
+ end
@@ -1,51 +1,55 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Matches messages of this form:
4
- #
5
- # Package tocbasic Info: omitting babel extension for `toc'
6
- # (tocbasic) because of feature `nobabel' available
7
- # (tocbasic) for `toc' on input line 132.
8
- #
9
- # Note: currently fails if lines get broken badly, e.g. in 000.log:634.
10
- class PrefixedMultiLinePattern
11
- include RegExpPattern
12
-
13
- def initialize
14
- super(/(Package|Class|\w+TeX)\s+(?:(\w+)\s+)?(Warning|Error|Info|Message)/,
15
- { pattern: ->(m) { /^\s*\(#{m[2]}\)/ }, # BROKEN_BY_LINEBREAKS
16
- until: :mismatch,
17
- inclusive: false })
18
- end
19
-
20
- def read(lines)
21
- # @type [LogMessage] msg
22
- # @type [Int] consumed
23
- msg, consumed = super(lines)
24
-
25
- case @start_match[3]
26
- when 'Error'
27
- msg.level = :error
28
- when 'Warning'
29
- msg.level = :warning
30
- when 'Info', 'Message'
31
- msg.level = :info
32
- else
33
- # TODO: abort?
34
- Logger.debug 'Unhandled message type!'
3
+ class TexLogParser
4
+ # Matches messages of this form:
5
+ #
6
+ # Package tocbasic Info: omitting babel extension for `toc'
7
+ # (tocbasic) because of feature `nobabel' available
8
+ # (tocbasic) for `toc' on input line 132.
9
+ #
10
+ # Note: currently fails if lines get broken badly, e.g. in 000.log:634.
11
+ class PrefixedMultiLinePattern
12
+ include LogParser::RegExpPattern
13
+
14
+ # Creates a new instance.
15
+ def initialize
16
+ super(/(Package|Class|\w+TeX)\s+(?:(\w+)\s+)?(Warning|Error|Info|Message)/,
17
+ { pattern: ->(m) { /^\s*\(#{m[2]}\)/ }, # BROKEN_BY_LINEBREAKS
18
+ until: :mismatch,
19
+ inclusive: false })
35
20
  end
36
21
 
37
- # source file from scope, parser does it
38
-
39
- # BROKEN_BY_LINEBREAKS
40
- # TODO: may be split across lines --> remove whitespace before extracting
41
- suffix_match = /on input line\s+(\d+)(?:\.\s*)?\z/.match(msg.message)
42
- unless suffix_match.nil?
43
- line = suffix_match[1].to_i
44
- msg.source_lines = { from: line, to: line }
22
+ # (see LogParser::RegExpPattern#read)
23
+ def read(lines)
24
+ # @type [Message] msg
25
+ # @type [Int] consumed
26
+ msg, consumed = super(lines)
27
+
28
+ case @start_match[3]
29
+ when 'Error'
30
+ msg.level = :error
31
+ when 'Warning'
32
+ msg.level = :warning
33
+ when 'Info', 'Message'
34
+ msg.level = :info
35
+ else
36
+ # TODO: abort?
37
+ Logger.debug 'Unhandled message type!'
38
+ end
39
+
40
+ # source file from scope, parser does it
41
+
42
+ # BROKEN_BY_LINEBREAKS
43
+ # TODO: may be split across lines --> remove whitespace before extracting
44
+ suffix_match = /on input line\s+(\d+)(?:\.\s*)?\z/.match(msg.message)
45
+ unless suffix_match.nil?
46
+ line = suffix_match[1].to_i
47
+ msg.source_lines = { from: line, to: line }
48
+ end
49
+
50
+ # TODO: message itself contains useless line prefixes --> remove, preformatted = false
51
+
52
+ [msg, consumed]
45
53
  end
46
-
47
- # TODO: message itself contains useless line prefixes --> remove, preformatted = false
48
-
49
- [msg, consumed]
50
54
  end
51
55
  end
@@ -1,24 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Matches messages of this form:
4
- #
5
- # Runaway argument?
6
- # {Test. Also, it contains some \ref {warnings} and \ref {errors} for t\ETC.
7
- class RunawayParameterError
8
- include RegExpPattern
3
+ class TexLogParser
4
+ # Matches messages of this form:
5
+ #
6
+ # Runaway argument?
7
+ # {Test. Also, it contains some \ref {warnings} and \ref {errors} for t\ETC.
8
+ class RunawayParameterError
9
+ include LogParser::RegExpPattern
9
10
 
10
- def initialize
11
- super(/^Runaway argument\?/,
12
- { pattern: ->(_) { /./ }, until: :match, inclusive: true }
13
- )
14
- end
11
+ # Creates a new instance.
12
+ def initialize
13
+ super(/^Runaway argument\?/,
14
+ { pattern: ->(_) { /./ }, until: :match, inclusive: true }
15
+ )
16
+ end
15
17
 
16
- def read(lines)
17
- # @type [LogMessage] msg
18
- msg, consumed = super(lines)
18
+ # (see LogParser::RegExpPattern#read)
19
+ def read(lines)
20
+ # @type [Message] msg
21
+ msg, consumed = super(lines)
19
22
 
20
- msg.level = :error
23
+ msg.level = :error
21
24
 
22
- [msg, consumed]
25
+ [msg, consumed]
26
+ end
23
27
  end
24
- end
28
+ end
@@ -1,44 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Matches messages of this form:
4
- #
5
- # ! File ended while scanning use of \@footnotetext.
6
- # <inserted text>
7
- # \par
8
- # <*> plain.tex
9
- #
10
- # and
11
- #
12
- # ! Font TU/NoSuchFont(0)/m/n/9=NoSuchFont at 9.0pt not loadable: Metric (TFM) fi
13
- # le or installed font not found.
14
- # <to be read again>
15
- # relax
16
- # l.40 \end{document}
17
- class StandardError
18
- include RegExpPattern
3
+ class TexLogParser
4
+ # Matches messages of this form:
5
+ #
6
+ # ! File ended while scanning use of \@footnotetext.
7
+ # <inserted text>
8
+ # \par
9
+ # <*> plain.tex
10
+ #
11
+ # and
12
+ #
13
+ # ! Font TU/NoSuchFont(0)/m/n/9=NoSuchFont at 9.0pt not loadable: Metric (TFM) fi
14
+ # le or installed font not found.
15
+ # <to be read again>
16
+ # relax
17
+ # l.40 \end{document}
18
+ class StandardError
19
+ include LogParser::RegExpPattern
19
20
 
20
- def initialize
21
- super(/^\! \w+/,
22
- { pattern: ->(_) { /^\s*<\*>\s+([^\s]+)|^l\.(\d+)\s+/ }, until: :match, inclusive: true }
23
- )
24
- end
21
+ # Creates a new instance.
22
+ def initialize
23
+ super(/^! \w+/,
24
+ { pattern: ->(_) { /^\s*<\*>\s+([^\s]+)|^l\.(\d+)\s+/ }, until: :match, inclusive: true }
25
+ )
26
+ end
25
27
 
26
- def read(lines)
27
- # @type [LogMessage] msg
28
- msg, consumed = super(lines)
28
+ # (see LogParser::RegExpPattern#read)
29
+ def read(lines)
30
+ # @type [Message] msg
31
+ msg, consumed = super(lines)
29
32
 
30
- msg.level = :error
31
- # Remove last line
32
- msg.message.gsub!(@ending[:pattern][nil], '')
33
- msg.message.rstrip!
33
+ msg.level = :error
34
+ # Remove last line
35
+ msg.message.gsub!(@ending[:pattern][nil], '')
36
+ msg.message.rstrip!
34
37
 
35
- file = @end_match[1]
36
- line = @end_match[2].to_i
38
+ file = @end_match[1]
39
+ line = @end_match[2].to_i
37
40
 
38
- msg.source_file = file unless file.nil?
39
- msg.source_lines = { from: line, to: line } unless line.nil? || line.zero?
40
- msg.preformatted = true
41
+ msg.source_file = file unless file.nil?
42
+ msg.source_lines = { from: line, to: line } unless line.nil? || line.zero?
43
+ msg.preformatted = true
41
44
 
42
- [msg, consumed]
45
+ [msg, consumed]
46
+ end
43
47
  end
44
- end
48
+ end
@@ -1,24 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
4
- require 'tex_log_parser/log_buffer'
5
- require 'tex_log_parser/log_message'
6
- require 'tex_log_parser/log_parser'
7
- require 'tex_log_parser/log_pattern'
3
+ require 'log_parser/log_parser'
8
4
  Dir["#{File.expand_path(__dir__)}/tex_log_parser/patterns/*.rb"].each { |p| require p }
9
5
 
10
- # TODO: document
6
+ # Parses logs (and output) of LaTeX interpreters, e.g. `pdflatex`, `xelatex` and `lualatex`.
7
+ #
8
+ # *Note:* Due to shortcomings in the native format of those logs, please be
9
+ # aware of these recommendations:
10
+ # - Use `-file-line-error` if possible; it makes for more robust source file and line reporting.
11
+ # - Ask for log lines to be broken as rarely as possible; see e.g. [here](https://tex.stackexchange.com/q/52988/3213).
12
+ # Search the sources for `BROKEN_BY_LINEBREAKS` to find all the nastiness (and potential issues) you can avoid by that.
11
13
  class TexLogParser
12
14
  include LogParser
13
15
 
14
- def initialize(log, _options = {})
15
- super(log, _options)
16
+ # (see LogParser#initialize)
17
+ def initialize(log)
18
+ super(log)
16
19
 
17
20
  # BROKEN_BY_LINEBREAKS
18
21
  # I'd prefer to have this stateless, but well (see below).
19
22
  @pushed_dummy = false
20
23
  end
21
24
 
25
+ protected
26
+
27
+ # (see LogParser#patterns)
22
28
  def patterns
23
29
  [HighlightedMessages.new,
24
30
  FileLineError.new,
@@ -29,7 +35,22 @@ class TexLogParser
29
35
  BadHboxWarning.new]
30
36
  end
31
37
 
38
+ # (see LogParser#scope_changes)
39
+ #
40
+ # _Implementation note:_ The basic format in LaTeX logs is that
41
+ # * `(filename` marks the beginning of messages from that file, and
42
+ # * the matching `)` marks the end.
43
+ # Those nest, of course.
44
+ #
45
+ # This implementation is mainly concerned with hacking around problems of how this format is implemented in the logs.
46
+ # * Filenames may be broken across lines.
47
+ # * Opening "tags" may or may not appear on a dedicated line.
48
+ # * Closing "tags" may or may not appear on a dedicated line.
49
+ # * Badly line-broken message fragments with parentheses confuse matching heuristics for either.
50
+ # If inopportune line breaks can be avoided, this method is a lot more reliable.
32
51
  def scope_changes(line)
52
+ pushed_dummy = false
53
+
33
54
  result =
34
55
  case line
35
56
  when /^\s*\(([^()]*)\)\s*(.*)$/
@@ -55,7 +76,7 @@ class TexLogParser
55
76
  when /^[^()]*\)/
56
77
  # BROKEN_BY_LINEBREAKS
57
78
  # Badly broken lines may push ) prefixed by non-whitespace. Narf.
58
- [:pop] if @pushed_dummy ? [:pop] : []
79
+ @pushed_dummy ? [:pop] : []
59
80
  else
60
81
  []
61
82
  end
data/lib/version.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @attr [String] VERSION
4
+ # The version of TexLogParser.
5
+ class TexLogParser
6
+ VERSION = '1.0.0.pre.14'
7
+ end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tex_log_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.10
4
+ version: 1.0.0.pre.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Raphael Reitzig
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-07 00:00:00.000000000 Z
11
+ date: 2018-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: github-markup
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: minitest
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,20 @@ dependencies:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: '12.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: redcarpet
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.4'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: yard
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -76,12 +104,12 @@ files:
76
104
  - LICENSE
77
105
  - README.md
78
106
  - bin/texlogparser
79
- - lib/logger.rb
107
+ - lib/log_parser/buffer.rb
108
+ - lib/log_parser/log_parser.rb
109
+ - lib/log_parser/logger.rb
110
+ - lib/log_parser/message.rb
111
+ - lib/log_parser/pattern.rb
80
112
  - lib/tex_log_parser.rb
81
- - lib/tex_log_parser/log_buffer.rb
82
- - lib/tex_log_parser/log_message.rb
83
- - lib/tex_log_parser/log_parser.rb
84
- - lib/tex_log_parser/log_pattern.rb
85
113
  - lib/tex_log_parser/patterns/bad_hbox_warning.rb
86
114
  - lib/tex_log_parser/patterns/fatal_error_occurred.rb
87
115
  - lib/tex_log_parser/patterns/file_line_error.rb
@@ -89,7 +117,7 @@ files:
89
117
  - lib/tex_log_parser/patterns/prefixed_multi_line_pattern.rb
90
118
  - lib/tex_log_parser/patterns/runaway_parameter_error.rb
91
119
  - lib/tex_log_parser/patterns/standard_error.rb
92
- - lib/tex_log_parser/version.rb
120
+ - lib/version.rb
93
121
  homepage: http://github.com/reitzig/texlogparser
94
122
  licenses:
95
123
  - MIT
@@ -111,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
139
  version: 1.3.1
112
140
  requirements: []
113
141
  rubyforge_project:
114
- rubygems_version: 2.5.2.1
142
+ rubygems_version: 2.7.6
115
143
  signing_key:
116
144
  specification_version: 4
117
145
  summary: Parses log files of (La)TeX engines
data/lib/logger.rb DELETED
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # A simple helper, probably to be replaced by a proper logging library
4
- # at some point.
5
- #
6
- # @attr [true,false] debug
7
- class Logger
8
- class << self
9
- attr_accessor :debugging
10
-
11
- def debug?
12
- debugging || !ENV['DEBUG'].nil?
13
- end
14
-
15
- # Logs the given message to STDOUT if `debug` is true.
16
- # @param [String] message
17
- def debug(message)
18
- puts message if debug?
19
- end
20
- end
21
- end
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class LogBuffer
4
- # @param [Array<String>,IO] log
5
- def initialize(log)
6
- @buffer = []
7
- @stream = nil
8
-
9
- @buffer = log if log.is_a?(Array)
10
- @stream = log if log.is_a?(IO) || log.is_a?(StringIO)
11
- end
12
-
13
- def empty?
14
- @buffer.empty? && stream_is_done?
15
- end
16
-
17
- def buffer_size
18
- @buffer.size
19
- end
20
-
21
- def first
22
- self[0]
23
- end
24
-
25
- def find_index(starting_from = 0)
26
- index = starting_from
27
- element = self[index]
28
-
29
- until element.nil?
30
- return index if yield(element)
31
- index += 1
32
- element = self[index]
33
- end
34
-
35
- nil
36
- end
37
-
38
- def [](offset, length = nil)
39
- base_length = length || 1
40
- while offset + base_length > @buffer.size
41
- return (length.nil? ? nil : @buffer[offset, @buffer.size]) if stream_is_done?
42
- @buffer.push(@stream.readline.rstrip)
43
- end
44
-
45
- length.nil? ? @buffer[offset] : @buffer[offset, length]
46
- end
47
-
48
- def forward(offset = 1)
49
- self[offset]
50
- @buffer.slice!(0, offset)
51
- end
52
-
53
- def close
54
- @stream.close unless @stream.nil? || @stream.closed?
55
- end
56
-
57
- private
58
-
59
- def stream_is_done?
60
- @stream.nil? || @stream.closed? || @stream.eof?
61
- end
62
- end