licensee 4.9.0 → 5.0.0b1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e32073ffb1db6eed03c14cee02c4d72096fc70c8
4
- data.tar.gz: f658b84856962074cebd0a310510510b7aa34dac
3
+ metadata.gz: 49baf7865bddf84e8237149cba6f21768e661c39
4
+ data.tar.gz: 95dbc39d96bed4d0952df9e85eb56ae37f387c1f
5
5
  SHA512:
6
- metadata.gz: 36b583c9dfc992f30e54425046d79f23b4522b31e470b54d61e1d08e20b146be096fdf8a684e0b45780ff487108a9bf5850452ba002883a1e8d357d316ef87c3
7
- data.tar.gz: 682553fa645a933c8bf3c2db07a29a59ff5269564aef2c58604bf17351212508e8f74f9e51388d71894f4e844c6bf52bc21dca1c6385f598695e67d4fb9cdb39
6
+ metadata.gz: 60a4c027e6d388d732ad3588606c380d90595be0955f55e9415a727370c78c8faff40c781843bc04989fb3a591821f91579079f54c2197f02778e9cac6cb73a3
7
+ data.tar.gz: 510467b863f02cdb658986dd5626460d0383c5602d22c3f170094d7d38bf80e56727691a4c8fc30dc7b4c79003a610383a90dfa4864fc87b1f3a4f83eb404012
data/bin/licensee CHANGED
@@ -3,11 +3,12 @@ require_relative "../lib/licensee"
3
3
 
4
4
  path = ARGV[0] || Dir.pwd
5
5
 
6
+ Licensee.package_manager_files = true
6
7
  project = Licensee::Project.new(path)
7
- license = project.license_file
8
+ license = project.matched_file
8
9
 
9
10
  if license
10
- puts "License file: #{license.path}"
11
+ puts "Matched file: #{license.path}"
11
12
  puts "License: #{license.match ? license.match.meta['title'] : 'no license'}"
12
13
  puts "Confidence: #{license.confidence}%"
13
14
  puts "Method: #{license.matcher.class}"
data/lib/licensee.rb CHANGED
@@ -5,15 +5,17 @@ require 'levenshtein'
5
5
 
6
6
  require_relative "licensee/version"
7
7
  require_relative "licensee/license"
8
- require_relative "licensee/licenses"
9
- require_relative "licensee/license_file"
10
8
  require_relative "licensee/project"
9
+ require_relative "licensee/project_file"
11
10
  require_relative "licensee/filesystem_repository"
12
11
  require_relative "licensee/matcher"
13
12
  require_relative "licensee/matchers/exact_matcher"
14
13
  require_relative "licensee/matchers/copyright_matcher"
15
14
  require_relative "licensee/matchers/git_matcher"
16
15
  require_relative "licensee/matchers/levenshtein_matcher"
16
+ require_relative "licensee/matchers/package_matcher"
17
+ require_relative "licensee/matchers/gemspec_matcher"
18
+ require_relative "licensee/matchers/npm_bower_matcher"
17
19
 
18
20
  class Licensee
19
21
 
@@ -25,11 +27,11 @@ class Licensee
25
27
 
26
28
  class << self
27
29
 
28
- attr_writer :confidence_threshold
30
+ attr_writer :confidence_threshold, :package_manager_files
29
31
 
30
32
  # Returns an array of Licensee::License instances
31
33
  def licenses
32
- @licenses ||= Licensee::Licenses.list
34
+ @licenses ||= Licensee::License.all
33
35
  end
34
36
 
35
37
  # Returns the license for a given git repo
@@ -45,11 +47,24 @@ class Licensee
45
47
  # Array of matchers to use, in order of preference
46
48
  # The order should be decending order of anticipated speed to match
47
49
  def matchers
48
- [Licensee::CopyrightMatcher, Licensee::ExactMatcher, Licensee::GitMatcher, Licensee::LevenshteinMatcher]
50
+ matchers = [
51
+ Licensee::CopyrightMatcher,
52
+ Licensee::ExactMatcher,
53
+ Licensee::GitMatcher,
54
+ Licensee::LevenshteinMatcher,
55
+ Licensee::GemspecMatcher,
56
+ Licensee::NpmBowerMatcher
57
+ ]
58
+ matchers.reject! { |m| m.package_manager? } unless package_manager_files?
59
+ matchers
49
60
  end
50
61
 
51
62
  def confidence_threshold
52
63
  @confidence_threshold ||= CONFIDENCE_THRESHOLD
53
64
  end
65
+
66
+ def package_manager_files?
67
+ @package_manager_files ||= false
68
+ end
54
69
  end
55
70
  end
@@ -2,16 +2,36 @@ class Licensee
2
2
  class InvalidLicense < ArgumentError; end
3
3
  class License
4
4
 
