Strategies take result from previous strategy into account (#4099)

Each strategy takes as candidates the language outputted by the
previous strategy if any. This was already the case for the
Classifier and Heuristic strategies as these couldn't generate new
candidate languages (as opposed to the Modeline, Filename, Shebang,
and Extension strategies).

In practice, this signifies that if, for example, the Shebang
strategy finds two possible languages for a given file (as is
currently possible with the perl interpreter), the next strategy, the
Extension strategy, will use this information and further reduce the
set of possible language.
Currently, without this commit, the Extension strategy would discard
the results from the previous strategy and start anew, possibly
returning a different language from those returned by the Shebang
strategy.
This commit is contained in:
Paul Chaignon
2018-04-17 10:02:57 +02:00
committed by GitHub
parent 5363e045bb
commit 54ae7e7b4d
4 changed files with 88 additions and 8 deletions

View File

@@ -3,17 +3,20 @@ module Linguist
# Public: Use shebang to detect language of the blob.
#
# blob - An object that quacks like a blob.
# candidates - A list of candidate languages.
#
# Examples
#
# Shebang.call(FileBlob.new("path/to/file"))
#
# Returns an Array with one Language if the blob has a shebang with a valid
# interpreter, or empty if there is no shebang.
def self.call(blob, _ = nil)
# Returns an array of languages from the candidate list for which the
# blob's shebang is valid. Returns an empty list if there is no shebang.
# If the candidate list is empty, any language is a valid candidate.
def self.call(blob, candidates)
return [] if blob.symlink?
Language.find_by_interpreter interpreter(blob.data)
languages = Language.find_by_interpreter interpreter(blob.data)
candidates.any? ? candidates & languages : languages
end
# Public: Get the interpreter from the shebang

View File

@@ -2,8 +2,21 @@ module Linguist
module Strategy
# Detects language based on extension
class Extension
def self.call(blob, _)
Language.find_by_extension(blob.name.to_s)
# Public: Use the file extension to detect the blob's language.
#
# blob - An object that quacks like a blob.
# candidates - A list of candidate languages.
#
# Examples
#
# Extension.call(FileBlob.new("path/to/file"))
#
# Returns an array of languages associated with a blob's file extension.
# Selected languages must be in the candidate list, except if it's empty,
# in which case any language is a valid candidate.
def self.call(blob, candidates)
languages = Language.find_by_extension(blob.name.to_s)
candidates.any? ? candidates & languages : languages
end
end
end

View File

@@ -2,9 +2,22 @@ module Linguist
module Strategy
# Detects language based on filename
class Filename
def self.call(blob, _)
# Public: Use the filename to detect the blob's language.
#
# blob - An object that quacks like a blob.
# candidates - A list of candidate languages.
#
# Examples
#
# Filename.call(FileBlob.new("path/to/file"))
#
# Returns an array of languages with a associated blob's filename.
# Selected languages must be in the candidate list, except if it's empty,
# in which case any language is a valid candidate.
def self.call(blob, candidates)
name = blob.name.to_s
Language.find_by_filename(name)
languages = Language.find_by_filename(name)
candidates.any? ? candidates & languages : languages
end
end
end

51
test/fixtures/Perl/01-methods.pl vendored Normal file
View File

@@ -0,0 +1,51 @@
#!perl
use Test::More;
use Test::Exception;
use_ok 'Music::ScaleNote';
my $msn = Music::ScaleNote->new(
scale_note => 'C',
scale_name => 'pminor',
# verbose => 1,
);
isa_ok $msn, 'Music::ScaleNote';
my $x;
throws_ok { $x = $msn->get_offset() }
qr/note_name, note_format or offset not provided/, 'invalid get_offset';
my $format = 'midinum';
$x = $msn->get_offset(
note_name => 60,
note_format => $format,
offset => 1,
);
is $x->format($format), 63, 'get_offset';
$format = 'ISO';
$x = $msn->get_offset(
note_name => 'D#4',
note_format => $format,
offset => -1,
);
is $x->format($format), 'C4', 'get_offset';
throws_ok {
$x = $msn->get_offset(
note_name => 'C0',
note_format => $format,
offset => -1,
)
} qr/Octave: -1 out of bounds/, 'out of bounds';
throws_ok {
$x = $msn->get_offset(
note_name => 'A#127',
note_format => $format,
offset => 1,
)
} qr/Octave: 128 out of bounds/, 'out of bounds';
done_testing();