Skip to content

Commit

Permalink
Merge pull request #2162 from github/instrumentation
Browse files Browse the repository at this point in the history
Add instrumentation to detection and classification
  • Loading branch information
arfon committed Mar 5, 2015
2 parents d81c796 + 9ceea4a commit 1da425a
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 12 deletions.
12 changes: 12 additions & 0 deletions lib/linguist.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,15 @@
require 'linguist/samples'
require 'linguist/shebang'
require 'linguist/version'

class << Linguist
attr_accessor :instrumenter

def instrument(*args, &bk)
if instrumenter
instrumenter.instrument(*args, &bk)
else
yield if block_given?
end
end
end
36 changes: 24 additions & 12 deletions lib/linguist/language.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,31 @@ def self.detect(blob)
# Bail early if the blob is binary or empty.
return nil if blob.likely_binary? || blob.binary? || blob.empty?

# Call each strategy until one candidate is returned.
STRATEGIES.reduce([]) do |languages, strategy|
candidates = strategy.call(blob, languages)
if candidates.size == 1
return candidates.first
elsif candidates.size > 1
# More than one candidate was found, pass them to the next strategy.
candidates
else
# No candiates were found, pass on languages from the previous strategy.
languages
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
end.first

Linguist.instrument("linguist.detected", :blob => blob, :strategy => returning_strategy, :language => languages.first)

languages.first
end
end

# Public: Get all Languages
Expand Down
50 changes: 50 additions & 0 deletions test/test_instrumentation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require_relative "./helper"

class TestInstrumentation < Minitest::Test
include Linguist

class LocalInstrumenter
Event = Struct.new(:name, :args)

attr_reader :events

def initialize
@events = []
end

def instrument(name, *args)
@events << Event.new(name, args)
yield if block_given?
end
end

def setup
Linguist.instrumenter = LocalInstrumenter.new
end

def teardown
Linguist.instrumenter = nil
end

def test_detection_instrumentation_with_binary_blob
binary_blob = fixture_blob("Binary/octocat.ai")
Language.detect(binary_blob)

# Shouldn't instrument this (as it's binary)
assert_equal 0, Linguist.instrumenter.events.size
end

def test_modeline_instrumentation
blob = fixture_blob("Data/Modelines/ruby")
Language.detect(blob)

detect_event = Linguist.instrumenter.events.last
detect_event_payload = detect_event[:args].first

assert_equal 3, Linguist.instrumenter.events.size
assert_equal "linguist.detected", detect_event.name
assert_equal Language['Ruby'], detect_event_payload[:language]
assert_equal blob, detect_event_payload[:blob]
assert_equal Linguist::Strategy::Modeline, detect_event_payload[:strategy]
end
end

0 comments on commit 1da425a

Please sign in to comment.