Module: SimpleCov::SourceFile::SourceLoader
- Extended by:
- SourceLoader
- Included in:
- 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 and undefined bytes replaced, both for JRuby compatibility and to
keep encoding shenanigans in one place (#866).
Constant Summary collapse
- SHEBANG_REGEX =
/\A#!/- RUBY_FILE_ENCODING_MAGIC_COMMENT_REGEX =
/\A#\s*(?:-\*-)?\s*(?:en)?coding:\s*(\S+)\s*(?:-\*-)?\s*\z/
Instance Method Summary collapse
- #call(filename) ⇒ Object
-
#ensure_remove_undefs(file_lines) ⇒ Object
Setting invalid/undef options on
file.set_encodingdoesn't work properly, and transcoding here also works around a JRuby incompatibility. -
#make_utf8(line) ⇒ Object
mutant:disable — on CRuby the two arms answer alike, because converting to the encoding a string already carries scrubs it when
invalid: :replaceis given. -
#open_file(name, mode) ⇒ Object
mutant:disable — Ruby 4.0 removed Kernel#open's leading-pipe command mode, so no test can tell
File.openfromopenhere any more. - #read_lines(file, lines, current_line) ⇒ Object
-
#scrub_invalid(line) ⇒ Object
A line read as UTF-8 can still carry invalid bytes, from a Latin-1 source file without a magic comment, say.
-
#set_encoding_based_on_magic_comment(file, line) ⇒ Object
An encoding magic comment must be placed on the first line, except after a shebang.
- #shebang?(line) ⇒ Boolean
Instance Method Details
#call(filename) ⇒ Object
15 16 17 18 19 20 |
# File 'lib/simplecov/source_file/source_loader.rb', line 15 def call(filename) lines = [] #: Array[String] open_file(filename, "rb:UTF-8") do |file| read_lines(file, lines, scrub_invalid(file.gets)) end end |
#ensure_remove_undefs(file_lines) ⇒ Object
Setting invalid/undef options on file.set_encoding doesn't work
properly, and transcoding here also works around a JRuby incompatibility.
67 68 69 |
# File 'lib/simplecov/source_file/source_loader.rb', line 67 def ensure_remove_undefs(file_lines) file_lines.each { |line| make_utf8(line) } end |
#make_utf8(line) ⇒ Object
mutant:disable — on CRuby the two arms answer alike, because
converting to the encoding a string already carries scrubs it
when invalid: :replace is given. The arms are kept apart for
the engines where that conversion is the documented no-op it
reads as, which is the same reason the transcode is here rather
than on file.set_encoding.
Encodings are singletons, so identity is the whole of the question. A line
already tagged UTF-8 has nothing to transcode, only invalid bytes to
replace, and scrubbing a line that has none of those leaves it alone.
80 81 82 83 84 85 86 |
# File 'lib/simplecov/source_file/source_loader.rb', line 80 def make_utf8(line) if line.encoding.equal?(Encoding::UTF_8) line.scrub! else line.encode!("UTF-8", invalid: :replace, undef: :replace) end end |
#open_file(name, mode) ⇒ Object
mutant:disable — Ruby 4.0 removed Kernel#open's leading-pipe
command mode, so no test can tell File.open from open here
any more. The explicit receiver is kept: on older rubies it is
what refuses to run a filename as a command.
26 27 28 |
# File 'lib/simplecov/source_file/source_loader.rb', line 26 def open_file(name, mode, &) File.open(name, mode, &) end |
#read_lines(file, lines, current_line) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/simplecov/source_file/source_loader.rb', line 44 def read_lines(file, lines, current_line) return lines unless current_line if shebang?(current_line) lines << current_line current_line = scrub_invalid(file.gets) return lines unless current_line end 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, from a Latin-1 source file without a magic comment, say. They are replaced before any regex sees the line: the shebang and magic-comment checks would otherwise raise ArgumentError and take the report down.
34 35 36 37 38 |
# File 'lib/simplecov/source_file/source_loader.rb', line 34 def scrub_invalid(line) return line if line.nil? || line.valid_encoding? line.scrub end |
#set_encoding_based_on_magic_comment(file, line) ⇒ Object
An encoding magic comment must be placed on the first line, except after a shebang.
59 60 61 62 63 |
# File 'lib/simplecov/source_file/source_loader.rb', line 59 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
40 41 42 |
# File 'lib/simplecov/source_file/source_loader.rb', line 40 def shebang?(line) SHEBANG_REGEX.match?(line) end |