From 924fddf69892537322188fab6a23c787c1bfc363 Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Fri, 17 Apr 2015 14:56:08 +1200 Subject: [PATCH] Move Linguist::Language.detect to Linguist.detect --- lib/linguist.rb | 78 ++++++++++++++++++++++++++++++++++++ lib/linguist/blob_helper.rb | 4 +- lib/linguist/language.rb | 38 +----------------- test/test_heuristics.rb | 2 +- test/test_instrumentation.rb | 4 +- 5 files changed, 85 insertions(+), 41 deletions(-) diff --git a/lib/linguist.rb b/lib/linguist.rb index 3929efb9..f0680ea6 100644 --- a/lib/linguist.rb +++ b/lib/linguist.rb @@ -8,8 +8,85 @@ require 'linguist/shebang' require 'linguist/version' class << Linguist + # Public: Detects the Language of the blob. + # + # blob - an object that includes the Linguist `BlobHelper` interface; + # see Linguist::LazyBlob and Linguist::FileBlob for examples + # + # Returns Language or nil. + def detect(blob) + # Bail early if the blob is binary or empty. + return nil if blob.likely_binary? || blob.binary? || blob.empty? + + Linguist.instrument("linguist.detection", :blob => blob) do + # Call each strategy until one candidate is returned. + languages = [] + returning_strategy = nil + + STRATEGIES.each do |strategy| + returning_strategy = strategy + candidates = Linguist.instrument("linguist.strategy", :blob => blob, :strategy => strategy, :candidates => languages) do + strategy.call(blob, languages) + end + if candidates.size == 1 + languages = candidates + break + elsif candidates.size > 1 + # More than one candidate was found, pass them to the next strategy. + languages = candidates + else + # No candidates, try the next strategy + end + end + + Linguist.instrument("linguist.detected", :blob => blob, :strategy => returning_strategy, :language => languages.first) + + languages.first + end + end + + # Internal: The strategies used to detect the language of a file. + # + # A strategy is an object that has a `.call` method that takes two arguments: + # + # blob - An object that quacks like a blob. + # languages - An Array of candidate Language objects that were returned by the + #     previous strategy. + # + # A strategy should return an Array of Language candidates. + # + # Strategies are called in turn until a single Language is returned. + STRATEGIES = [ + Linguist::Strategy::Modeline, + Linguist::Shebang, + Linguist::Strategy::Filename, + Linguist::Heuristics, + Linguist::Classifier + ] + + # Public: Set an instrumenter. + # + # class CustomInstrumenter + # def instrument(name, payload = {}) + # warn "Instrumenting #{name}: #{payload[:blob]}" + # end + # end + # + # Linguist.instrumenter = CustomInstrumenter + # + # The instrumenter must conform to the `ActiveSupport::Notifications` + # interface, which defines `#instrument` and accepts: + # + # name - the String name of the event (e.g. "linguist.detected") + # payload - a Hash of the exception context. attr_accessor :instrumenter + # Internal: Perform instrumentation on a block + # + # Linguist.instrument("linguist.dosomething", :blob => blob) do + # # logic to instrument here. + # end + # def instrument(*args, &bk) if instrumenter instrumenter.instrument(*args, &bk) @@ -17,4 +94,5 @@ class << Linguist yield if block_given? end end + end diff --git a/lib/linguist/blob_helper.rb b/lib/linguist/blob_helper.rb index 01a567e0..a1565646 100644 --- a/lib/linguist/blob_helper.rb +++ b/lib/linguist/blob_helper.rb @@ -6,7 +6,7 @@ require 'yaml' module Linguist # DEPRECATED Avoid mixing into Blob classes. Prefer functional interfaces - # like `Language.detect` over `Blob#language`. Functions are much easier to + # like `Linguist.detect` over `Blob#language`. Functions are much easier to # cache and compose. # # Avoid adding additional bloat to this module. @@ -325,7 +325,7 @@ module Linguist # # Returns a Language or nil if none is detected def language - @language ||= Language.detect(self) + @language ||= Linguist.detect(self) end # Internal: Get the TextMate compatible scope for the blob diff --git a/lib/linguist/language.rb b/lib/linguist/language.rb index da02b110..f7d7772d 100644 --- a/lib/linguist/language.rb +++ b/lib/linguist/language.rb @@ -87,14 +87,6 @@ module Linguist language end - STRATEGIES = [ - Linguist::Strategy::Modeline, - Linguist::Shebang, - Linguist::Strategy::Filename, - Linguist::Heuristics, - Linguist::Classifier - ] - # Public: Detects the Language of the blob. # # blob - an object that includes the Linguist `BlobHelper` interface; @@ -102,34 +94,8 @@ module Linguist # # Returns Language or nil. def self.detect(blob) - # Bail early if the blob is binary or empty. - return nil if blob.likely_binary? || blob.binary? || blob.empty? - - Linguist.instrument("linguist.detection", :blob => blob) do - # Call each strategy until one candidate is returned. - languages = [] - returning_strategy = nil - - STRATEGIES.each do |strategy| - returning_strategy = strategy - candidates = Linguist.instrument("linguist.strategy", :blob => blob, :strategy => strategy, :candidates => languages) do - strategy.call(blob, languages) - end - if candidates.size == 1 - languages = candidates - break - elsif candidates.size > 1 - # More than one candidate was found, pass them to the next strategy. - languages = candidates - else - # No candidates, try the next strategy - end - end - - Linguist.instrument("linguist.detected", :blob => blob, :strategy => returning_strategy, :language => languages.first) - - languages.first - end + warn "[DEPRECATED] `Linguist::Language.detect` is deprecated. Use `Linguist.detect`. #{caller[0]}" + Linguist.detect(blob) end # Public: Get all Languages diff --git a/test/test_heuristics.rb b/test/test_heuristics.rb index b3197c69..0f7c0cf4 100644 --- a/test/test_heuristics.rb +++ b/test/test_heuristics.rb @@ -40,7 +40,7 @@ class TestHeuristcs < Minitest::Test def test_detect_still_works_if_nothing_matches blob = Linguist::FileBlob.new(File.join(samples_path, "Objective-C/hello.m")) - match = Language.detect(blob) + match = Linguist.detect(blob) assert_equal Language["Objective-C"], match end diff --git a/test/test_instrumentation.rb b/test/test_instrumentation.rb index ab0615e5..d2eedad8 100644 --- a/test/test_instrumentation.rb +++ b/test/test_instrumentation.rb @@ -28,7 +28,7 @@ class TestInstrumentation < Minitest::Test def test_detection_instrumentation_with_binary_blob binary_blob = fixture_blob("Binary/octocat.ai") - Language.detect(binary_blob) + Linguist.detect(binary_blob) # Shouldn't instrument this (as it's binary) assert_equal 0, Linguist.instrumenter.events.size @@ -36,7 +36,7 @@ class TestInstrumentation < Minitest::Test def test_modeline_instrumentation blob = fixture_blob("Data/Modelines/ruby") - Language.detect(blob) + Linguist.detect(blob) detect_event = Linguist.instrumenter.events.last detect_event_payload = detect_event[:args].first