epuber 0.9.4 → 0.10.0

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.
@@ -21,7 +21,7 @@ module Epuber
21
21
  end
22
22
 
23
23
  def run
24
- UI.puts "📖 Loading EPUB file #{@filepath}"
24
+ UI.info "📖 Loading EPUB file #{@filepath}"
25
25
 
26
26
  Zip::File.open(@filepath) do |zip_file|
27
27
  @zip_file = zip_file
@@ -29,22 +29,22 @@ module Epuber
29
29
  validate_mimetype
30
30
 
31
31
  @opf_path = content_opf_path
32
- UI.puts " Parsing OPF file at #{@opf_path}"
32
+ UI.info " Parsing OPF file at #{@opf_path}"
33
33
  @opf = OpfFile.new(zip_file.read(@opf_path))
34
34
 
35
35
  if zip_file.find_entry(ENCRYPTION_PATH)
36
- UI.puts ' Parsing encryption.xml file'
36
+ UI.info ' Parsing encryption.xml file'
37
37
  @encryption_handler = EncryptionHandler.new(zip_file.read(ENCRYPTION_PATH), @opf)
38
38
  end
39
39
 
40
- UI.puts ' Generating bookspec file'
40
+ UI.info ' Generating bookspec file'
41
41
  basename = File.basename(@filepath, File.extname(@filepath))
42
42
  File.write("#{basename}.bookspec", generate_bookspec)
43
43
 
44
44
  export_files
45
45
 
46
- UI.puts '' # empty line
47
- UI.puts <<~TEXT.rstrip.ansi.green
46
+ UI.info '' # empty line
47
+ UI.info <<~TEXT.rstrip.ansi.green
48
48
  🎉 Project initialized.
49
49
  Please review generated #{basename}.bookspec file and start using Epuber.
50
50
 
@@ -112,13 +112,13 @@ module Epuber
112
112
  extension = File.extname(item.href).downcase
113
113
  if text_file_extensions.include?(extension) &&
114
114
  @opf.spine_items.none? { |spine_item| spine_item.idref == item.id }
115
- UI.puts " Skipping #{item.href} (not in spine)"
115
+ UI.info " Skipping #{item.href} (not in spine)"
116
116
  next
117
117
  end
118
118
 
119
119
  # ignore ncx file
120
120
  if item.media_type == 'application/x-dtbncx+xml'
121
- UI.puts " Skipping #{item.href} (ncx file)"
121
+ UI.info " Skipping #{item.href} (ncx file)"
122
122
  next
123
123
  end
124
124
 
@@ -127,7 +127,7 @@ module Epuber
127
127
  .join(item.href)
128
128
  .to_s
129
129
 
130
- UI.puts " Exporting #{item.href} (from #{full_path})"
130
+ UI.info " Exporting #{item.href} (from #{full_path})"
131
131
 
132
132
  contents = @zip_file.read(full_path)
133
133
  contents = @encryption_handler.process_file(full_path, contents) if @encryption_handler
data/lib/epuber/plugin.rb CHANGED
@@ -12,7 +12,7 @@ module Epuber
12
12
  #
13
13
  attr_reader :instances
14
14
 
15
- # @param [String] file_path path to plugin file
15
+ # @param [String] relative_path path to plugin file (relative to project root)
16
16
  #
17
17
  def initialize(file_path)
18
18
  super(file_path)
data/lib/epuber/server.rb CHANGED
@@ -116,7 +116,7 @@ module Epuber
116
116
 
117
117
  super() do |server|
118
118
  $stderr = old_stderr
119
- UI.puts "Started development server on #{server.host}:#{server.port}"
119
+ UI.info "Started development server on #{server.host}:#{server.port}"
120
120
 
121
121
  host = if server.host == '0.0.0.0'
122
122
  'localhost'
@@ -187,13 +187,13 @@ module Epuber
187
187
  def self._log(level, message)
188
188
  case level
189
189
  when :ui
190
- UI.puts message
190
+ UI.info message
191
191
  when :info
192
- UI.puts "INFO: #{message}" if verbose
192
+ UI.info "INFO: #{message}" if verbose
193
193
  when :get
194
- UI.puts " GET: #{message}" if verbose
194
+ UI.info " GET: #{message}" if verbose
195
195
  when :ws
196
- UI.puts " WS: #{message}" if verbose
196
+ UI.info " WS: #{message}" if verbose
197
197
  else
