diff --git a/lib/linguist/blob_helper.rb b/lib/linguist/blob_helper.rb index f62a67d7..3011bb83 100644 --- a/lib/linguist/blob_helper.rb +++ b/lib/linguist/blob_helper.rb @@ -451,24 +451,26 @@ module Linguist # Internal: Guess language of .m files. # # Objective-C heuristics: - # * Keywords + # * Keywords ("#import", "#include", "#ifdef", #define, "@end") or "//" and opening "\*" comments # # Matlab heuristics: - # * Leading function keyword + # * Leading "function " of "classdef " keyword # * "%" comments # + # Note: All "#" keywords, e.g., "#import", are guaranteed to be Objective-C. Because the ampersand + # is used to created function handles and anonymous functions in Matlab, most "@" keywords are not + # safe heuristics. However, "end" is a reserved term in Matlab and can't be used to create a valid + # function handle. Because @end is required to close any @implementation, @property, @interface, + # @synthesize, etc. directive in Objective-C, only @end needs to be checked for. + # # Returns a Language. def guess_m_language - # Objective-C keywords - if lines.grep(/^#import|@(interface|implementation|property|synthesize|end)/).any? + # Objective-C keywords or comments + if lines.grep(/^#(import|include|ifdef|define)|@end/).any? || lines.grep(/^\s*\/\//).any? || lines.grep(/^\s*\/\*/).any? Language['Objective-C'] - # File function - elsif lines.first.to_s =~ /^function / - Language['Matlab'] - - # Matlab comment - elsif lines.grep(/^%/).any? + # Matlab file function or class or comments + elsif lines.first.grep(/^\s*(function |classdef )/).any? || lines.grep(/^\s*%/).any? Language['Matlab'] # Fallback to Objective-C, don't want any Matlab false positives diff --git a/test/fixtures/matlab_class.m b/test/fixtures/matlab_class.m new file mode 100644 index 00000000..7377a4d3 --- /dev/null +++ b/test/fixtures/matlab_class.m @@ -0,0 +1,29 @@ +classdef matlab_class + properties + R; + G; + B; + end + methods + function obj = matlab_class(r,g,b) + obj.R = r; + obj.G = g; + obj.B = b; + end + function disp(obj) + disp(['Red: ' num2str(obj.R) ... + ', Green: ' num2str(obj.G) ... + ', Blue: ' num2str(obj.B)]); + end + end + enumeration + red (1,0,0) + green (0,1,0) + blue (0,0,1) + cyan (0,1,1) + magenta (1,0,1) + yellow (1,1,0) + black (0,0,0) + white (1,1,1) + end +end \ No newline at end of file diff --git a/test/fixtures/matlab_function2.m b/test/fixtures/matlab_function2.m new file mode 100644 index 00000000..8063dad6 --- /dev/null +++ b/test/fixtures/matlab_function2.m @@ -0,0 +1,33 @@ + function ret = matlab_function2(A,B) +% Simple function that combines two values using function handles and displays +% the return value + +% create function handles +fun1=@interface; +fun2=@implementation; +fun3=@property; +fun4=@synthesize; + +% use function handles +ret = fun1(A)+fun2(A)+fun3(B)+fun4(B); + +% Display the return value +disp('Return value in function'); +disp(ret); + + +function A=interface(A) +% simple sub-function with same name Objective-C @keyword +A=2*A; + +function A=implementation(A) +% simple sub-function with same name Objective-C @keyword +A=A^2; + +function B=property(B) +% simple sub-function with same name Objective-C @keyword +B=2*B; + +function B=synthesize(B) +% simple sub-function with same name Objective-C @keyword +B=B^2; \ No newline at end of file diff --git a/test/fixtures/matlab_script2.m b/test/fixtures/matlab_script2.m new file mode 100644 index 00000000..8e16eca6 --- /dev/null +++ b/test/fixtures/matlab_script2.m @@ -0,0 +1,13 @@ + % Matlab example script 2 + % Comments precended with arbitrary whitespace (spaces or tabs) + + %Call matlab_function function which resides in the same directory + +value1 = 5 % semicolon at end of line is not mandatory, only suppresses output to command line. +value2 = 3 + + % Calculate sum of value1 and value2 +result = matlab_function(value1,value2); + +disp('called from script') +disp(result); \ No newline at end of file diff --git a/test/test_blob.rb b/test/test_blob.rb index 170e45f7..9f2003c3 100644 --- a/test/test_blob.rb +++ b/test/test_blob.rb @@ -311,6 +311,9 @@ class TestBlob < Test::Unit::TestCase assert_equal Language['Objective-C'], blob("hello.m").language assert_equal Language['Matlab'], blob("matlab_function.m").language assert_equal Language['Matlab'], blob("matlab_script.m").language + assert_equal Language['Matlab'], blob("matlab_function2.m").language + assert_equal Language['Matlab'], blob("matlab_script2.m").language + assert_equal Language['Matlab'], blob("matlab_class.m").language # .r disambiguation assert_equal Language['R'], blob("hello-r.R").language