tex_log_parser 1.0.0.pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4278834a923e4825ac4e56bcd07e6b7eeb681643
4
+ data.tar.gz: 38810767f39844e7ec8eac3b78a445f8ebdbf68c
5
+ SHA512:
6
+ metadata.gz: 701b97b4ab74385a29286fbb30055296ee417881f636f00638d692ece7b74a4fa47b3e68a567c22c403279709240abcd4fad45df80f82d4c6be95fa4a643ab2d
7
+ data.tar.gz: 0aaa4a74adb27548e8e2487bbf2b3a8782481eb4cce192098b549e250ab39a4bb142ead0796eac745f5f940a3d90ee030274773d853ee7159cb940aad1a4f792
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Raphael R.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,6 @@
1
+ # TeXLogParser
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/texlogparser.svg)](https://rubygems.org/gems/texlogparser)
4
+ [![Travis build status](https://api.travis-ci.org/reitzig/texlogparser.svg?branch=master)](https://travis-ci.org/reitzig/texlogparser)
5
+
6
+ TODO write
data/bin/texlogparser ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tex_log_parser'
4
+
5
+ # TODO read stdin, parse, write default format (file-line? json?) to stdout
6
+ # TODO options for output format?
@@ -0,0 +1,32 @@
1
+ # @attr [String] message
2
+ # @attr [String,nil] source_file
3
+ # @attr [Hash<Symbol, Int>,nil] source_lines
4
+ # @attr [Hash<Symbol, Int>,nil] log_lines
5
+ # @attr [true,false] preformatted
6
+ # @attr [:error,:warning,:info,:debug] level
7
+ class LogMessage
8
+ def initialize(message:, source_file: nil, source_lines: nil, log_lines: nil, preformatted: false, level: :info)
9
+ @message = message
10
+ @source_file = source_file
11
+ @source_lines = source_lines
12
+ @log_lines = log_lines
13
+ @preformatted = preformatted
14
+ @level = level
15
+ end
16
+
17
+ attr_accessor :message, :source_file, :source_lines, :log_lines,
18
+ :preformatted, :level
19
+
20
+ def to_s
21
+ lines = if @source_lines.nil?
22
+ ""
23
+ else
24
+ # @type [Hash<Symbol, Int>] @source_lines
25
+ @source_lines.values.join("-")
26
+ end
27
+ <<~MSG
28
+ #{@source_file}:#{lines} #{@level.to_s.capitalize}
29
+ #{@message}
30
+ MSG
31
+ end
32
+ end
@@ -0,0 +1,74 @@
1
+ # TODO: document
2
+ module LogParser
3
+ def initialize
4
+ @files = []
5
+ end
6
+
7
+ # @return [Array<LogPattern>]
8
+ def patterns
9
+ raise NotImplementedError
10
+ end
11
+
12
+ # @param [String] line
13
+ # @return [Array<String,:pop>] A list of new scopes this line enters (strings)
14
+ # and leaves (`:pop`).
15
+ # Read stack operations from left to right.
16
+ def scope_changes(line)
17
+ raise NotImplementedError
18
+ end
19
+
20
+ # TODO: document
21
+ # @param [Array<String>] log_lines
22
+ # @return [Array<LogMessage>]
23
+ def parse(log_lines)
24
+ messages = []
25
+
26
+ log_line_number = 1
27
+ until log_lines.empty?
28
+ line = log_lines.first
29
+
30
+ if line.strip.empty?
31
+ consumed_lines = 1
32
+ else
33
+ # Use the first pattern that matches. Let's hope that's a good heuristic.
34
+ # If not, we'll have to let all competitors consume and see who wins --
35
+ # which we'd decide how?
36
+ matching_pattern = patterns.detect { |p| p.begins_at?(line) }
37
+
38
+ if matching_pattern.nil?
39
+ # In the hope that scope changes happen not on the same
40
+ # line as messages. Gulp.
41
+ scope_changes(log_lines.first).each { |op|
42
+ if op == :pop
43
+ left = @files.pop
44
+ #puts "Finished file #{left.nil? ? "nil" : left}" # TODO: debug mode
45
+ left
46
+ else
47
+ #puts "Entered file #{op}" # TODO: debug mode
48
+ @files.push(op)
49
+ end
50
+ }
51
+
52
+ # Try again with the next line
53
+ consumed_lines = 1
54
+ else
55
+ # Apply the pattern, i.e. read the next message!
56
+ # @type [LogMessage] message
57
+ message, consumed_lines = matching_pattern.read(log_lines)
58
+ message.log_lines = { from: log_line_number,
59
+ to: log_line_number + consumed_lines - 1 }
60
+ message.source_file ||= @files.last
61
+
62
+ messages.push(message)
63
+ end
64
+ end
65
+
66
+ # Forward the window
67
+ log_lines.slice!(0, consumed_lines)
68
+ log_line_number += consumed_lines
69
+ end
70
+
71
+ #puts "Filestack: #{@files}" # TODO: debug mode
72
+ messages
73
+ end
74
+ end
@@ -0,0 +1,65 @@
1
+ require "#{File.expand_path(__dir__)}/log_message.rb"
2
+
3
+ # TODO: Document
4
+ module LogPattern
5
+ # TODO: Document
6
+ # @param [String] line
7
+ # @return [true,false]
8
+ def begins_at?(line)
9
+ raise NotImplementedError
10
+ end
11
+
12
+ # TODO: Document
13
+ # @param [Array<String>] lines
14
+ # @return [Array<(LogMessage, Int)>]
15
+ def read(lines)
16
+ raise NotImplementedError
17
+ end
18
+ end
19
+
20
+ # TODO: document
21
+ # @attr [Regexp] start
22
+ # @attr [MatchData] start_match
23
+ # @attr [Regexp] ending
24
+ module RegExpPattern
25
+ include LogPattern
26
+
27
+ # @param [Regexp] start
28
+ # @param [Hash] ending
29
+ # @option ending [Regexp] :pattern
30
+ # @option ending [:match,:mismatch] :until
31
+ # @option ending [true,false] :inclusive
32
+ def initialize(start, ending = { pattern: ->(_) { /^\s+$/ },
33
+ until: :match,
34
+ inclusive: false })
35
+ @start = start
36
+ @ending = ending
37
+ end
38
+
39
+ # TODO: document
40
+ def begins_at?(line)
41
+ match = @start.match(line)
42
+ @start_match = match unless match.nil?
43
+ !match.nil?
44
+ end
45
+
46
+ # TODO: document
47
+ def ends_at?(line)
48
+ match = !(@ending[:pattern][@start_match] =~ line).nil?
49
+ match == (@ending[:until] == :match)
50
+ end
51
+
52
+ # TODO make failable (e.g. EOF)
53
+ # @param [Array<String>] lines
54
+ # @return [Array<(LogMessage, Int)>]
55
+ def read(lines) # TODO: How useful is this? Not very, I'm afraid... there should be functions for source file, line, and level?
56
+ raise NotImplementedError if @ending.nil?
57
+
58
+ ending = lines[1, lines.size].find_index { |l| ends_at?(l) }
59
+ ending += 1 if @ending[:inclusive]
60
+
61
+ # Use ending+1 since ending is the index when we drop the first line!
62
+ msg = LogMessage.new(message: lines[0, ending+1].join, preformatted: false, level: nil)
63
+ [msg, ending + 1]
64
+ end
65
+ end
@@ -0,0 +1,8 @@
1
+ require "#{File.expand_path(__dir__)}/../log_pattern"
2
+
3
+ # TODO: document
4
+ class BadHboxWarning
5
+ include RegExpPattern
6
+
7
+ # TODO: implement
8
+ end
@@ -0,0 +1,27 @@
1
+ require "#{File.expand_path(__dir__)}/../log_pattern"
2
+
3
+ # Matches messages of this form:
4
+ #
5
+ # ./plain.tex:31: Undefined control sequence.
6
+ # l.31 ...t contains some \ref{warnings} and \errors
7
+ # for testing.
8
+ class FileLineError
9
+ include RegExpPattern
10
+
11
+ def initialize
12
+ super(/^(\/?(?:.*?\/)*[^\/]+):(\d+):/)
13
+ end
14
+
15
+ def read(lines)
16
+ # @type [LogMessage] msg
17
+ msg, consumed = super(lines)
18
+
19
+ msg.source_file = @start_match[1]
20
+ line = @start_match[2].to_i
21
+ msg.source_lines = { from: line, to: line}
22
+ msg.preformatted = true
23
+ msg.level = :error
24
+
25
+ [msg, consumed]
26
+ end
27
+ end
@@ -0,0 +1,8 @@
1
+ require "#{File.expand_path(__dir__)}/../log_pattern"
2
+
3
+ # TODO: document
4
+ class FontspecError
5
+ include RegExpPattern
6
+
7
+ # TODO: implement
8
+ end
@@ -0,0 +1,51 @@
1
+ require "#{File.expand_path(__dir__)}/../log_pattern"
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
+ # TODO: debug output
35
+ end
36
+
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 }
45
+ end
46
+
47
+ # TODO: message itself contains useless line prefixes --> remove
48
+
49
+ [msg, consumed]
50
+ end
51
+ end
@@ -0,0 +1,8 @@
1
+ require "#{File.expand_path(__dir__)}/../log_pattern"
2
+
3
+ # TODO: document
4
+ class RunawayParameterError
5
+ include RegExpPattern
6
+
7
+ # TODO: implement
8
+ end
@@ -0,0 +1,41 @@
1
+ require 'tex_log_parser/log_parser'
2
+ Dir["#{File.expand_path(__dir__)}/tex_log_parser/patterns/*.rb"].each { |p| require p }
3
+
4
+ # TODO: document
5
+ class TexLogParser
6
+ include LogParser
7
+
8
+ def patterns
9
+ [FileLineError.new, PrefixedMultiLinePattern.new]
10
+ end
11
+
12
+ def scope_changes(line)
13
+ ops = case line
14
+ when /^\s*\(([^()]*)\)\s+(.*)$/
15
+ # A scope opened and closed immediately -- log it, then
16
+ # continue with rest of the line (there can be multiple such
17
+ # things in one line, see e.g. 000.log:656)
18
+ [$1, :pop] + ($2.strip.empty? ? [] : scope_changes($2))
19
+ when /^\s*\(([^()]+?)\s*$/
20
+ # A scope opened and will be closed later.
21
+ # Happens on a dedicated line
22
+ [$1]
23
+ when /^\s*(\)+)(.*)$/
24
+ # Scopes close on a dedicated line, except if they don't (cf 000.log:624)
25
+ # So we have to continue on the rest of the line. Uh oh.
26
+ ([:pop] * $1.length) + scope_changes($2)
27
+ when /\([^)]*$/
28
+ # BROKEN_BY_LINEBREAKS
29
+ # Bad linebreaks can cause trailing ) to spill over. Narf.
30
+ # e.g. 000.log:502-503
31
+ ["dummy"] # Compensate the bad pop that will happen next line.
32
+ else
33
+ []
34
+ end
35
+
36
+ # puts line # TODO: debug mode
37
+ # puts ops.to_s
38
+ # puts ""
39
+ ops
40
+ end
41
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tex_log_parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.pre.1
5
+ platform: ruby
6
+ authors:
7
+ - Raphael Reitzig
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-03-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Parses log files of (La)TeX engines
56
+ email: 4246780+reitzig@users.noreply.github.com
57
+ executables:
58
+ - texlogparser
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - LICENSE
63
+ - README.md
64
+ - bin/texlogparser
65
+ - lib/tex_log_parser.rb
66
+ - lib/tex_log_parser/log_message.rb
67
+ - lib/tex_log_parser/log_parser.rb
68
+ - lib/tex_log_parser/log_pattern.rb
69
+ - lib/tex_log_parser/patterns/bad_hbox_warning.rb
70
+ - lib/tex_log_parser/patterns/file_line_error.rb
71
+ - lib/tex_log_parser/patterns/fontspec_error.rb
72
+ - lib/tex_log_parser/patterns/prefixed_multi_line_pattern.rb
73
+ - lib/tex_log_parser/patterns/runaway_parameter_error.rb
74
+ homepage: http://github.com/reitzig/texlogparser
75
+ licenses:
76
+ - MIT
77
+ metadata:
78
+ yard.run: yri
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: 2.3.0
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">"
91
+ - !ruby/object:Gem::Version
92
+ version: 1.3.1
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.5.2.1
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Parses log files of (La)TeX engines
99
+ test_files: []