198
198
  raise "Unknown log level #{level}"
199
199
  end
@@ -29,21 +29,27 @@ module Epuber
29
29
  # Find file in source or destination paths
30
30
  #
31
31
  # @param [String] pattern
32
+ # @param [String] context_path path to directory that is used as context for finding
33
+ # @param [Array<Symbol>, Symbol] groups
32
34
  # @param [Thread::Backtrace::Location] location
33
35
  #
34
36
  # @return [Epuber::Compiler::FileTypes::AbstractFile, nil]
35
37
  #
36
- def find_file(pattern, location: caller_locations.first)
38
+ def find_file(pattern, context_path: nil, groups: nil, location: caller_locations.first)
37
39
  return pattern if pattern.is_a?(Compiler::FileTypes::AbstractFile)
38
40
 
39
41
  UI.error!("Pattern for finding file can't be nil", location: location) if pattern.nil?
40
42
 
41
43
  begin
42
- path = @compilation_context.file_resolver.source_finder.find_file(pattern)
44
+ path = @compilation_context.file_resolver.source_finder.find_file(pattern, context_path: context_path,
45
+ groups: groups)
46
+ path = File.join(context_path, path) if context_path
43
47
  @compilation_context.file_resolver.file_with_source_path(path)
44
48
  rescue Compiler::FileFinders::FileNotFoundError
45
49
  begin
46
- path = @compilation_context.file_resolver.dest_finder.find_file(pattern)
50
+ path = @compilation_context.file_resolver.dest_finder.find_file(pattern, context_path: context_path,
51
+ groups: groups)
52
+ path = File.join(context_path, path) if context_path
47
53
  @compilation_context.file_resolver.file_with_destination_path(path)
48
54
  rescue Compiler::FileFinders::FileNotFoundError
49
55
  nil
@@ -54,27 +60,35 @@ module Epuber
54
60
  # Find files destination paths
55
61
  #
56
62
  # @param [String] pattern
63
+ # @param [String] context_path path to directory that is used as context for finding
64
+ # @param [Array<Symbol>, Symbol] groups
57
65
  # @param [Thread::Backtrace::Location] location
58
66
  #
59
67
  # @return [Array<Epuber::Compiler::FileTypes::AbstractFile>]
60
68
  #
61
- def find_destination_files(pattern, location: caller_locations.first)
69
+ def find_destination_files(pattern, context_path: nil, groups: nil, location: caller_locations.first)
62
70
  UI.error!("Pattern for finding file can't be nil", location: location) if pattern.nil?
63
71
 
64
- paths = @compilation_context.file_resolver.dest_finder.find_files(pattern)
72
+ paths = @compilation_context.file_resolver.dest_finder.find_files(pattern, context_path: context_path,
73
+ groups: groups)
65
74
  paths.map { |path| @compilation_context.file_resolver.file_with_destination_path(path) }
66
75
  end
67
76
 
68
77
  # Find file and raise exception if not found
69
78
  #
70
79
  # @param [String] pattern
80
+ # @param [String] context_path path to directory that is used as context for finding
81
+ # @param [Array<Symbol>, Symbol] groups
71
82
  # @param [Thread::Backtrace::Location] location
72
83
  #
73
84
  # @return [Epuber::Compiler::FileTypes::AbstractFile]
74
85
  #
75
- def get_file(pattern, location: caller_locations.first)
76
- file = find_file(pattern, location: location)
77
- UI.error!("File with pattern #{pattern} not found", location: location) unless file
86
+ def get_file(pattern, context_path: nil, groups: nil, location: caller_locations.first)
87
+ file = find_file(pattern, context_path: context_path, groups: groups, location: location)
88
+ unless file
89
+ UI.error!("File with pattern #{pattern} not found (context path: #{context_path || 'nil'})",
90
+ location: location)
91
+ end
78
92
 
79
93
  file
80
94
  end
@@ -82,12 +96,14 @@ module Epuber
82
96
  # Read file from destination path (raises exception if not found)
83
97
  #
84
98
  # @param [String] pattern
99
+ # @param [String] context_path path to directory that is used as context for finding
100
+ # @param [Array<Symbol>, Symbol] groups
85
101
  # @param [Thread::Backtrace::Location] location
86
102
  #
87
103
  # @return [String]
88
104
  #
