tex_log_parser 1.0.0.pre.2 → 1.0.0.pre.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 062e87fb6cd767aacf4df4306f06812861c0f435
4
- data.tar.gz: 36c8a772c8a16b79b112288a4673603050b181d2
3
+ metadata.gz: 1771cd7fe895030d25eb1487e9af597b0617e5ff
4
+ data.tar.gz: acb8d3e74d985533efd9e45b613dfcf086aaf75d
5
5
  SHA512:
6
- metadata.gz: d2dbe0b0507532726115f4c45652ba3d5d642db99ff43e9298a628f2fc3891d6e0b97e0fe4226cb91d1c81f8afa32be6bfc38093b2a6bb897edb6356e61eeb8f
7
- data.tar.gz: 1251c33e7e6803f91f309b8d5920febfb45e6d0e4a14eb9c24bbaea5aa83a47f2fe290ae0d7d1b97e59d81170fc54ff71d35f7309c8741ba27afd9adb2cc7c03
6
+ metadata.gz: 740853668e14c12939f5284030a9adce6cc43e3eca3db4f837a3220d01a31734adaed14e87379fd16962472337c67a0148f38642f444672e7d4c40f84ead69b4
7
+ data.tar.gz: c47346069d27184a711e51b66c63ac9a2c55f622f08f1b227173baa4808571909eafddddfab3c4493f338b8dab2be9068b3b9f939b69aba076f8972d4b32b6a4
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # TeXLogParser
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/tex_log_parser.svg)](https://badge.fury.io/rb/tex_log_parser)
4
- [![Yard docs](http://img.shields.io/badge/yard-docs-green.svg)](http://www.rubydoc.info/gems/tex_log_parser/1.0.0.pre.1) **˙**
4
+ [![Yard docs](http://img.shields.io/badge/yard-docs-green.svg)](http://www.rubydoc.info/gems/tex_log_parser/1.0.0.pre.2) **˙**
5
5
  [![Maintainability](https://api.codeclimate.com/v1/badges/748992a2c5f6570797d4/maintainability)](https://codeclimate.com/github/reitzig/texlogparser/maintainability)
6
6
  [![Test Coverage](https://api.codeclimate.com/v1/badges/748992a2c5f6570797d4/test_coverage)](https://codeclimate.com/github/reitzig/texlogparser/test_coverage) **˙**
7
7
  [![Travis build status](https://api.travis-ci.org/reitzig/texlogparser.svg?branch=master)](https://travis-ci.org/reitzig/texlogparser)
data/bin/texlogparser CHANGED
@@ -1,29 +1,26 @@
1
1
  #!/usr/bin/env ruby
2
-
3
- if $PROGRAM_NAME == __FILE__
4
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
5
- end
2
+ # frozen_string_literal: true
6
3
 
7
4
  require 'tex_log_parser'
5
+ require 'tex_log_parser/version'
8
6
  require 'optparse'
9
7
  require 'json'
10
8
 
11
9
  # Defaults
12
10
  options = {
13
- debug: false,
14
11
  format: :file_line,
15
12
  input: STDIN,
16
13
  output: STDOUT
17
14
  }
18
- formats = [:file_line, :json]
15
+ formats = %i[file_line json]
19
16
 
20
17
  OptionParser.new do |opts|
21
18
  opts.banner = 'Usage: texlogparser [options]'
22
19
  opts.on('-d', '--debug', 'Output debug information') do
23
- options[:debug] = true
20
+ Logger.debugging = true
24
21
  end
25
22
  opts.on('-f ENUM', '--format ENUM', formats,
26
- 'Output format', "One of: #{formats.map { |e| e.to_s }.join(", ")}") do |format|
23
+ 'Output format', "One of: #{formats.map(&:to_s).join(', ')}") do |format|
27
24
  options[:format] = format
28
25
  end
29
26
  opts.on('-i', '--input PATH', 'Read input from PATH') do |path|
@@ -48,7 +45,7 @@ OptionParser.new do |opts|
48
45
 
49
46
  begin
50
47
  opts.parse!
51
- rescue => e
48
+ rescue StandardError => e
52
49
  STDERR.puts e
53
50
  exit 1
54
51
  end
@@ -68,8 +65,9 @@ output = STDOUT
68
65
  output = File.open(options[:output], 'w') if options[:output].is_a?(String)
69
66
  case options[:format]
70
67
  when :file_line
71
- output.write(messages.map { |m| m.to_s }.join("\n\n"))
68
+ output.write(messages.map(&:to_s).join("\n\n"))
69
+ # TODO: print summary?
72
70
  when :json
73
71
  output.write(JSON.pretty_generate(messages))
74
72
  end
75
- output.close
73
+ output.close
data/lib/logger.rb ADDED
@@ -0,0 +1,17 @@
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
+ # Logs the given message to STDOUT if `debug` is true.
12
+ # @param [String] message
13
+ def debug(message)
14
+ puts message if debugging || !ENV['DEBUG'].nil?
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class LogBuffer
2
4
  # @param [Array<String>,IO] log
3
5
  def initialize(log)
@@ -12,6 +14,10 @@ class LogBuffer
12
14
  @buffer.empty? && stream_is_done?
13
15
  end
14
16
 
17
+ def buffer_size
18
+ @buffer.size
19
+ end
20
+
15
21
  def first
16
22
  self[0]
17
23
  end
@@ -53,4 +59,4 @@ class LogBuffer
53
59
  def stream_is_done?
54
60
  @stream.nil? || @stream.closed? || @stream.eof?
55
61
  end
56
- end
62
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json'
2
4
 
3
5
  # @attr [String] message
@@ -17,8 +19,6 @@ class LogMessage
17
19
  @preformatted = preformatted
18
20
  @level = level
19
21
  @pattern = pattern
20
-
21
- @debug = false # TODO: get option here
22
22
  end
23
23
 
24
24
  attr_accessor :message, :source_file, :source_lines, :log_lines,
@@ -33,8 +33,8 @@ class LogMessage
33
33
  end
34
34
 
35
35
  message = @message
36
- message = message.split("\n").map {|l| l.strip }.join("") unless @preformatted
37
- message += "\nLog pattern: '#{@pattern}'" if @debug
36
+ message = message.split("\n").map(&:strip).join(' ') unless @preformatted
37
+ message += "\nLog pattern: '#{@pattern}'" if Logger.debugging
38
38
 
39
39
  <<~MSG
40
40
  #{@source_file}#{lines}: #{@level.to_s.upcase}
@@ -42,15 +42,16 @@ class LogMessage
42
42
  MSG
43
43
  end
44
44
 
45
- def to_json(options={})
45
+ def to_json(_options = {})
46
46
  hash = {
47
- level: @level,
48
- source_file: @source_file,
49
- source_lines: @source_lines,
50
- message: @message,
51
- log_lines: @log_lines,
52
- preformatted: @preformatted
47
+ level: @level,
48
+ source_file: @source_file,
49
+ source_lines: @source_lines,
50
+ message: @message,
51
+ log_lines: @log_lines,
52
+ preformatted: @preformatted
53
53
  }
54
+ hash[:pattern] = @pattern if Logger.debugging
54
55
  JSON.pretty_generate hash
55
56
  end
56
- end
57
+ end
@@ -1,4 +1,4 @@
1
- require "#{File.expand_path(__dir__)}/log_buffer.rb"
1
+ # frozen_string_literal: true
2
2
 
3
3
  # TODO: document
4
4
  module LogParser
@@ -6,17 +6,15 @@ module LogParser
6
6
 
7
7
  # TODO: document
8
8
  # @param [Array<String>,IO,StringIO] log
9
- # @param [Hash] options
10
- def initialize(log, options)
9
+ # @param [Hash] _options
10
+ def initialize(log, _options = {})
11
11
  @files = []
12
12
 
13
13
  @messages = []
14
- @log_line_number = 0
14
+ @log_line_number = 1
15
15
  @lines = LogBuffer.new(log)
16
16
 
17
- @debug = options.fetch(:debug, false)
18
-
19
- puts "Parsing from '#{log}'" if @debug
17
+ Logger.debug "Parsing from '#{log}'"
20
18
  end
21
19
 
22
20
  # @return [Array<LogPattern>]
@@ -24,72 +22,92 @@ module LogParser
24
22
  raise NotImplementedError
25
23
  end
26
24
 
27
- # @param [String] line
25
+ # @param [String] _line
28
26
  # @return [Array<String,:pop>] A list of new scopes this line enters (strings)
29
27
  # and leaves (`:pop`).
30
28
  # Read stack operations from left to right.
31
- def scope_changes(line)
29
+ def scope_changes(_line)
32
30
  raise NotImplementedError
33
31
  end
34
32
 
33
+ def empty?
34
+ @lines.empty?
35
+ end
36
+
35
37
  # TODO: document
36
38
  # @return [Array<LogMessage>]
37
39
  def parse
38
- raise 'Parser already ran!' unless @log_line_number.zero?
40
+ skip_empty_lines
41
+ until empty?
42
+ parse_next_lines
43
+ skip_empty_lines
44
+ end
39
45
 
40
- @log_line_number = 1
41
- until @lines.empty?
42
- line = @lines.first
46
+ @messages
47
+ end
43
48
 
44
- if line.strip.empty?
45
- remove_consumed_lines 1
46
- next
47
- end
49
+ private
48
50
 
49
- puts "\nLine: '#{line.strip}'" if @debug
51
+ def skip_empty_lines
52
+ @lines.first
50
53
 
51
- # Use the first pattern that matches. Let's hope that's a good heuristic.
52
- # If not, we'll have to let all competitors consume and see who wins --
53
- # which we'd decide how?
54
- matching_pattern = patterns.detect { |p| p.begins_at?(line) }
54
+ first_nonempty_line = @lines.find_index { |line| /[^\s]/ =~ line }
55
+ remove_consumed_lines(first_nonempty_line || @lines.buffer_size)
56
+ end
55
57
 
56
- if matching_pattern.nil?
57
- puts '- No pattern matches' if @debug
58
- apply_scope_changes
59
- else
60
- puts "- Matched pattern: '#{matching_pattern.class}'" if @debug
61
- consume_pattern(matching_pattern)
62
- end
58
+ # TODO: document
59
+ # @return [LogMessage,nil]
60
+ def parse_next_lines
61
+ raise 'Parse already done!' if @lines.empty?
62
+
63
+ line = @lines.first
64
+ Logger.debug "\nLine: '#{line.strip}'"
65
+ msg = nil
66
+
67
+ # Use the first pattern that matches. Let's hope that's a good heuristic.
68
+ # If not, we'll have to let all competitors consume and see who wins --
69
+ # which we'd decide how?
70
+ matching_pattern = patterns.detect { |p| p.begins_at?(line) }
71
+
72
+ if matching_pattern.nil?
73
+ Logger.debug '- No pattern matches'
74
+ apply_scope_changes
75
+ else
76
+ Logger.debug "- Matched pattern: '#{matching_pattern.class}'"
77
+ msg = consume_pattern(matching_pattern)
78
+ @messages.push(msg) unless msg.nil?
63
79
  end
64
80
 
65
- puts "\nFiles that did not close: #{@files}" if @debug
66
- @lines.close
67
- messages
68
- end
81
+ if @lines.empty?
82
+ @lines.close
83
+ Logger.debug "\nFiles that did not close: #{@files}"
84
+ end
69
85
 
70
- private
86
+ msg
87
+ end
71
88
 
72
89
  def remove_consumed_lines(i)
73
90
  @lines.forward(i)
74
91
  @log_line_number += i
75
92
  end
76
93
 
94
+ # @return [LogMessage,nil]
77
95
  def consume_pattern(pattern)
78
96
  # Apply the pattern, i.e. read the next message!
79
- begin
80
- # @type [LogMessage] message
81
- message, consumed_lines = pattern.read(@lines)
82
- message.log_lines = { from: @log_line_number,
83
- to: @log_line_number + consumed_lines - 1 }
84
- message.source_file ||= @files.last
85
-
86
- puts message if @debug
87
- @messages.push(message)
88
- remove_consumed_lines consumed_lines
89
- rescue => e
90
- puts "#{e}" if @debug
91
- remove_consumed_lines 1
92
- end
97
+
98
+ # @type [LogMessage] message
99
+ message, consumed_lines = pattern.read(@lines)
100
+ message.log_lines = { from: @log_line_number,
101
+ to: @log_line_number + consumed_lines - 1 }
102
+ message.source_file ||= @files.last
103
+
104
+ Logger.debug message
105
+ remove_consumed_lines consumed_lines
106
+ return message
107
+ rescue StandardError => e
108
+ Logger.debug e.to_s
109
+ remove_consumed_lines 1
110
+ return nil
93
111
  end
94
112
 
95
113
  def apply_scope_changes
@@ -98,13 +116,13 @@ module LogParser
98
116
  scope_changes(@lines.first).each do |op|
99
117
  if op == :pop
100
118
  left = @files.pop
101
- puts "- Finished source file: '#{left.nil? ? 'nil' : left}'" if @debug
119
+ Logger.debug "- Finished source file: '#{left.nil? ? 'nil' : left}'"
102
120
  else # op is file name
103
- puts "- Entered source file: '#{op}'" if @debug
121
+ Logger.debug "- Entered source file: '#{op}'"
104
122
  @files.push(op)
105
123
  end
106
124
  end
107
125
 
108
126
  remove_consumed_lines 1
109
127
  end
110
- end
128
+ end
@@ -1,18 +1,18 @@
1
- require "#{File.expand_path(__dir__)}/log_message.rb"
1
+ # frozen_string_literal: true
2
2
 
3
3
  # TODO: Document
4
4
  module LogPattern
5
5
  # TODO: Document
6
- # @param [String] line
6
+ # @param [String] _line
7
7
  # @return [true,false]
8
- def begins_at?(line)
8
+ def begins_at?(_line)
9
9
  raise NotImplementedError
10
10
  end
11
11
 
12
12
  # TODO: Document
13
- # @param [Array<String>] lines
13
+ # @param [Array<String>] _lines
14
14
  # @return [Array<(LogMessage, Int)>]
15
- def read(lines)
15
+ def read(_lines)
16
16
  raise NotImplementedError
17
17
  end
18
18
  end
@@ -34,7 +34,7 @@ module RegExpPattern
34
34
  inclusive: false })
35
35
  @start = start
36
36
  @ending = ending
37
- @debug = false # TODO: Get the option here
37
+ @ending = ending
38
38
  end
39
39
 
40
40
  # TODO: document
@@ -50,7 +50,7 @@ module RegExpPattern
50
50
  match == (@ending[:until] == :match)
51
51
  end
52
52
 
53
- # TODO make failable (e.g. EOF)
53
+ # TODO: make failable (e.g. EOF)
54
54
  # @param [LogBuffer] lines
55
55
  # @return [Array<(LogMessage, Int)>]
56
56
  def read(lines)
@@ -61,7 +61,8 @@ module RegExpPattern
61
61
  ending -= 1 unless @ending[:inclusive]
62
62
 
63
63
  # Use ending+1 since ending is the index when we drop the first line!
64
- msg = LogMessage.new(message: lines[0, ending + 1].join("\n"), preformatted: true, level: nil)
64
+ msg = LogMessage.new(message: lines[0, ending + 1].join("\n"),
65
+ preformatted: true, level: nil, pattern: self.class)
65
66
  [msg, ending + 1]
66
67
  end
67
- end
68
+ end
@@ -1,8 +1,8 @@
1
- require "#{File.expand_path(__dir__)}/../log_pattern"
1
+ # frozen_string_literal: true
2
2
 
3
3
  # TODO: document
4
4
  class BadHboxWarning
5
5
  include RegExpPattern
6
6
 
7
7
  # TODO: implement
8
- end
8
+ end
@@ -1,4 +1,4 @@
1
- require "#{File.expand_path(__dir__)}/../log_pattern"
1
+ # frozen_string_literal: true
2
2
 
3
3
  # Matches messages of this form:
4
4
  #
@@ -9,7 +9,7 @@ class FileLineError
9
9
  include RegExpPattern
10
10
 
11
11
  def initialize
12
- super(/^(\/?(?:.*?\/)*[^\/]+):(\d+):/)
12
+ super(%r{^(/?(?:.*?/)*[^/]+):(\d+):})
13
13
  end
14
14
 
15
15
  def read(lines)
@@ -18,10 +18,10 @@ class FileLineError
18
18
 
19
19
  msg.source_file = @start_match[1]
20
20
  line = @start_match[2].to_i
21
- msg.source_lines = { from: line, to: line}
21
+ msg.source_lines = { from: line, to: line }
22
22
  msg.preformatted = true
23
23
  msg.level = :error
24
24
 
25
25
  [msg, consumed]
26
26
  end
27
- end
27
+ end
@@ -1,8 +1,8 @@
1
- require "#{File.expand_path(__dir__)}/../log_pattern"
1
+ # frozen_string_literal: true
2
2
 
3
3
  # TODO: document
4
4
  class FontspecError
5
5
  include RegExpPattern
6
6
 
7
7
  # TODO: implement
8
- end
8
+ end
@@ -1,4 +1,4 @@
1
- require "#{File.expand_path(__dir__)}/../log_pattern"
1
+ # frozen_string_literal: true
2
2
 
3
3
  # Matches messages of this form:
4
4
  #
@@ -31,7 +31,7 @@ class PrefixedMultiLinePattern
31
31
  msg.level = :info
32
32
  else
33
33
  # TODO: abort?
34
- # TODO: debug output
34
+ Logger.debug 'Unhandled message type!'
35
35
  end
36
36
 
37
37
  # source file from scope, parser does it
@@ -48,4 +48,4 @@ class PrefixedMultiLinePattern
48
48
 
49
49
  [msg, consumed]
50
50
  end
51
- end
51
+ end
@@ -1,8 +1,8 @@
1
- require "#{File.expand_path(__dir__)}/../log_pattern"
1
+ # frozen_string_literal: true
2
2
 
3
3
  # TODO: document
4
4
  class RunawayParameterError
5
5
  include RegExpPattern
6
6
 
7
7
  # TODO: implement
8
- end
8
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class TexLogParser
2
- VERSION = '1.0.0.pre.2'
3
- end
4
+ VERSION = '1.0.0.pre.7'
5
+ end
@@ -1,5 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require 'tex_log_parser/log_buffer'
5
+ require 'tex_log_parser/log_message'
1
6
  require 'tex_log_parser/log_parser'
2
- require 'tex_log_parser/version'
7
+ require 'tex_log_parser/log_pattern'
3
8
  Dir["#{File.expand_path(__dir__)}/tex_log_parser/patterns/*.rb"].each { |p| require p }
4
9
 
5
10
  # TODO: document
@@ -16,22 +21,22 @@ class TexLogParser
16
21
  # A scope opened and closed immediately -- log it, then
17
22
  # continue with rest of the line (there can be multiple such
18
23
  # things in one line, see e.g. 000.log:656)
19
- [$1, :pop] + ($2.strip.empty? ? [] : scope_changes($2))
24
+ [Regexp.last_match(1), :pop] + (Regexp.last_match(2).strip.empty? ? [] : scope_changes(Regexp.last_match(2)))
20
25
  when /^\s*\(([^()]+?)\s*$/
21
26
  # A scope opened and will be closed later.
22
27
  # Happens on a dedicated line
23
- [$1]
28
+ [Regexp.last_match(1)]
24
29
  when /^\s*(\)+)(.*)$/
25
30
  # Scopes close on a dedicated line, except if they don't (cf 000.log:624)
26
31
  # So we have to continue on the rest of the line. Uh oh.
27
- ([:pop] * $1.length) + scope_changes($2)
32
+ ([:pop] * Regexp.last_match(1).length) + scope_changes(Regexp.last_match(2))
28
33
  when /\([^)]*$/
29
34
  # BROKEN_BY_LINEBREAKS
30
35
  # Bad linebreaks can cause trailing ) to spill over. Narf.
31
36
  # e.g. 000.log:502-503
32
- ["dummy"] # Compensate the bad pop that will happen next line.
37
+ ['dummy'] # Compensate the bad pop that will happen next line.
33
38
  else
34
39
  []
35
40
  end
36
41
  end
37
- end
42
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
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.2
4
+ version: 1.0.0.pre.7
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-03-01 00:00:00.000000000 Z
11
+ date: 2018-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -76,6 +76,7 @@ files:
76
76
  - LICENSE
77
77
  - README.md
78
78
  - bin/texlogparser
79
+ - lib/logger.rb
79
80
  - lib/tex_log_parser.rb
80
81
  - lib/tex_log_parser/log_buffer.rb
81
82
  - lib/tex_log_parser/log_message.rb