5
- def self.all
6
- Licensee::licenses
5
+ class << self
6
+ def all
7
+ @all ||= keys.map { |key| self.new(key) }
8
+ end
9
+
10
+ def keys
11
+ @keys ||= license_files.map { |l| File.basename(l, ".txt").downcase }
12
+ end
13
+
14
+ def find(key)
15
+ key = key.downcase
16
+ all.find { |l| l.key == key }
17
+ end
18
+ alias_method :[], :find
19
+
20
+ def license_dir
21
+ File.expand_path "../../vendor/choosealicense.com/_licenses", File.dirname(__FILE__)
22
+ end
23
+
24
+ def license_files
25
+ @license_files ||= Dir.glob("#{license_dir}/*.txt")
26
+ end
7
27
  end
8
28
 
9
29
  attr_reader :key
10
30
 
11
31
  YAML_DEFAULTS = {
12
32
  "featured" => false,
13
- "hidden" => false,
14
- "variant" => false
33
+ "hidden" => false,
34
+ "variant" => false
15
35
  }
16
36
 
17
37
  HIDDEN_LICENSES = %w[other no-license]
@@ -22,7 +42,7 @@ class Licensee
22
42
 
23
43
  # Path to vendored license file on disk
24
44
  def path
25
- @path ||= File.expand_path "#{@key}.txt", Licensee::Licenses.base
45
+ @path ||= File.expand_path "#{@key}.txt", Licensee::License.license_dir
26
46
  end
27
47
 
28
48
  # Raw content of license file, including YAML front matter
@@ -12,6 +12,10 @@ class Licensee
12
12
  self.new(file).match
13
13
  end
14
14
 
15
+ def self.package_manager?
16
+ false
17
+ end
18
+
15
19
  def initialize(file)
16
20
  @file = file
17
21
  end
@@ -17,7 +17,7 @@ class Licensee
17
17
  private
18
18
 
19
19
  def no_license
20
- @no_license ||= Licensee::Licenses.find("no-license")
20
+ @no_license ||= Licensee::License.find("no-license")
21
21
  end
22
22
  end
23
23
  end
