diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 8c405356..c80fdb2b 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -559,6 +559,8 @@ Crystal: - .cr ace_mode: ruby tm_scope: source.ruby + interpreters: + - crystal Cucumber: extensions: @@ -736,6 +738,8 @@ Erlang: - .es - .escript - .hrl + interpreters: + - escript F#: type: programming @@ -931,6 +935,8 @@ Gnuplot: - .gnuplot - .plot - .plt + interpreters: + - gnuplot Go: type: programming @@ -1196,6 +1202,8 @@ Ioke: color: "#078193" extensions: - .ik + interpreters: + - ioke Isabelle: type: programming @@ -1703,6 +1711,8 @@ Nu: filenames: - Nukefile tm_scope: source.scheme + interpreters: + - nush NumPy: group: Python @@ -1889,6 +1899,8 @@ Parrot Assembly: - pasm extensions: - .pasm + interpreters: + - parrot tm_scope: none Parrot Internal Representation: @@ -1899,6 +1911,8 @@ Parrot Internal Representation: - pir extensions: - .pir + interpreters: + - parrot Pascal: type: programming @@ -1941,6 +1955,8 @@ Perl6: - .p6m - .pl6 - .pm6 + interpreters: + - perl6 tm_scope: none PigLatin: @@ -2005,6 +2021,8 @@ Prolog: - .ecl - .pro - .prolog + interpreters: + - swipl Propeller Spin: type: programming @@ -2068,6 +2086,8 @@ Python: - wscript interpreters: - python + - python2 + - python3 Python traceback: type: data @@ -2088,6 +2108,8 @@ QMake: extensions: - .pro - .pri + interpreters: + - qmake R: type: programming @@ -2242,6 +2264,8 @@ Ruby: - .watchr interpreters: - ruby + - macruby + - rake filenames: - .pryrc - Appraisals @@ -2328,6 +2352,8 @@ Scala: - .scala - .sbt - .sc + interpreters: + - scala Scaml: group: HTML diff --git a/lib/linguist/samples.rb b/lib/linguist/samples.rb index 82c011b1..001204b5 100644 --- a/lib/linguist/samples.rb +++ b/lib/linguist/samples.rb @@ -52,14 +52,16 @@ module Linguist }) end else + path = File.join(dirname, filename) + if File.extname(filename) == "" - raise "#{File.join(dirname, filename)} is missing an extension, maybe it belongs in filenames/ subdir" + raise "#{path} is missing an extension, maybe it belongs in filenames/ subdir" end yield({ - :path => File.join(dirname, filename), + :path => path, :language => category, - :interpreter => File.exist?(filename) ? Linguist.interpreter_from_shebang(File.read(filename)) : nil, + :interpreter => Linguist.interpreter_from_shebang(File.read(path)), :extname => File.extname(filename) }) end @@ -131,18 +133,19 @@ module Linguist script = script == 'env' ? tokens[1] : script - # "python2.6" -> "python" - if script =~ /((?:\d+\.?)+)/ - script.sub! $1, '' - end + # If script has an invalid shebang, we might get here + return unless script + + # "python2.6" -> "python2" + script.sub! $1, '' if script =~ /(\.\d+)$/ # Check for multiline shebang hacks that call `exec` if script == 'sh' && lines[0...5].any? { |l| l.match(/exec (\w+).+\$0.+\$@/) } script = $1 end - - script + + File.basename(script) else nil end diff --git a/samples/Ruby/wrong_shebang.rb b/samples/Ruby/wrong_shebang.rb deleted file mode 100644 index 22b4804a..00000000 --- a/samples/Ruby/wrong_shebang.rb +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env python -puts "Not Python" diff --git a/test/test_samples.rb b/test/test_samples.rb index 114ed315..06ede379 100644 --- a/test/test_samples.rb +++ b/test/test_samples.rb @@ -31,23 +31,29 @@ class TestSamples < Test::Unit::TestCase assert_equal data['languages_total'], data['languages'].inject(0) { |n, (_, c)| n += c } assert_equal data['tokens_total'], data['language_tokens'].inject(0) { |n, (_, c)| n += c } assert_equal data['tokens_total'], data['tokens'].inject(0) { |n, (_, ts)| n += ts.inject(0) { |m, (_, c)| m += c } } + assert !data["interpreters"].empty? end - # Check that there aren't samples with extensions that aren't explicitly defined in languages.yml - def test_parity - extensions = Samples.cache['extnames'] - languages_yml = File.expand_path("../../lib/linguist/languages.yml", __FILE__) - languages = YAML.load_file(languages_yml) - - languages.each do |name, options| + # Check that there aren't samples with extensions or interpreters that + # aren't explicitly defined in languages.yml + languages_yml = File.expand_path("../../lib/linguist/languages.yml", __FILE__) + YAML.load_file(languages_yml).each do |name, options| + define_method "test_samples_have_parity_with_languages_yml_for_#{name}" do options['extensions'] ||= [] - - if extnames = extensions[name] + if extnames = Samples.cache['extnames'][name] extnames.each do |extname| next if extname == '.script!' assert options['extensions'].include?(extname), "#{name} has a sample with extension (#{extname}) that isn't explicitly defined in languages.yml" end end + + options['interpreters'] ||= [] + if interpreters = Samples.cache['interpreters'][name] + interpreters.each do |interpreter| + # next if extname == '.script!' + assert options['interpreters'].include?(interpreter), "#{name} has a sample with an interpreter (#{interpreter}) that isn't explicitly defined in languages.yml" + end + end end end @@ -76,4 +82,9 @@ class TestSamples < Test::Unit::TestCase end end end + + def test_shebang + assert_equal "crystal", Linguist.interpreter_from_shebang("#!/usr/bin/env bin/crystal") + assert_equal "python2", Linguist.interpreter_from_shebang("#!/usr/bin/python2.4") + end end