89
- def read_destination_file(pattern, location: caller_locations.first)
90
- file = get_file(pattern, location: location)
105
+ def read_destination_file(pattern, context_path: nil, groups: nil, location: caller_locations.first)
106
+ file = get_file(pattern, context_path: context_path, groups: groups, location: location)
91
107
  File.read(file.final_destination_path)
92
108
  end
93
109
 
@@ -95,12 +111,14 @@ module Epuber
95
111
  #
96
112
  # @param [String] pattern
97
113
  # @param [String] content
114
+ # @param [String] context_path path to directory that is used as context for finding
115
+ # @param [Array<Symbol>, Symbol] groups
98
116
  # @param [Thread::Backtrace::Location] location
99
117
  #
100
118
  # @return [void]
101
119
  #
102
- def write_destination_file(pattern, content, location: caller_locations.first)
103
- file = get_file(pattern, location: location)
120
+ def write_destination_file(pattern, content, context_path: nil, groups: nil, location: caller_locations.first)
121
+ file = get_file(pattern, context_path: context_path, groups: groups, location: location)
104
122
  Compiler::FileTypes::AbstractFile.write_to_file(content, file.final_destination_path)
105
123
  end
106
124
  end
@@ -1,235 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/core_ext/object/try'
4
- require 'nokogiri'
3
+ require 'delegate'
5
4
 
6
- require_relative 'ruby_extensions/thread'
7
- require_relative 'command'
5
+ require_relative 'utils/logger/console_logger'
8
6
 
9
7
  module Epuber
10
- class UserInterface
11
- Location = Struct.new(:path, :lineno, :column, keyword_init: true)
12
-
13
- class << self
14
- # @return [Epuber::Command]
15
- #
16
- attr_accessor :current_command
17
- end
18
-
19
- # Fatal error, prints message and exit with return code 1
20
- #
21
- # @param [Exception, String] message message of the error
22
- # @param [Thread::Backtrace::Location] location location of the error
23
- #
24
- def self.error!(message, location: nil)
25
- error(message, location: location)
26
- exit(1)
27
- end
28
-
29
- # Fatal error, prints message and exit with return code 1
30
- #
31
- # @param [String] message message of the error
32
- # @param [Thread::Backtrace::Location] location location of the error
33
- # @param [Bool] backtrace output backtrace locations, nil == automatic, true == always and false == never
34
- #
35
- def self.error(message, location: nil)
36
- _clear_processing_line_for_new_output do
37
- $stdout.puts(_format_message(:error, message, location: location))
38
- if current_command&.verbose?
39
- _print_backtrace(location.try(:backtrace_locations) || message.try(:backtrace_locations) || caller_locations,
40
- location: location)
41
- end
42
- end
43
- end
44
-
45
- # @param [String] message message of the error
46
- # @param [Thread::Backtrace::Location] location location of the error
47
- #
48
- def self.warning(message, location: nil)
49
- _clear_processing_line_for_new_output do
50
- $stdout.puts(_format_message(:warning, message, location: location))
51
- end
52
- end
53
-
54
- # @param [#to_s] problem some problem, object just have to know to convert self into string with method #to_s
55
- #
56
- def self.print_processing_problem(problem)
57
- _clear_processing_line_for_new_output do
58
- $stdout.puts(problem.to_s.ansi.send(_color_from_level(:warning)))
59
- end
60
- end
61
-
62
- # @param [String] info_text
63
- #
64
- def self.print_processing_debug_info(info_text)
65
- return unless current_command&.verbose?
66
-
67
- _clear_processing_line_for_new_output do
68
- message = if @current_file.nil?
69
- "▸ #{info_text}"
70
- else
71
- "▸ #{@current_file.source_path}: #{info_text}"
72
- end
73
-
74
- $stdout.puts(message.ansi.send(_color_from_level(:debug)))
75
- end
76
- end
77
-
78
- # @param [Compiler::FileTypes::AbstractFile] file
79
- #
80
- # @return nil
81
- #
82
- def self.print_processing_file(file, index, count)
83
- remove_processing_file_line
84
-
85
- @current_file = file
86
-
87
- @last_processing_file_line = "▸ Processing #{file.source_path} (#{index + 1} of #{count})"
88
- $stdout.print(@last_processing_file_line)
89
- end
90
-
91
- def self.remove_processing_file_line
92
- last_line = @last_processing_file_line
93
-
94
- unless @last_processing_file_line.nil?
95
- $stdout.print("\033[2K") # remove line, but without moving cursor
96
- $stdout.print("\r") # go to beginning of line
97
- @last_processing_file_line = nil
98
- end
99
-
100
- last_line
101
- end
102
-
103
- def self.processing_files_done
104
- remove_processing_file_line
105
-
106
- @current_file = nil
107
- end
108
-
109
- def self.puts(message)
110
- _clear_processing_line_for_new_output do
111
- $stdout.puts(message)
112
- end
113
- end
114
-
115
- # @param [Compiler::FileTypes::AbstractFile] file
116
- # @param [String] step_name
117
- # @param [Fixnum] time
8
+ class UserInterface < Delegator
9
+ # @return [Logger::AbstractLogger]
118
10
  #