@@ -0,0 +1,16 @@
1
+ class Licensee
2
+ class GemspecMatcher < PackageMatcher
3
+
4
+ # We definitely don't want to be evaling arbitrary Gemspec files
5
+ # While not 100% accurate, use some lenient regex to try to grep the
6
+ # license declaration from the Gemspec as a string, if any
7
+ LICENSE_REGEX = /^\s*[a-z0-9_]+\.license\s*\=\s*[\'\"]([a-z\-0-9\.]+)[\'\"]\s*$/i
8
+
9
+ private
10
+
11
+ def license_property
12
+ match = file.content.match LICENSE_REGEX
13
+ match[1].downcase if match && match[1]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ class Licensee
2
+ class NpmBowerMatcher < PackageMatcher
3
+
4
+ # While we could parse the package.json or bower.json file, prefer
5
+ # a lenient regex for speed and security. Moar parsing moar problems.
6
+ LICENSE_REGEX = /\s*[\"\']license[\"\']\s*\:\s*[\'\"]([a-z\-0-9\.]+)[\'\"],?\s*/i
7
+
8
+ private
9
+
10
+ def license_property
11
+ match = file.content.match LICENSE_REGEX
12
+ match[1].downcase if match && match[1]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ class Licensee
2
+ class PackageMatcher < Matcher
3
+
4
+ def match
5
+ Licensee.licenses.find { |l| l.key == license_property } if file.package?
6
+ end
7
+
8
+ def confidence
9
+ 90
10
+ end
11
+
12
+ def self.package_manager?
13
+ true
14
+ end
15
+ end
16
+ end
@@ -1,6 +1,6 @@
1
1
  class Licensee
2
2
  class Project
3
- attr_reader :repository
3
+ attr_reader :repository, :revision
4
4
 
5
5
  # Initializes a new project
6
6
  #
@@ -13,66 +13,44 @@ class Licensee
13
13
  begin
14
14
  @repository = Rugged::Repository.new(path_or_repo)
15
15
  rescue Rugged::RepositoryError
16
- if revision
17
- raise
18
- else
19
- @repository = FilesystemRepository.new(path_or_repo)
20
- end
16
+ raise if revision
17
+ @repository = FilesystemRepository.new(path_or_repo)
21
18
  end
22
19
  end
23
20
 
24
21
  @revision = revision
25
22
  end
26
23
 
27
- # Returns an instance of Licensee::LicenseFile if there's a license file detected
24
+ # Returns the matching Licensee::License instance if a license can be detected
25
+ def license
26
+ @license ||= matched_file.match if matched_file
27
+ end
28
+
28
29
  def license_file
29
- @license_file ||= LicenseFile.new(license_blob, :path => license_path) if license_blob
30
+ @license_file ||= files.select { |f| f.license? }.sort_by { |f| f.license_score }.last
30
31
  end
31
32
 
32
- # Returns the matching Licensee::License instance if a license can be detected
33
- def license
34
- @license ||= license_file.match if license_file
33
+ def package_file
34
+ return unless Licensee.package_manager_files?
35
+ @package_file ||= files.select { |f| f.package? }.sort_by { |f| f.package_score }.last
35
36
  end
36
37
 
37
- # Scores a given file as a potential license
38
- #
39
- # filename - (string) the name of the file to score
40
- #
41
- # Returns 1.0 if the file is definitely a license file
42
- # Returns 0.75 if the file is probably a license file
43
- # Returns 0.5 if the file is likely a license file
44
- # Returns 0.0 if the file is definitely not a license file
45
- def self.match_license_file(filename)
46
- return 1.0 if filename =~ /\A(un)?licen[sc]e(\.[^.]+)?\z/i
47
- return 0.75 if filename =~ /\Acopy(ing|right)(\.[^.]+)?\z/i
48
- return 0.5 if filename =~ /licen[sc]e/i
49
- return 0.0
38
+ def matched_file
39
+ license_file || package_file
50
40
  end
51
41
 
52
42
  private
53
43
 
54
44
  def commit
55
- @revision ? @repository.lookup(@revision) : @repository.last_commit
45
+ @commit ||= revision ? repository.lookup(revision) : repository.last_commit
56
46
  end
57
47
 
58
48
  def tree
59
- commit.tree.select { |blob| blob[:type] == :blob }
60
- end
61
-
62
- # Detects the license file, if any
63
- # Returns the blob hash as detected in the tree
64
- def license_hash
65
- hashes = tree.map { |blob| [self.class.match_license_file(blob[:name]), blob] }
66
- hash = hashes.select { |hash| hash[0] > 0 }.sort_by { |hash| hash[0] }.last
67
- hash[1] if hash
68
- end
69
-
70
- def license_blob
71
- @repository.lookup(license_hash[:oid]) if license_hash
49
+ @tree ||= commit.tree.select { |blob| blob[:type] == :blob }
72
50
  end
73
51
 
74
- def license_path
75
- license_hash[:name] if license_hash
52
+ def files
53
+ @files ||= tree.map { |blob| ProjectFile.new(repository.lookup(blob[:oid]), blob[:name]) }
76
54
  end
77
55
  end
78
56
  end
@@ -0,0 +1,91 @@
1
+ class Licensee
2
+ class ProjectFile
3
+
4
+ # Note: File can be a license file (e.g., `LICENSE.txt`)
5
+ # or a package manager file (e.g, `package.json`)
6
+
7
+ attr_reader :blob, :path
8
+ alias_method :filename, :path
9
+
10
+ def initialize(blob, path)
11
+ @blob = blob
12
+ @path = path
13
+ end
14
+
15
+ # Raw file contents
16
+ def content
17
+ @contents ||= blob.content.force_encoding("UTF-8")
18
+ end
19
+ alias_method :to_s, :content
20
+ alias_method :contents, :content
21
+
22
+ # File content with all whitespace replaced with a single space
23
+ def content_normalized
24
+ @content_normalized ||= content.downcase.gsub(/\s+/, " ").strip
25
+ end
26
+
27
+ # Determines which matching strategy to use, returns an instane of that matcher
28
+ def matcher
29
+ @matcher ||= Licensee.matchers.map { |m| m.new(self) }.find { |m| m.match }
30
+ end
31
+
32
+ # Returns an Licensee::License instance of the matches license
33
+ def match
34
+ @match ||= matcher.match if matcher
35
+ end
36
+
37
+ # Returns the percent confident with the match
38
+ def confidence
39
+ @condience ||= matcher.confidence if matcher
40
+ end
41
+
42
+ def similarity(other)
43
+ blob.hashsig(Rugged::Blob::HashSignature::WHITESPACE_SMART)
44
+ other.hashsig ? blob.similarity(other.hashsig) : 0
45
+ rescue Rugged::InvalidError
46
+ 0
47
+ end
48
+
49
+ # Comptutes a diff between known license and project license
50
+ def diff(options={})
51
+ options = options.merge(:reverse => true)
52
+ blob.diff(match.body, options).to_s if match
53
+ end
54
+
55
+ def license_score
56
+ self.class.license_score(filename)
57
+ end
58
+
59
+ def license?
60
+ license_score != 0.0
61
+ end
62
+
63
+ def package_score
64
+ return 1.0 if filename =~ /[a-zA-Z0-9\-_]+\.gemspec/
65
+ return 1.0 if filename =~ /package\.json/
66
+ return 0.75 if filename =~ /bower.json/
67
+ return 0.0
68
+ end
69
+
70
+ def package?
71
+ Licensee.package_manager_files? && package_score != 0.0
72
+ end
73
+
74
+ class << self
75
+ # Scores a given file as a potential license
76
+ #
77
+ # filename - (string) the name of the file to score
78
+ #
79
+ # Returns 1.0 if the file is definitely a license file
80
+ # Returns 0.75 if the file is probably a license file
81
+ # Returns 0.5 if the file is likely a license file
82
+ # Returns 0.0 if the file is definitely not a license file
83
+ def license_score(filename)
84
+ return 1.0 if filename =~ /\A(un)?licen[sc]e(\.[^.]+)?\z/i
85
+ return 0.75 if filename =~ /\Acopy(ing|right)(\.[^.]+)?\z/i
86
+ return 0.5 if filename =~ /licen[sc]e/i
87
+ return 0.0
88
+ end
89
+ end
90
+ end
91
+ end
@@ -1,3 +1,3 @@
1
1
  class Licensee
2
- VERSION = "4.9.0"
2
+ VERSION = "5.0.0b1"
3
3
  end
@@ -0,0 +1,3 @@
1
+ {
2
+ "license": "mit"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "license": "mit-1.0"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "license": "mit"
3
+ }
data/test/functions.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # Pulled from helper.rb because something in the test suite monkey patches benchmarking
2
2
 
3
3
  require 'securerandom'
4
- require 'licensee/filesystem_repository'
4
+ require_relative '../lib/licensee'
5
5
 
6
6
  def fixtures_base
7
7
  File.expand_path "fixtures", File.dirname( __FILE__ )
@@ -36,7 +36,7 @@ def verify_license_file(license, chaos = false, wrap=false)
36
36
  text = wrap(text, wrap) if wrap
37
37
 
38
38
  blob = FakeBlob.new(text)
39
- license_file = Licensee::LicenseFile.new(blob)
39
+ license_file = Licensee::ProjectFile.new(blob, "LICENSE")
40
40
 
41
41
  actual = license_file.match
42
42
  assert actual, "No match for #{expected}. Here's the test text:\n#{text}"
data/test/helper.rb CHANGED
@@ -4,7 +4,4 @@ require 'minitest/autorun'
4
4
  require 'shoulda'
5
5
  require 'open3'
6
6
  require_relative 'functions'
7
-
8
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
-
10
- require 'licensee'
7
+ require_relative '../lib/licensee'
@@ -15,13 +15,27 @@ class TestLicensee < Minitest::Test
15
15
  Licensee.diff(fixture_path("licenses.git"))
16
16
  end
17
17
 
18
- should "return the confidence threshold" do
19
- assert_equal 90, Licensee.confidence_threshold
18
+ context "confidence threshold" do
19
+ should "return the confidence threshold" do
20
+ assert_equal 90, Licensee.confidence_threshold
21
+ end
22
+
23
+ should "let the user override the confidence threshold" do
24
+ Licensee.confidence_threshold = 50
25
+ assert_equal 50, Licensee.confidence_threshold
26
+ Licensee.confidence_threshold = 90
27
+ end
20
28
  end
21
29
 
22
- should "let the user override the confidence threshold" do
23
- Licensee.confidence_threshold = 50
24
- assert_equal 50, Licensee.confidence_threshold
25
- Licensee.confidence_threshold = 90
30
+ context "npm-bower matcher" do
31
+ should "be disabled by default" do
32
+ refute Licensee.matchers.include? Licensee::NpmBowerMatcher
33
+ end
34
+
35
+ should "be enable-able" do
36
+ Licensee.package_manager_files = true
37
+ assert Licensee.matchers.include? Licensee::NpmBowerMatcher
38
+ Licensee.package_manager_files = false
39
+ end
26
40
  end
27
41
  end
@@ -6,7 +6,7 @@ class TestLicenseeBin < Minitest::Test
6
6
  Dir.chdir root
7
7
  stdout,stderr,status = Open3.capture3("#{root}/bin/licensee")
8
8
  assert stdout.include?("License: MIT"), "expected #{stdout} to include `License: MIT`"
9
- assert stdout.include?("License file: LICENSE.md"), "expected #{stdout} to include `License file: LICENSE.md`"
9
+ assert stdout.include?("Matched file: LICENSE.md"), "expected #{stdout} to include `Matched file: LICENSE.md`"
10
10
  assert_equal 0, status
11
11
  end
12
12
  end
@@ -6,7 +6,7 @@ class TestLicenseeCopyrightMatcher < Minitest::Test
6
6
  def setup
7
7
  text = "Copyright 2015 Ben Balter"
8
8
  blob = FakeBlob.new(text)
9
- @file = Licensee::LicenseFile.new(blob)
9
+ @file = Licensee::ProjectFile.new(blob, "LICENSE")
10
10
  end
11
11
 
12
12
  should "match the license" do
@@ -20,35 +20,35 @@ class TestLicenseeCopyrightMatcher < Minitest::Test
20
20
  should "match Copyright (C) copyright notices" do
21
21
  text = "Copyright (C) 2015 Ben Balter"
22
22
  blob = FakeBlob.new(text)
23
- file = Licensee::LicenseFile.new(blob)
23
+ file = Licensee::ProjectFile.new(blob, "LICENSE")
24
24
  assert_equal "no-license", Licensee::CopyrightMatcher.match(file).key
25
25
  end
26
26
 
27
27
  should "match Copyright © copyright notices" do
28
28
  text = "copyright © 2015 Ben Balter"
29
29
  blob = FakeBlob.new(text)
30
- file = Licensee::LicenseFile.new(blob)
30
+ file = Licensee::ProjectFile.new(blob, "LICENSE")
31
31
  assert_equal "no-license", Licensee::CopyrightMatcher.match(file).key
32
32
  end
33
33
 
34
34
  should "not false positive" do
35
- text = File.open(Licensee::Licenses.find("mit").path).read.split("---").last
35
+ text = File.open(Licensee::License.find("mit").path).read.split("---").last
36
36
  blob = FakeBlob.new(text)
37
- file = Licensee::LicenseFile.new(blob)
37
+ file = Licensee::ProjectFile.new(blob, "LICENSE")
38
38
  assert_equal nil, Licensee::CopyrightMatcher.match(file)
39
39
  end
40
40
 
41
41
  should "handle UTF-8 encoded copyright notices" do
42
42
  text = "Copyright (c) 2010-2014 Simon Hürlimann"
43
43
  blob = FakeBlob.new(text)
44
- file = Licensee::LicenseFile.new(blob)
44
+ file = Licensee::ProjectFile.new(blob, "LICENSE")
45
45
  assert_equal "no-license", Licensee::CopyrightMatcher.match(file).key
46
46
  end
47
47
 
48
48
  should "handle ASCII-8BIT encoded copyright notices" do
49
49
  text = "Copyright \xC2\xA92015 Ben Balter`".force_encoding("ASCII-8BIT")
50
50
  blob = FakeBlob.new(text)
51
- file = Licensee::LicenseFile.new(blob)
51
+ file = Licensee::ProjectFile.new(blob, "LICENSE")
52
52
  assert_equal "no-license", Licensee::CopyrightMatcher.match(file).key
53
53
  end
54
54
  end
@@ -3,9 +3,9 @@ require 'helper'
3
3
  class TestLicenseeExactMatcher < Minitest::Test
4
4
 
5
5
  def setup
6
- text = File.open(Licensee::Licenses.find("mit").path).read.split("---").last
6
+ text = File.open(Licensee::License.find("mit").path).read.split("---").last
7
7
  blob = FakeBlob.new(text)
8
- @mit = Licensee::LicenseFile.new(blob)
8
+ @mit = Licensee::ProjectFile.new(blob, "LICENSE")
9
9
  end
10
10
 
11
11
  should "match the license" do
@@ -0,0 +1,19 @@
1
+ require 'helper'
2
+
3
+ class TestLicenseeGemspecMatcher < Minitest::Test
4
+ def setup
5
+ Licensee.package_manager_files = true
6
+ end
7
+
8
+ def teardown
9
+ Licensee.package_manager_files = false
10
+ end
11
+
12
+ should "detect its own license" do
13
+ root = File.expand_path "../", File.dirname(__FILE__)
14
+ project = Licensee::Project.new(root)
15
+ matcher = Licensee::GemspecMatcher.new(project.package_file)
16
+ assert_equal "mit", matcher.send(:license_property)
17
+ assert_equal "mit", matcher.match.key
18
+ end
19
+ end
@@ -3,9 +3,9 @@ require 'helper'
3
3
  class TestLicenseeGitMatcher < Minitest::Test
4
4
 
5
5
  def setup
6
- text = license_from_path( Licensee::Licenses.find("mit").path )
6
+ text = license_from_path( Licensee::License.find("mit").path )
7
7
  blob = FakeBlob.new(text)
8
- @mit = Licensee::LicenseFile.new(blob)
8
+ @mit = Licensee::ProjectFile.new(blob, "LICENSE")
9
9
  end
10
10
 
11
11
  should "match the license" do
@@ -3,9 +3,9 @@ require 'helper'
3
3
  class TestLicenseeLevenshteinMatcher < Minitest::Test
4
4
 
5
5
  def setup
6
- text = license_from_path( Licensee::Licenses.find("mit").path )
6
+ text = license_from_path( Licensee::License.find("mit").path )
7
7
  blob = FakeBlob.new(text)
8
- @mit = Licensee::LicenseFile.new(blob)
8
+ @mit = Licensee::ProjectFile.new(blob, "LICENSE")
9
9
  end
10
10
 
11
11
  should "match the license" do
@@ -22,8 +22,8 @@ class TestLicenseeLevenshteinMatcher < Minitest::Test
22
22
  end
23
23
 
24
24
  should "calculate length delta" do
25
- isc = Licensee::Licenses.find("isc")
26
- assert_equal 2, Licensee::LevenshteinMatcher.new(@mit).length_delta(Licensee::Licenses.find("mit"))
25
+ isc = Licensee::License.find("isc")
26
+ assert_equal 2, Licensee::LevenshteinMatcher.new(@mit).length_delta(Licensee::License.find("mit"))
27
27
  assert_equal 334, Licensee::LevenshteinMatcher.new(@mit).length_delta(isc)
28
28
  end
29
29
 
@@ -88,4 +88,23 @@ class TestLicenseeLicense < Minitest::Test
88
88
  assert_equal "Other", license.name
89
89
  refute license.featured?
90
90
  end
91
+
92
+ describe "class methods" do
93
+ should "know license names" do
94
+ assert_equal Array, Licensee::License.keys.class
95
+ assert_equal 19, Licensee::License.keys.size
96
+ end
97
+
98
+ should "load the licenses" do
99
+ assert_equal Array, Licensee::License.all.class
100
+ assert_equal 19, Licensee::License.all.size
101
+ assert_equal Licensee::License, Licensee::License.all.first.class
102
+ end
103
+
104
+ should "find a license" do
105
+ assert_equal "mit", Licensee::License.find("mit").key
106
+ assert_equal "mit", Licensee::License.find("MIT").key
107
+ assert_equal "mit", Licensee::License["mit"].key
108
+ end
109
+ end
91
110
  end
@@ -0,0 +1,33 @@
1
+ require 'helper'
2
+
3
+ class TestLicenseeNpmBowerMatcher < Minitest::Test
4
+
5
+ def setup
6
+ Licensee.package_manager_files = true
7
+ end
8
+
9
+ def teardown
10
+ Licensee.package_manager_files = false
11
+ end
12
+
13
+ should "detect NPM files" do
14
+ project = Licensee::Project.new fixture_path "npm"
15
+ matcher = Licensee::NpmBowerMatcher.new(project.package_file)
16
+ assert_equal "mit", matcher.send(:license_property)
17
+ assert_equal "mit", matcher.match.key
18
+ end
19
+
20
+ should "detect Bower files" do
21
+ project = Licensee::Project.new fixture_path "bower"
22
+ matcher = Licensee::NpmBowerMatcher.new(project.package_file)
23
+ assert_equal "mit", matcher.send(:license_property)
24
+ assert_equal "mit", matcher.match.key
25
+ end
26
+
27
+ should "not err on non-spdx licenses" do
28
+ project = Licensee::Project.new fixture_path "npm-non-spdx"
29
+ matcher = Licensee::NpmBowerMatcher.new(project.package_file)
30
+ assert_equal "mit-1.0", matcher.send(:license_property)
31
+ assert_equal nil, matcher.match
32
+ end
33
+ end
@@ -28,7 +28,7 @@ class TestLicenseeProject < Minitest::Test
28
28
 
29
29
  should "detect the license file" do
30
30
  project = make_project "licenses.git", as_git
31
- assert_instance_of Licensee::LicenseFile, project.license_file
31
+ assert_instance_of Licensee::ProjectFile, project.license_file
32
32
  end
33
33
 
34
34
  should "detect the license" do
@@ -36,24 +36,9 @@ class TestLicenseeProject < Minitest::Test
36
36
  assert_equal "mit", project.license.key
37
37
  end
38
38
 
39
- should "return the license hash" do
40
- project = make_project "licenses.git", as_git
41
- assert_equal "LICENSE", project.send(:license_hash)[:name]
42
- end
43
-
44
- should "return the license blob" do
45
- project = make_project "licenses.git", as_git
46
- assert_equal 1077, project.send(:license_blob).size
47
- end
48
-
49
- should "return the license path" do
50
- project = make_project "licenses.git", as_git
51
- assert_equal "LICENSE", project.send(:license_path)
52
- end
53
-
54
39
  should "detect an atypically cased license file" do
55
40
  project = make_project "case-sensitive.git", as_git
56
- assert_instance_of Licensee::LicenseFile, project.license_file
41
+ assert_instance_of Licensee::ProjectFile, project.license_file
57
42
  end
58
43
 
59
44
  should "detect MIT-LICENSE licensed projects" do
@@ -83,29 +68,20 @@ class TestLicenseeProject < Minitest::Test
83
68
  end
84
69
  end
85
70
 
86
- context "license filename scoring" do
87
-
88
- EXPECTATIONS = {
89
- "license" => 1.0,
90
- "LICENCE" => 1.0,
91
- "license.md" => 1.0,
92
- "LICENSE.md" => 1.0,
93
- "license.txt" => 1.0,
94
- "unLICENSE" => 1.0,
95
- "unlicence" => 1.0,
96
- "COPYING" => 0.75,
97
- "copyRIGHT" => 0.75,
98
- "COPYRIGHT.txt" => 0.75,
99
- "LICENSE-MIT" => 0.5,
100
- "MIT-LICENSE.txt" => 0.5,
101
- "mit-license-foo.md" => 0.5,
102
- "README.txt" => 0.0
103
- }
104
-
105
- EXPECTATIONS.each do |filename, expected|
106
- should "score a license named `#{filename}` as `#{expected}`" do
107
- assert_equal expected, Licensee::Project.match_license_file(filename)
108
- end
71
+ describe "packages" do
72
+
73
+ def setup
74
+ Licensee.package_manager_files = true
75
+ end
76
+
77
+ def teardown
78
+ Licensee.package_manager_files = false
79
+ end
80
+
81
+ should "detect a package file" do
82
+ project = Licensee::Project.new fixture_path "npm"
83
+ assert_equal "package.json", project.package_file.filename
84
+ assert_equal "mit", project.license.key
109
85
  end
110
86
  end
111
87
  end
@@ -0,0 +1,59 @@
1
+ require 'helper'
2
+
3
+ class TestLicenseeProjectFile < Minitest::Test
4
+
5
+ def setup
6
+ @repo = Rugged::Repository.new(fixture_path("licenses.git"))
7
+ blob = 'bcb552d06d9cf1cd4c048a6d3bf716849c2216cc'
8
+ @file = Licensee::ProjectFile.new(@repo.lookup(blob), "LICENSE")
9
+ @gpl = Licensee::License.find "GPL-3.0"
10
+ @mit = Licensee::License.find "MIT"
11
+ end
12
+
13
+ should "read the file" do
14
+ assert @file.contents =~ /MIT/
15
+ end
16
+
17
+ should "match the license" do
18
+ assert_equal "mit", @file.match.key
19
+ end
20
+
21
+ should "know the path" do
22
+ assert_equal "LICENSE", @file.path
23
+ end
24
+
25
+ should "diff the file" do
26
+ expected = "-Copyright (c) [year] [fullname]\n+Copyright (c) 2014 Ben Balter"
27
+ assert @file.diff.include?(expected)
28
+ end
29
+
30
+ should "calculate confidence" do
31
+ assert_equal 94, @file.confidence
32
+ end
33
+
34
+ context "license filename scoring" do
35
+
36
+ EXPECTATIONS = {
37
+ "license" => 1.0,
38
+ "LICENCE" => 1.0,
39
+ "license.md" => 1.0,
40
+ "LICENSE.md" => 1.0,
41
+ "license.txt" => 1.0,
42
+ "unLICENSE" => 1.0,
43
+ "unlicence" => 1.0,
44
+ "COPYING" => 0.75,
45
+ "copyRIGHT" => 0.75,
46
+ "COPYRIGHT.txt" => 0.75,
47
+ "LICENSE-MIT" => 0.5,
48
+ "MIT-LICENSE.txt" => 0.5,
49
+ "mit-license-foo.md" => 0.5,
50
+ "README.txt" => 0.0
51
+ }
52
+
53
+ EXPECTATIONS.each do |filename, expected|
54
+ should "score a license named `#{filename}` as `#{expected}`" do
55
+ assert_equal expected, Licensee::ProjectFile.license_score(filename)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,7 +1,7 @@
1
1
  require 'helper'
2
2
 
3
3
  class TestLicenseeVendor < Minitest::Test
4
- Dir["#{Licensee::Licenses.base}/*"].shuffle.each do |license|
4
+ Licensee::License.send(:license_files).shuffle.each do |license|
5
5
 
6
6
  should "detect the #{license} license" do
7
7
  verify_license_file(license)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: licensee
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.9.0
4
+ version: 5.0.0b1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Balter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-22 00:00:00.000000000 Z
11
+ date: 2015-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rugged
@@ -109,15 +109,18 @@ files:
109
109
  - lib/licensee.rb
110
110
  - lib/licensee/filesystem_repository.rb
111
111
  - lib/licensee/license.rb
112
- - lib/licensee/license_file.rb
113
- - lib/licensee/licenses.rb
114
112
  - lib/licensee/matcher.rb
115
113
  - lib/licensee/matchers/copyright_matcher.rb
116
114
  - lib/licensee/matchers/exact_matcher.rb
115
+ - lib/licensee/matchers/gemspec_matcher.rb
117
116
  - lib/licensee/matchers/git_matcher.rb
118
117
  - lib/licensee/matchers/levenshtein_matcher.rb
118
+ - lib/licensee/matchers/npm_bower_matcher.rb
119
+ - lib/licensee/matchers/package_matcher.rb
119
120
  - lib/licensee/project.rb
121
+ - lib/licensee/project_file.rb
120
122
  - lib/licensee/version.rb
123
+ - test/fixtures/bower/bower.json
121
124
  - test/fixtures/case-sensitive.git/HEAD
122
125
  - test/fixtures/case-sensitive.git/config
123
126
  - test/fixtures/case-sensitive.git/objects/01/7b4f1eebd1dcb735e950b1d01093e3e2bf85e9
@@ -168,19 +171,22 @@ files:
168
171
  - test/fixtures/no-license.git/objects/e1/d9b2a3d41c2ea74a520e66da2b5c63b2f6202f
169
172
  - test/fixtures/no-license.git/objects/ff/1592f44259635df9feda5e02853964b26f9e4d
170
173
  - test/fixtures/no-license.git/refs/heads/master
174
+ - test/fixtures/npm-non-spdx/package.json
175
+ - test/fixtures/npm/package.json
171
176
  - test/functions.rb
172
177
  - test/helper.rb
173
178
  - test/test_licensee.rb
174
179
  - test/test_licensee_bin.rb
175
180
  - test/test_licensee_copyright_matcher.rb
176
181
  - test/test_licensee_exact_matcher.rb
182
+ - test/test_licensee_gemspec_matcher.rb
177
183
  - test/test_licensee_git_matcher.rb
178
184
  - test/test_licensee_levenshtein_matcher.rb
179
185
  - test/test_licensee_license.rb
180
- - test/test_licensee_license_file.rb
181
- - test/test_licensee_licenses.rb
182
186
  - test/test_licensee_matcher.rb
187
+ - test/test_licensee_npm_bower_matcher.rb
183
188
  - test/test_licensee_project.rb
189
+ - test/test_licensee_project_file.rb
184
190
  - test/test_licensee_vendor.rb
185
191
  - vendor/choosealicense.com/_licenses/agpl-3.0.txt
186
192
  - vendor/choosealicense.com/_licenses/apache-2.0.txt
@@ -216,9 +222,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
216
222
  version: '0'
217
223
  required_rubygems_version: !ruby/object:Gem::Requirement
218
224
  requirements:
219
- - - ">="
225
+ - - ">"
220
226
  - !ruby/object:Gem::Version
221
- version: '0'
227
+ version: 1.3.1
222
228
  requirements: []
223
229
  rubyforge_project:
224
230
  rubygems_version: 2.4.8
@@ -1,52 +0,0 @@
1
- class Licensee
2
- class LicenseFile
3
- attr_reader :blob, :path
4
-
5
- def initialize(blob, options={})
6
- @blob = blob
7
- @path = options[:path]
8
- end
9
-
10
- def similarity(other)
11
- blob.hashsig(Rugged::Blob::HashSignature::WHITESPACE_SMART)
12
- other.hashsig ? blob.similarity(other.hashsig) : 0
13
- rescue Rugged::InvalidError
14
- 0
15
- end
16
-
17
- # Raw file contents
18
- def content
19
- @contents ||= begin
20
- blob.content.force_encoding("UTF-8")
21
- end
22
- end
23
- alias_method :to_s, :content
24
- alias_method :contents, :content
25
-
26
- # File content with all whitespace replaced with a single space
27
- def content_normalized
28
- @content_normalized ||= content.downcase.gsub(/\s+/, " ").strip
29
- end
30
-
31
- # Comptutes a diff between known license and project license
32
- def diff(options={})
33
- options = options.merge(:reverse => true)
34
- blob.diff(match.body, options).to_s if match
35
- end
36
-
37
- # Determines which matching strategy to use, returns an instane of that matcher
38
- def matcher
39
- @matcher ||= Licensee.matchers.map { |m| m.new(self) }.find { |m| m.match }
40
- end
41
-
42
- # Returns an Licensee::License instance of the matches license
43
- def match
44
- @match ||= matcher.match if matcher
45
- end
46
-
47
- # Returns the percent confident with the match
48
- def confidence
49
- @condience ||= matcher.confidence if matcher
50
- end
51
- end
52
- end
@@ -1,36 +0,0 @@
1
- class Licensee
2
- class Licenses
3
- class << self
4
-
5
- # Returns an array of Licensee::License instances
6
- def list
7
- @licenses ||= begin
8
- licenses = []
9
- keys.each { |key| licenses.push License.new(key) }
10
- licenses
11
- end
12
- end
13
-
14
- # Given a license key, attempt to return a matching Licensee::License instance
15
- def find(key)
16
- list.find { |l| l.key.downcase == key.downcase }
17
- end
18
- alias_method :[], :find
19
-
20
- # Path to vendored licenses
21
- def base
22
- @base ||= File.expand_path "../../vendor/choosealicense.com/_licenses", File.dirname(__FILE__)
23
- end
24
-
25
- # Returns a list of potential license keys, as vendored
26
- def keys
27
- @keys ||= begin
28
- keyes = Dir.entries(base)
29
- keyes.map! { |l| File.basename(l, ".txt").downcase }
30
- keyes.reject! { |l| l =~ /^\./ || l.nil? }
31
- keyes
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1,33 +0,0 @@
1
- require 'helper'
2
-
3
- class TestLicenseeLicenseFile < Minitest::Test
4
-
5
- def setup
6
- @repo = Rugged::Repository.new(fixture_path("licenses.git"))
7
- blob = 'bcb552d06d9cf1cd4c048a6d3bf716849c2216cc'
8
- @file = Licensee::LicenseFile.new(@repo.lookup(blob), :path => "LICENSE")
9
- @gpl = Licensee::Licenses.find "GPL-3.0"
10
- @mit = Licensee::Licenses.find "MIT"
11
- end
12
-
13
- should "read the file" do
14
- assert @file.contents =~ /MIT/
15
- end
16
-
17
- should "match the license" do
18
- assert_equal "mit", @file.match.key
19
- end
20
-
21
- should "know the path" do
22
- assert_equal "LICENSE", @file.path
23
- end
24
-
25
- should "diff the file" do
26
- expected = "-Copyright (c) [year] [fullname]\n+Copyright (c) 2014 Ben Balter"
27
- assert @file.diff.include?(expected)
28
- end
29
-
30
- should "calculate confidence" do
31
- assert_equal 94, @file.confidence
32
- end
33
- end
@@ -1,21 +0,0 @@
1
- require 'helper'
2
-
3
- class TestLicenseeLicenses < Minitest::Test
4
-
5
- should "know license names" do
6
- assert_equal Array, Licensee::Licenses.keys.class
7
- assert_equal 19, Licensee::Licenses.keys.size
8
- end
9
-
10
- should "load the licenses" do
11
- assert_equal Array, Licensee::Licenses.list.class
12
- assert_equal 19, Licensee::Licenses.list.size
13
- assert_equal Licensee::License, Licensee::Licenses.list.first.class
14
- end
15
-
16
- should "find a license" do
17
- assert_equal "mit", Licensee::Licenses.find("mit").key
18
- assert_equal "mit", Licensee::Licenses.find("MIT").key
19
- assert_equal "mit", Licensee::Licenses["mit"].key
20
- end
21
- end