Skip to content

Commit

Permalink
Merge pull request github-linguist#2341 from github/api-changes
Browse files Browse the repository at this point in the history
Move Linguist::Language.detect to Linguist.detect
  • Loading branch information
arfon committed Mar 17, 2016
2 parents 0f76774 + 924fddf commit 1efd4c8
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 41 deletions.
78 changes: 78 additions & 0 deletions lib/linguist.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,91 @@
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)
elsif block_given?
yield
end
end

end
4 changes: 2 additions & 2 deletions lib/linguist/blob_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

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.
Expand Down Expand Up @@ -325,7 +325,7 @@ def generated?
#
# 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
Expand Down
38 changes: 2 additions & 36 deletions lib/linguist/language.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,49 +87,15 @@ def self.create(attributes = {})
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;
# see Linguist::LazyBlob and Linguist::FileBlob for examples
#
# 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
Expand Down
2 changes: 1 addition & 1 deletion test/test_heuristics.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def assert_heuristics(hash)

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

Expand Down
4 changes: 2 additions & 2 deletions test/test_instrumentation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ def teardown

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
end

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
Expand Down

0 comments on commit 1efd4c8

Please sign in to comment.