119
- def self.print_step_processing_time(step_name, time = nil)
120
- return yield if !current_command || !current_command.debug_steps_times
121
-
122
- remove_processing_file_line
11
+ attr_reader :logger
123
12
 
124
- if block_given?
125
- start = Time.now
126
- returned_value = yield
13
+ def initialize
14
+ super(nil)
127
15
 
128
- time = Time.now - start
129
- end
130
-
131
- info_text = "Step #{step_name} took #{time * 1000} ms"
132
- message = if @current_file.nil?
133
- "▸ #{info_text}"
134
- else
135
- "▸ #{@current_file.source_path}: #{info_text}"
136
- end
137
-
138
- $stdout.puts(_format_message(:debug, message))
139
-
140
- returned_value
16
+ @logger = Logger::ConsoleLogger.new
141
17
  end
142
18
 
143
- def self._clear_processing_line_for_new_output
144
- last_line = remove_processing_file_line
145
-
146
- yield
147
-
148
- @last_processing_file_line = last_line
149
- $stdout.print(last_line)
150
- end
151
-
152
- # @param [Symbol] level color of the output
153
- #
154
- # @return [Symbol] color
155
- #
156
- def self._color_from_level(level)
157
- case level
158
- when :error then :red
159
- when :warning then :yellow
160
- when :normal then :white
161
- when :debug then :blue
162
- else
163
- raise "Unknown output level #{level}"
164
- end
19
+ def __getobj__
20
+ @logger
165
21
  end
166
22
 
167
- # @param [Thread::Backtrace::Location, Nokogiri::XML::Node] obj
168
- #
169
- # @return [Location]
170
- #
171
- def self._location_from_obj(obj)
172
- case obj
173
- when ::Thread::Backtrace::Location
174
- Location.new(path: obj.path, lineno: obj.lineno)
175
- when ::Nokogiri::XML::Node
176
- Location.new(path: obj.document.file_path, lineno: obj.line)
177
- when Location
178
- obj
179
- when Epuber::Compiler::FileTypes::AbstractFile
180
- Location.new(path: obj.source_path)
181
- end
182
- end
183
-
184
- # @param [Symbol] level color of the output
185
- # @param [String] message message of the error
186
- # @param [Thread::Backtrace::Location] location location of the error
187
- #
188
- # @return [String] formatted message
189
- #
190
- def self._format_message(level, message, location: nil)
191
- location = _location_from_obj(location)
192
-
193
- comps = []
194
- comps << message.to_s
195
- message_already_formatted =
196
- message.is_a?(Epuber::Compiler::Problem) || message.is_a?(Epuber::Checker::TextChecker::MatchProblem)
197
-
198
- if !location.nil? && !message_already_formatted
199
- path = location.path
200
-
201
- # calculate relative path when path is absolute and in project
202
- path = path[Config.instance.project_path.size + 1..-1] if path.start_with?(Config.instance.project_path)
203
-
204
- line_parts = [
205
- " (in file #{path}",
206
- ]
207
- line_parts << "line #{location.lineno}" if location.lineno
208
- line_parts << "column #{location.column}" if location.column
209
-
210
- comps << "#{line_parts.join(' ')})"
211
- end
212
-
213
- comps.join("\n").ansi.send(_color_from_level(level))
214
- end
215
-
216
- # @param [Array<Thread::Backtrace::Location>] locations locations of the error (only for verbose output)
217
- # @param [Thread::Backtrace::Location] location location of the error
218
- #
219
- # @return [String] formatted message
220
- #
221
- def self._format_backtrace(locations, location: nil)
222
- index = locations.index(location) || 0
223
- locations[index, locations.size].map(&:to_s)
224
- end
225
-
226
- # @param [Thread::Backtrace::Location] location location of the error
227
- #
228
- def self._print_backtrace(locations, location: nil)
229
- $stdout.puts(_format_backtrace(locations, location: location)) if current_command.verbose?
23
+ def __setobj__(obj)
24
+ @logger = obj
230
25
  end
