Module: SimpleCov::SourceFile::SourceLoader
- Defined in:
- lib/simplecov/source_file/source_loader.rb
Overview
Reads a source file into an array of lines, honoring the source's
shebang and coding: magic comment when present. Always
transcodes to UTF-8 with invalid/undef bytes replaced — both for
JRuby compatibility and to keep encoding shenanigans in one place
(see #866).
Constant Summary collapse
- SHEBANG_REGEX =
/\A#!/- RUBY_FILE_ENCODING_MAGIC_COMMENT_REGEX =
/\A#\s*(?:-\*-)?\s*(?:en)?coding:\s*(\S+)\s*(?:-\*-)?\s*\z/
Class Method Summary collapse
- .call(filename) ⇒ Object
-
.ensure_remove_undefs(file_lines) ⇒ Object
Guarantee every line leaves the loader as valid UTF-8, replacing what can't be represented: transcode non-UTF-8 lines (setting invalid/undef options on
file.set_encodingdoesn't work properly, and this also works around a JRuby incompatibility) and scrub UTF-8-tagged lines that carry invalid bytes, which would otherwise raise from every regex the classifier runs. - .read_lines(file, lines, current_line) ⇒ Object
-
.scrub_invalid(line) ⇒ Object
A line read as UTF-8 can still carry invalid bytes (a Latin-1 source file without a magic comment, say).
-
.set_encoding_based_on_magic_comment(file, line) ⇒ Object
Encoding magic comment must be placed at first line except for shebang.
- .shebang?(line) ⇒ Boolean
Class Method Details
.call(filename) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/simplecov/source_file/source_loader.rb', line 16 def call(filename) lines = [] #: Array[String] # The default encoding is UTF-8 File.open(filename, "rb:UTF-8") do |file| current_line = scrub_invalid(file.gets) if current_line && shebang?(current_line) lines << current_line current_line = scrub_invalid(file.gets) end read_lines(file, lines, current_line) end end |
.ensure_remove_undefs(file_lines) ⇒ Object
Guarantee every line leaves the loader as valid UTF-8, replacing
what can't be represented: transcode non-UTF-8 lines (setting
invalid/undef options on file.set_encoding doesn't work
properly, and this also works around a JRuby incompatibility)
and scrub UTF-8-tagged lines that carry invalid bytes, which
would otherwise raise from every regex the classifier runs.
66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/simplecov/source_file/source_loader.rb', line 66 def ensure_remove_undefs(file_lines) file_lines.each do |line| # simplecov:disable — defensive: only fires for non-UTF-8 source files if line.encoding == Encoding::UTF_8 line.scrub! unless line.valid_encoding? else line.encode!("UTF-8", invalid: :replace, undef: :replace) end # simplecov:enable end end |
.read_lines(file, lines, current_line) ⇒ Object
45 46 47 48 49 50 |
# File 'lib/simplecov/source_file/source_loader.rb', line 45 def read_lines(file, lines, current_line) return lines unless current_line set_encoding_based_on_magic_comment(file, current_line) lines.concat([current_line], ensure_remove_undefs(file.readlines)) end |
.scrub_invalid(line) ⇒ Object
A line read as UTF-8 can still carry invalid bytes (a Latin-1 source file without a magic comment, say). Replace them before any regex sees the line: the shebang and magic-comment checks would otherwise raise ArgumentError and take the report down.
35 36 37 38 39 |
# File 'lib/simplecov/source_file/source_loader.rb', line 35 def scrub_invalid(line) return line if line.nil? || line.valid_encoding? line.scrub end |
.set_encoding_based_on_magic_comment(file, line) ⇒ Object
Encoding magic comment must be placed at first line except for shebang.
54 55 56 57 58 |
# File 'lib/simplecov/source_file/source_loader.rb', line 54 def set_encoding_based_on_magic_comment(file, line) if (match = RUBY_FILE_ENCODING_MAGIC_COMMENT_REGEX.match(line)) file.set_encoding(match[1], "UTF-8") end end |
.shebang?(line) ⇒ Boolean
41 42 43 |
# File 'lib/simplecov/source_file/source_loader.rb', line 41 def shebang?(line) SHEBANG_REGEX.match?(line) end |