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

Sign up to get free protection for your applications and to get access to all the features.
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