aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJoshua Peek <josh@joshpeek.com>2012-08-03 15:47:50 -0500
committerJoshua Peek <josh@joshpeek.com>2012-08-03 15:47:50 -0500
commit41b7d13aa7541bc03b3bfd4e3eda36f6cde9cca1 (patch)
tree74a8b56a5cb2dbe7971797ec265d2b9338d78632 /lib
parent453110303393f46a046ae13c7c2b260b2ed52705 (diff)
Extract generated blob check into its own module
Diffstat (limited to 'lib')
-rw-r--r--lib/linguist.rb1
-rw-r--r--lib/linguist/blob_helper.rb132
-rw-r--r--lib/linguist/generated.rb161
3 files changed, 165 insertions, 129 deletions
diff --git a/lib/linguist.rb b/lib/linguist.rb
index 36702e3..0f1b0f8 100644
--- a/lib/linguist.rb
+++ b/lib/linguist.rb
@@ -1,4 +1,5 @@
require 'linguist/blob_helper'
+require 'linguist/generated'
require 'linguist/language'
require 'linguist/mime'
require 'linguist/repository'
diff --git a/lib/linguist/blob_helper.rb b/lib/linguist/blob_helper.rb
index af0150c..d805df1 100644
--- a/lib/linguist/blob_helper.rb
+++ b/lib/linguist/blob_helper.rb
@@ -1,4 +1,5 @@
require 'linguist/classifier'
+require 'linguist/generated'
require 'linguist/language'
require 'linguist/mime'
require 'linguist/samples'
@@ -212,143 +213,16 @@ module Linguist
lines.grep(/\S/).size
end
- # Internal: Compute average line length.
- #
- # Returns Integer.
- def average_line_length
- if lines.any?
- lines.inject(0) { |n, l| n += l.length } / lines.length
- else
- 0
- end
- end
-
# Public: Is the blob a generated file?
#
# Generated source code is supressed in diffs and is ignored by
# language statistics.
#
- # Requires Blob#data
- #
- # Includes:
- # - XCode project XML files
- # - Minified JavaScript
- # - Compiled CoffeeScript
- # - PEG.js-generated parsers
- #
- # Please add additional test coverage to
- # `test/test_blob.rb#test_generated` if you make any changes.
+ # May load Blob#data
#
# Return true or false
def generated?
- if name == 'Gemfile.lock' || minified_javascript? || compiled_coffeescript? ||
- xcode_project_file? || generated_net_docfile? || generated_parser?
- true
- else
- false
- end
- end
-
- # Internal: Is the blob an XCode project file?
- #
- # Generated if the file extension is an XCode project
- # file extension.
- #
- # Returns true of false.
- def xcode_project_file?
- ['.xib', '.nib', '.storyboard', '.pbxproj', '.xcworkspacedata', '.xcuserstate'].include?(extname)
- end
-
- # Internal: Is the blob minified JS?
- #
- # Consider JS minified if the average line length is
- # greater then 100c.
- #
- # Returns true or false.
- def minified_javascript?
- return unless extname == '.js'
- average_line_length > 100
- end
-
- # Internal: Is the blob of JS a parser generated by PEG.js?
- #
- # Requires Blob#data
- #
- # PEG.js-generated parsers are not meant to be consumed by humans.
- #
- # Return true or false
- def generated_parser?
- return false unless extname == '.js'
-
- # PEG.js-generated parsers include a comment near the top of the file
- # that marks them as such.
- if lines[0..4].join('') =~ /^(?:[^\/]|\/[^\*])*\/\*(?:[^\*]|\*[^\/])*Generated by PEG.js/
- return true
- end
-
- false
- end
-
- # Internal: Is the blob of 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
- # output by the CS compiler.
- #
- # Return true or false
- def compiled_coffeescript?
- return false unless extname == '.js'
-
- # CoffeeScript generated by > 1.2 include a comment on the first line
- if lines[0] =~ /^\/\/ Generated by /
- return true
- end
-
- 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
-
- # Internal: Is this a generated documentation file for a .NET assembly?
- #
- # Requires Blob#data
- #
- # .NET developers often check in the XML Intellisense file along with an
- # assembly - however, these don't have a special extension, so we have to
- # dig into the contents to determine if it's a docfile. Luckily, these files
- # are extremely structured, so recognizing them is easy.
- #
- # Returns true or false
- def generated_net_docfile?
- return false unless extname.downcase == ".xml"
- return false unless lines.count > 3
-
- # .NET Docfiles always open with <doc> and their first tag is an
- # <assembly> tag
- return lines[1].include?("<doc>") &&
- lines[2].include?("<assembly>") &&
- lines[-2].include?("</doc>")
+ @_generated ||= Generated.generated?(name, lambda { data })
end
# Public: Should the blob be indexed for searching?
diff --git a/lib/linguist/generated.rb b/lib/linguist/generated.rb
new file mode 100644
index 0000000..1b05e91
--- /dev/null
+++ b/lib/linguist/generated.rb
@@ -0,0 +1,161 @@
+module Linguist
+ class Generated
+ # Public: Is the blob a generated file?
+ #
+ # name - String filename
+ # data - String blob data. A block also maybe passed in for lazy
+ # loading. This behavior is deprecated and you should always
+ # pass in a String.
+ #
+ # Return true or false
+ def self.generated?(name, data)
+ new(name, data).generated?
+ end
+
+ # Internal: Initialize Generated instance
+ #
+ # name - String filename
+ # data - String blob data
+ def initialize(name, data)
+ @name = name
+ @extname = File.extname(name)
+ @_data = data
+ end
+
+ attr_reader :name, :extname
+
+ # Lazy load blob data if block was passed in.
+ #
+ # Awful, awful stuff happening here.
+ #
+ # Returns String data.
+ def data
+ @data ||= @_data.respond_to?(:call) ? @_data.call() : @_data
+ end
+
+ # Public: Get each line of data
+ #
+ # Returns an Array of lines
+ def lines
+ @lines ||= data.split("\n", -1)
+ end
+
+ # Internal: Is the blob a generated file?
+ #
+ # Generated source code is supressed in diffs and is ignored by
+ # language statistics.
+ #
+ # Please add additional test coverage to
+ # `test/test_blob.rb#test_generated` if you make any changes.
+ #
+ # Return true or false
+ def generated?
+ name == 'Gemfile.lock' ||
+ minified_javascript? ||
+ compiled_coffeescript? ||
+ xcode_project_file? ||
+ generated_net_docfile? ||
+ generated_parser?
+ end
+
+ # Internal: Is the blob an XCode project file?
+ #
+ # Generated if the file extension is an XCode project
+ # file extension.
+ #
+ # Returns true of false.
+ def xcode_project_file?
+ ['.xib', '.nib', '.storyboard', '.pbxproj', '.xcworkspacedata', '.xcuserstate'].include?(extname)
+ end
+
+ # Internal: Is the blob minified JS?
+ #
+ # Consider JS minified if the average line length is
+ # greater then 100c.
+ #
+ # Returns true or false.
+ def minified_javascript?
+ return unless extname == '.js'
+ if lines.any?
+ (lines.inject(0) { |n, l| n += l.length } / lines.length) > 100
+ else
+ false
+ end
+ end
+
+ # Internal: Is the blob of JS generated by CoffeeScript?
+ #
+ # CoffeScript is meant to output JS that would be difficult to
+ # tell if it was generated or not. Look for a number of patterns
+ # output by the CS compiler.
+ #
+ # Return true or false
+ def compiled_coffeescript?
+ return false unless extname == '.js'
+
+ # CoffeeScript generated by > 1.2 include a comment on the first line
+ if lines[0] =~ /^\/\/ Generated by /
+ return true
+ end
+
+ 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
+
+ # Internal: Is this a generated documentation file for a .NET assembly?
+ #
+ # .NET developers often check in the XML Intellisense file along with an
+ # assembly - however, these don't have a special extension, so we have to
+ # dig into the contents to determine if it's a docfile. Luckily, these files
+ # are extremely structured, so recognizing them is easy.
+ #
+ # Returns true or false
+ def generated_net_docfile?
+ return false unless extname.downcase == ".xml"
+ return false unless lines.count > 3
+
+ # .NET Docfiles always open with <doc> and their first tag is an
+ # <assembly> tag
+ return lines[1].include?("<doc>") &&
+ lines[2].include?("<assembly>") &&
+ lines[-2].include?("</doc>")
+ end
+
+ # Internal: Is the blob of JS a parser generated by PEG.js?
+ #
+ # PEG.js-generated parsers are not meant to be consumed by humans.
+ #
+ # Return true or false
+ def generated_parser?
+ return false unless extname == '.js'
+
+ # PEG.js-generated parsers include a comment near the top of the file
+ # that marks them as such.
+ if lines[0..4].join('') =~ /^(?:[^\/]|\/[^\*])*\/\*(?:[^\*]|\*[^\/])*Generated by PEG.js/
+ return true
+ end
+
+ false
+ end
+ end
+end