CoffeeScript JS guessing

This commit is contained in:
Joshua Peek
2011-05-25 11:25:11 -05:00
parent 3ea66af178
commit 972632b9db
10 changed files with 188 additions and 0 deletions

View File

@@ -150,6 +150,8 @@ module Linguist
# Generated source code is supressed in diffs and is ignored by
# langauge statistics.
#
# Requires Blob#data
#
# Includes:
# - XCode project XML files
# - Minified JavaScript
@@ -158,6 +160,8 @@ module Linguist
def generated?
if ['.xib', '.nib', '.pbxproj'].include?(pathname.extname)
true
elsif generated_coffeescript?
true
elsif pathname.extname == '.js'
# JS is minified if any lines are longer than 1000c
lines.any? { |l| l.length > 1000 }
@@ -166,6 +170,42 @@ module Linguist
end
end
# Internal: Is the blob JS generated by CoffeeScript?
#
# Requires Blob#data
#
# CoffeScript is meant to output JS that would be difficult to
# tell if it was generated or not. Look for a number of patterns
# outputed by the CS compiler.
#
# Return true or false
def generated_coffeescript?
return unless pathname.extname == '.js'
if lines[0] == '(function() {' && # First line is module closure opening
lines[-2] == '}).call(this);' && # Second to last line closes module closure
lines[-1] == '' # Last line is blank
score = 0
lines.each do |line|
if line =~ /var /
# Underscored temp vars are likely to be Coffee
score += 1 * line.gsub(/(_fn|_i|_len|_ref|_results)/).count
# bind and extend functions are very Coffee specific
score += 3 * line.gsub(/(__bind|__extends|__hasProp|__indexOf|__slice)/).count
end
end
# Require a score of 3. This is fairly arbitrary. Consider
# tweaking later.
score >= 3
else
false
end
end
# Public: Should the blob be indexed for searching?
#
# Excluded:

View File

@@ -0,0 +1,21 @@
class Animal
constructor: (@name) ->
move: (meters) ->
alert @name + " moved " + meters + "m."
class Snake extends Animal
move: ->
alert "Slithering..."
super 5
class Horse extends Animal
move: ->
alert "Galloping..."
super 45
sam = new Snake "Sammy the Python"
tom = new Horse "Tommy the Palomino"
sam.move()
tom.move()

46
test/fixtures/blob/coffee/classes.js vendored Normal file
View File

@@ -0,0 +1,46 @@
(function() {
var Animal, Horse, Snake, sam, tom;
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
};
Animal = (function() {
function Animal(name) {
this.name = name;
}
Animal.prototype.move = function(meters) {
return alert(this.name + " moved " + meters + "m.");
};
return Animal;
})();
Snake = (function() {
__extends(Snake, Animal);
function Snake() {
Snake.__super__.constructor.apply(this, arguments);
}
Snake.prototype.move = function() {
alert("Slithering...");
return Snake.__super__.move.call(this, 5);
};
return Snake;
})();
Horse = (function() {
__extends(Horse, Animal);
function Horse() {
Horse.__super__.constructor.apply(this, arguments);
}
Horse.prototype.move = function() {
alert("Galloping...");
return Horse.__super__.move.call(this, 45);
};
return Horse;
})();
sam = new Snake("Sammy the Python");
tom = new Horse("Tommy the Palomino");
sam.move();
tom.move();
}).call(this);

View File

3
test/fixtures/blob/coffee/empty.js vendored Normal file
View File

@@ -0,0 +1,3 @@
(function() {
}).call(this);

View File

@@ -0,0 +1 @@
console.log "Hello, World!"

3
test/fixtures/blob/coffee/hello.js vendored Normal file
View File

@@ -0,0 +1,3 @@
(function() {
console.log("Hello, World!");
}).call(this);

28
test/fixtures/blob/coffee/intro.coffee vendored Normal file
View File

@@ -0,0 +1,28 @@
# Assignment:
number = 42
opposite = true
# Conditions:
number = -42 if opposite
# Functions:
square = (x) -> x * x
# Arrays:
list = [1, 2, 3, 4, 5]
# Objects:
math =
root: Math.sqrt
square: square
cube: (x) -> x * square x
# Splats:
race = (winner, runners...) ->
print winner, runners
# Existence:
alert "I knew it!" if elvis?
# Array comprehensions:
cubes = (math.cube num for num in list)

37
test/fixtures/blob/coffee/intro.js vendored Normal file
View File

@@ -0,0 +1,37 @@
(function() {
var cubes, list, math, num, number, opposite, race, square;
var __slice = Array.prototype.slice;
number = 42;
opposite = true;
if (opposite) {
number = -42;
}
square = function(x) {
return x * x;
};
list = [1, 2, 3, 4, 5];
math = {
root: Math.sqrt,
square: square,
cube: function(x) {
return x * square(x);
}
};
race = function() {
var runners, winner;
winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
return print(winner, runners);
};
if (typeof elvis !== "undefined" && elvis !== null) {
alert("I knew it!");
}
cubes = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = list.length; _i < _len; _i++) {
num = list[_i];
_results.push(math.cube(num));
}
return _results;
})();
}).call(this);

View File

@@ -116,6 +116,15 @@ class TestBlob < Test::Unit::TestCase
# Minified JS
assert !blob("jquery-1.6.1.js").generated?
assert blob("jquery-1.6.1.min.js").generated?
# CoffeScript JS
# These examples are to basic to tell
assert !blob("coffee/empty.js").generated?
assert !blob("coffee/hello.js").generated?
assert blob("coffee/intro.js").generated?
assert blob("coffee/classes.js").generated?
end
def test_vendored