231
26
  end
232
27
 
233
28
  # shortcut
234
- UI = UserInterface
29
+ UI = UserInterface.new
235
30
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Epuber
4
+ Location = Struct.new(:path, :lineno, :column, keyword_init: true) do
5
+ # !@attribute [r] path
6
+ # @return [String] path to file
7
+
8
+ # !@attribute [r] lineno
9
+ # @return [Integer, nil] line number
10
+
11
+ # !@attribute [r] column
12
+ # @return [Integer, nil] column number
13
+ end
14
+ end
@@ -0,0 +1,214 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/object/try'
4
+ require 'nokogiri'
5
+
6
+ require_relative '../location'
7
+
8
+ module Epuber
9
+ module Logger
10
+ class AbstractLogger
11
+ LEVELS = %i[
12
+ error
13
+ warning
14
+ info
15
+ debug
16
+ ].freeze
17
+
18
+ # @return [Boolean]
19
+ #
20
+ attr_accessor :verbose
21
+
22
+ # @return [Boolean]
23
+ #
24
+ attr_accessor :debug_steps_times
25
+
26
+ # @param [Hash] opts
27
+ # @option opts [Boolean] :verbose (false)
28
+ # @option opts [Boolean] :debug_steps_times (false)
29
+ #
30
+ def initialize(opts = {})
31
+ @verbose = opts.fetch(:verbose, false)
32
+ @debug_steps_times = opts.fetch(:debug_steps_times, false)
33
+
34
+ @current_file = nil
35
+ @sticky_message = nil
36
+ @error_was_logged = false
37
+ end
38
+
39
+ # Report error message
40
+ #
41
+ # @param [String, #to_s] message
42
+ # @param [Thread::Backtrace::Location, Epuber::Location, Nokogiri::XML::Node, nil] location
43
+ # @param [Boolean] stick if true, the error message will be sticked to the previous one
44
+ #
45
+ def error!(message, location: nil, backtrace: caller_locations)
46
+ _common_log(:error, message, location: location, backtrace: backtrace)
47
+ exit(1)
48
+ end
49
+
50
+ # Report error message
51
+ #
52
+ # @param [String, #to_s] message
53
+ # @param [Thread::Backtrace::Location, Epuber::Location, Nokogiri::XML::Node, nil] location
54
+ # @param [Boolean] stick if true, the error message will be sticked to the previous one
55
+ #
56
+ def error(message, sticky: false, location: nil, backtrace: caller_locations)
57
+ _common_log(:error, message, sticky: sticky, location: location, backtrace: backtrace)
58
+ end
59
+
60
+ # Report warning message
61
+ #
62
+ # @param [String, #to_s] message
63
+ # @param [Thread::Backtrace::Location, Epuber::Location, Nokogiri::XML::Node, nil] location
64
+ #
65
+ def warning(message, sticky: false, location: nil, backtrace: caller_locations)
66
+ _common_log(:warning, message, sticky: sticky, location: location, backtrace: backtrace)
67
+ end
68
+
69
+ # Report info message
70
+ #
71
+ # @param [String, #to_s] message
72
+ # @param [Thread::Backtrace::Location, Epuber::Location, Nokogiri::XML::Node, nil] location
73
+ #
74
+ def info(message, sticky: false, location: nil, backtrace: caller_locations)
75
+ _common_log(:info, message, sticky: sticky, location: location, backtrace: backtrace)
76
+ end
77
+
78
+ # Report debug message
79
+ #
80
+ # @param [String, #to_s] message
81
+ # @param [Thread::Backtrace::Location, Epuber::Location, Nokogiri::XML::Node, nil] location
82
+ #
83
+ def debug(message, sticky: false, location: nil, backtrace: caller_locations)
84
+ return unless @verbose
85
+
86
+ _common_log(:debug, message, sticky: sticky, location: location, backtrace: backtrace)
87
+ end
88
+
89
+ # @param [Epuber::Compiler::FileTypes::AbstractFile] file
90
+ # @param [Fixnum] index
91
+ # @param [Fixnum] count
92
+ #
93
+ def start_processing_file(file, index, count)
94
+ @current_file = file
95
+
96
+ _common_log(:debug, "▸ Processing #{file.source_path} (#{index + 1} of #{count})", sticky: true)
97
+ end
98
+
99
+ def end_processing
100
+ _remove_sticky_message
101
+ @current_file = nil
102
+ end
103
+
104
+ # @param [String] info_text
105
+ #
106
+ def print_processing_debug_info(info_text)
107
+ return unless @verbose
108
+
109
+ message = if @current_file.nil?
110
+ "▸ #{info_text}"
111
+ else
112
+ "▸ #{@current_file.source_path}: #{info_text}"
113
+ end
114
+ _log(:debug, message)
115
+ end
116
+
117
+ # @param [String] step_name
118
+ # @param [Fixnum] time
119
+ #
120
+ def print_step_processing_time(step_name, time = nil)
121
+ return yield unless @debug_steps_times
122
+
123
+ if block_given?
124
+ start = Time.now
125
+ returned_value = yield
126
+
127
+ time = Time.now - start
128
+ end
129
+
130
+ info_text = "Step #{step_name} took #{(time * 1000).round(2)} ms"
131
+ message = if @current_file.nil?
132
+ "▸ #{info_text}"
133
+ else
134
+ "▸ #{@current_file.source_path}: #{info_text}"
135
+ end
136
+
137
+ _log(:debug, message)
138
+
139
+ returned_value
140
+ end
141
+
142
+ # Return true if there was any error logged
143
+ #
144
+ # @return [Boolean]
145
+ def error?
146
+ @error_was_logged
147
+ end
148
+
149
+ protected
150
+
151
+ # Point of implementation for concrete logger
152
+ #
153
+ # @param [Symbol] level
154
+ # @param [String] message
155
+ # @param [Epuber::Location, nil] location
156
+ # @param [Array<Thread::Backtrace::Location>, nil] backtrace
157
+ # @param [Boolean] sticky if true, the message will be sticky (will be always as the last message)
158
+ #
159
+ def _log(level, message, location: nil, backtrace: nil, remove_last: false) # rubocop:disable Lint/UnusedMethodArgument
160
+ raise 'Not implemented, this is abstract class'
161
+ end
162
+
163
+ # Remove last line of the output (if it was sticky)
164
+ #
165
+ # @return [String, nil] last line
166
+ #
167
+ def _remove_sticky_message; end
168
+
169
+ private
170
+
171
+ # Core logging method
172
+ #
173
+ # @param level [Symbol]
174
+ # @param message [String]
175
+ # @param location [Thread::Backtrace::Location, Epuber::Location, Nokogiri::XML::Node,
176
+ # Epuber::Compiler::FileTypes::AbstractFile, nil]
177
+ # @param sticky [Boolean] if true, the message will be sticky (will be always as the last message)
178
+ #
179
+ def _common_log(level, message, sticky: false, location: nil, backtrace: nil)
180
+ raise ArgumentError, "Unknown log level #{level}" unless LEVELS.include?(level)
181
+
182
+ @error_was_logged = true if level == :error
183
+
184
+ location = _location_from_obj(location)
185
+
186
+ if @verbose && level == :error
187
+ backtrace = location.try(:backtrace_locations) ||
188
+ message.try(:backtrace_locations) ||
189
+ backtrace ||
190
+ caller_locations
191
+ end
192
+
193
+ _log(level, message, location: location, backtrace: backtrace, sticky: sticky)
194
+ end
195
+
196
+ # @param [Thread::Backtrace::Location, Nokogiri::XML::Node] obj
197
+ #
198
+ # @return [Location]
199
+ #
200
+ def _location_from_obj(obj)
201
+ case obj
202
+ when ::Thread::Backtrace::Location
203
+ Location.new(path: obj.path, lineno: obj.lineno)
204
+ when ::Nokogiri::XML::Node
205
+ Location.new(path: obj.document.file_path, lineno: obj.line)
206
+ when Location
207
+ obj
208
+ when Epuber::Compiler::FileTypes::AbstractFile
209
+ Location.new(path: obj.source_path)
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end