licensee 9.13.1 → 9.15.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +1 -1
  3. data/bin/licensee +1 -1
  4. data/lib/licensee.rb +4 -4
  5. data/lib/licensee/commands/detect.rb +3 -5
  6. data/lib/licensee/commands/diff.rb +3 -5
  7. data/lib/licensee/content_helper.rb +46 -42
  8. data/lib/licensee/hash_helper.rb +1 -1
  9. data/lib/licensee/license.rb +29 -15
  10. data/lib/licensee/matchers.rb +1 -0
  11. data/lib/licensee/matchers/cabal.rb +1 -1
  12. data/lib/licensee/matchers/cargo.rb +1 -1
  13. data/lib/licensee/matchers/copyright.rb +3 -8
  14. data/lib/licensee/matchers/cran.rb +1 -1
  15. data/lib/licensee/matchers/dice.rb +2 -2
  16. data/lib/licensee/matchers/dist_zilla.rb +1 -1
  17. data/lib/licensee/matchers/gemspec.rb +4 -4
  18. data/lib/licensee/matchers/npm_bower.rb +5 -2
  19. data/lib/licensee/matchers/nuget.rb +43 -0
  20. data/lib/licensee/matchers/spdx.rb +1 -1
  21. data/lib/licensee/project_files/license_file.rb +29 -22
  22. data/lib/licensee/project_files/package_manager_file.rb +3 -2
  23. data/lib/licensee/project_files/project_file.rb +3 -4
  24. data/lib/licensee/project_files/readme_file.rb +1 -1
  25. data/lib/licensee/projects/fs_project.rb +8 -5
  26. data/lib/licensee/projects/git_project.rb +6 -4
  27. data/lib/licensee/projects/github_project.rb +1 -1
  28. data/lib/licensee/projects/project.rb +11 -10
  29. data/lib/licensee/version.rb +1 -1
  30. data/licensee.gemspec +7 -8
  31. data/spec/fixture_spec.rb +3 -3
  32. data/spec/fixtures/bom/LICENSE.txt +21 -0
  33. data/spec/fixtures/bsd-3-authorowner/LICENSE +27 -0
  34. data/spec/fixtures/cc-by-sa-mdlinks/License.md +173 -0
  35. data/spec/fixtures/cc-by-sa-nocclicensor/License.md +425 -0
  36. data/spec/fixtures/crlf-bsd/LICENSE.md +27 -0
  37. data/spec/fixtures/detect.json +16 -22
  38. data/spec/fixtures/eupl-cal2017/LICENSE.txt +274 -0
  39. data/spec/fixtures/fixtures.yml +62 -22
  40. data/spec/fixtures/license-hashes.json +39 -38
  41. data/spec/fixtures/markdown-artistic/LICENSE.md +192 -0
  42. data/spec/fixtures/pixar-modified-apache/LICENSE.txt +174 -0
  43. data/spec/fixtures/readme-invalid-encoding/README.md +24 -0
  44. data/spec/fixtures/vim/LICENSE +78 -0
  45. data/spec/integration_spec.rb +86 -9
  46. data/spec/licensee/commands/detect_spec.rb +2 -2
  47. data/spec/licensee/content_helper_spec.rb +21 -21
  48. data/spec/licensee/hash_helper_spec.rb +22 -22
  49. data/spec/licensee/license_meta_spec.rb +5 -11
  50. data/spec/licensee/license_spec.rb +14 -10
  51. data/spec/licensee/matchers/dice_matcher_spec.rb +4 -11
  52. data/spec/licensee/matchers/matcher_spec.rb +6 -6
  53. data/spec/licensee/matchers/npm_bower_matcher_spec.rb +9 -0
  54. data/spec/licensee/matchers/nu_get_matcher_spec.rb +91 -0
  55. data/spec/licensee/project_files/license_file_spec.rb +34 -27
  56. data/spec/licensee/project_files/package_info_spec.rb +8 -0
  57. data/spec/licensee/project_spec.rb +1 -3
  58. data/spec/licensee/rule_spec.rb +1 -1
  59. data/spec/licensee_spec.rb +1 -1
  60. data/spec/spec_helper.rb +3 -3
  61. data/spec/vendored_license_spec.rb +2 -2
  62. data/vendor/choosealicense.com/_data/meta.yml +1 -1
  63. data/vendor/choosealicense.com/_data/rules.yml +13 -13
  64. data/vendor/choosealicense.com/_licenses/0bsd.txt +3 -3
  65. data/vendor/choosealicense.com/_licenses/apache-2.0.txt +3 -3
  66. data/vendor/choosealicense.com/_licenses/bsd-2-clause.txt +3 -3
  67. data/vendor/choosealicense.com/_licenses/bsd-3-clause.txt +3 -3
  68. data/vendor/choosealicense.com/_licenses/bsd-4-clause.txt +3 -3
  69. data/vendor/choosealicense.com/_licenses/bsl-1.0.txt +3 -3
  70. data/vendor/choosealicense.com/_licenses/cc-by-4.0.txt +16 -16
  71. data/vendor/choosealicense.com/_licenses/cc-by-sa-4.0.txt +16 -16
  72. data/vendor/choosealicense.com/_licenses/cc0-1.0.txt +3 -3
  73. data/vendor/choosealicense.com/_licenses/cecill-2.1.txt +3 -3
  74. data/vendor/choosealicense.com/_licenses/ecl-2.0.txt +3 -3
  75. data/vendor/choosealicense.com/_licenses/epl-1.0.txt +3 -3
  76. data/vendor/choosealicense.com/_licenses/epl-2.0.txt +3 -3
  77. data/vendor/choosealicense.com/_licenses/eupl-1.2.txt +77 -60
  78. data/vendor/choosealicense.com/_licenses/gpl-2.0.txt +3 -3
  79. data/vendor/choosealicense.com/_licenses/gpl-3.0.txt +3 -3
  80. data/vendor/choosealicense.com/_licenses/isc.txt +3 -3
  81. data/vendor/choosealicense.com/_licenses/mit-0.txt +45 -0
  82. data/vendor/choosealicense.com/_licenses/mit.txt +3 -3
  83. data/vendor/choosealicense.com/_licenses/mpl-2.0.txt +3 -3
  84. data/vendor/choosealicense.com/_licenses/ncsa.txt +3 -3
  85. data/vendor/choosealicense.com/_licenses/odbl-1.0.txt +3 -3
  86. data/vendor/choosealicense.com/_licenses/ofl-1.1.txt +3 -3
  87. data/vendor/choosealicense.com/_licenses/osl-3.0.txt +3 -3
  88. data/vendor/choosealicense.com/_licenses/postgresql.txt +3 -3
  89. data/vendor/choosealicense.com/_licenses/unlicense.txt +3 -3
  90. data/vendor/choosealicense.com/_licenses/upl-1.0.txt +3 -3
  91. data/vendor/choosealicense.com/_licenses/vim.txt +3 -3
  92. data/vendor/choosealicense.com/_licenses/zlib.txt +3 -3
  93. data/vendor/license-list-XML/src/0BSD.xml +21 -0
  94. data/vendor/license-list-XML/src/AFL-3.0.xml +212 -0
  95. data/vendor/license-list-XML/src/AGPL-3.0.xml +852 -0
  96. data/vendor/license-list-XML/src/Apache-2.0.xml +223 -0
  97. data/vendor/license-list-XML/src/Artistic-2.0.xml +238 -0
  98. data/vendor/license-list-XML/src/BSD-2-Clause.xml +42 -0
  99. data/vendor/license-list-XML/src/BSD-3-Clause-Clear.xml +59 -0
  100. data/vendor/license-list-XML/src/BSD-3-Clause.xml +46 -0
  101. data/vendor/license-list-XML/src/BSD-4-Clause.xml +59 -0
  102. data/vendor/license-list-XML/src/BSL-1.0.xml +30 -0
  103. data/vendor/license-list-XML/src/CC-BY-4.0.xml +444 -0
  104. data/vendor/license-list-XML/src/CC-BY-SA-4.0.xml +475 -0
  105. data/vendor/license-list-XML/src/CC0-1.0.xml +153 -0
  106. data/vendor/license-list-XML/src/CECILL-2.1.xml +669 -0
  107. data/vendor/license-list-XML/src/ECL-2.0.xml +242 -0
  108. data/vendor/license-list-XML/src/EPL-1.0.xml +255 -0
  109. data/vendor/license-list-XML/src/EPL-2.0.xml +639 -0
  110. data/vendor/license-list-XML/src/EUPL-1.1.xml +337 -0
  111. data/vendor/license-list-XML/src/EUPL-1.2.xml +502 -0
  112. data/vendor/license-list-XML/src/GPL-2.0.xml +474 -0
  113. data/vendor/license-list-XML/src/GPL-3.0.xml +858 -0
  114. data/vendor/license-list-XML/src/ISC.xml +29 -0
  115. data/vendor/license-list-XML/src/LGPL-2.1.xml +662 -0
  116. data/vendor/license-list-XML/src/LGPL-3.0.xml +260 -0
  117. data/vendor/license-list-XML/src/LPPL-1.3c.xml +380 -0
  118. data/vendor/license-list-XML/src/MIT-0.xml +40 -0
  119. data/vendor/license-list-XML/src/MIT.xml +32 -0
  120. data/vendor/license-list-XML/src/MPL-2.0.xml +438 -0
  121. data/vendor/license-list-XML/src/MS-PL.xml +89 -0
  122. data/vendor/license-list-XML/src/MS-RL.xml +97 -0
  123. data/vendor/license-list-XML/src/NCSA.xml +60 -0
  124. data/vendor/license-list-XML/src/ODbL-1.0.xml +660 -0
  125. data/vendor/license-list-XML/src/OFL-1.1.xml +94 -0
  126. data/vendor/license-list-XML/src/OSL-3.0.xml +209 -0
  127. data/vendor/license-list-XML/src/PostgreSQL.xml +32 -0
  128. data/vendor/license-list-XML/src/UPL-1.0.xml +46 -0
  129. data/vendor/license-list-XML/src/Unlicense.xml +27 -0
  130. data/vendor/license-list-XML/src/Vim.xml +124 -0
  131. data/vendor/license-list-XML/src/WTFPL.xml +30 -0
  132. data/vendor/license-list-XML/src/Zlib.xml +38 -0
  133. metadata +97 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd74e74f07c0dc4111b3cbbebf62ae3ab140a788ed511491b5995d45f2371de0
4
- data.tar.gz: 90561b8b85ded55614a88e38b0469e80d110bd113e3a6ddfee9bdd840dec237a
3
+ metadata.gz: dff748195c8e0488eee7b7a9d15b90c1683059c0d52a30721f36250cdeac8935
4
+ data.tar.gz: 30f85a2b7d664c4b1345a8a76d98e8c059ef550b5b4ce878484f47f296d70a33
5
5
  SHA512:
6
- metadata.gz: bc64456f4f05411ab8152ce3ade984aa52851f39399d0bffe1e6c51fa4f9de6b00fcd84008bed0d0b71b0569a9799ba0b539ce6323fee55b4436c583ae4ce92c
7
- data.tar.gz: d797f174a17e2f91eb8f4e7c9eff9b3d4631f58531d4d57cc9da98e75e062345a52354a9ca3a8e1f991cb70a92b91e7b600814dddca345c3528742011e92c8ed
6
+ metadata.gz: 3dfa1f6ece5593ef76abf731cf3787b4e616803735f4c241c462f7081c333cee0d88da6854dcbe4bb43a6aefcd35414340f45a2cb3057ddb7d434a27acc0b461
7
+ data.tar.gz: 2444b1b8e714a4385baaeb8863bd8af26fb62b9bf31dd810e62b189158459cc0fcd23056adbdcc670df1c690f916e2f8cc3f62953704eae8b7651a624ea14613
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2014-2017 Ben Balter
3
+ Copyright (c) 2014-2021 Ben Balter and Licensee contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/bin/licensee CHANGED
@@ -19,7 +19,7 @@ class LicenseeCLI < Thor
19
19
  args.first || Dir.pwd
20
20
  else
21
21
  "https://github.com/#{args.first}"
22
- end
22
+ end
23
23
  end
24
24
 
25
25
  def project
data/lib/licensee.rb CHANGED
@@ -37,13 +37,13 @@ module Licensee
37
37
  end
38
38
 
39
39
  def project(path, **args)
40
- if path =~ %r{\Ahttps://github.com}
41
- Licensee::Projects::GitHubProject.new(path, args)
40
+ if %r{\Ahttps://github.com}.match?(path)
41
+ Licensee::Projects::GitHubProject.new(path, **args)
42
42
  else
43
- Licensee::Projects::GitProject.new(path, args)
43
+ Licensee::Projects::GitProject.new(path, **args)
44
44
  end
45
45
  rescue Licensee::Projects::GitProject::InvalidRepository
46
- Licensee::Projects::FSProject.new(path, args)
46
+ Licensee::Projects::FSProject.new(path, **args)
47
47
  end
48
48
 
49
49
  def confidence_threshold
@@ -28,11 +28,9 @@ class LicenseeCLI < Thor
28
28
  ['Licenses:', project.licenses.map(&:spdx_id)]
29
29
  else
30
30
  ['License:', set_color('None', :red)]
31
- end
31
+ end
32
32
 
33
- unless project.matched_files.empty?
34
- rows << ['Matched files:', project.matched_files.map(&:filename).join(', ')]
35
- end
33
+ rows << ['Matched files:', project.matched_files.map(&:filename).join(', ')] unless project.matched_files.empty?
36
34
 
37
35
  print_table rows
38
36
 
@@ -88,7 +86,7 @@ class LicenseeCLI < Thor
88
86
  when :confidence
89
87
  Licensee::ContentHelper.format_percent(value)
90
88
  when :method
91
- value.to_s.tr('_', ' ').capitalize + ':'
89
+ "#{value.to_s.tr('_', ' ').capitalize}:"
92
90
  else
93
91
  value
94
92
  end
@@ -41,17 +41,15 @@ class LicenseeCLI < Thor
41
41
 
42
42
  def license_to_diff
43
43
  return options[:license_to_diff] if options[:license_to_diff]
44
- return project.license_file if remote? || STDIN.tty? && project.license_file
44
+ return project.license_file if remote? || $stdin.tty? && project.license_file
45
45
 
46
46
  @license_to_diff ||= begin
47
- Licensee::ProjectFiles::LicenseFile.new(STDIN.read, 'LICENSE')
47
+ Licensee::ProjectFiles::LicenseFile.new($stdin.read, 'LICENSE')
48
48
  end
49
49
  end
50
50
 
51
51
  def expected_license
52
- if options[:license]
53
- @expected_license ||= Licensee::License.find options[:license]
54
- end
52
+ @expected_license ||= Licensee::License.find options[:license] if options[:license]
55
53
  return @expected_license if @expected_license
56
54
 
57
55
  if options[:license]
@@ -7,23 +7,24 @@ module Licensee
7
7
  module ContentHelper
8
8
  DIGEST = Digest::SHA1
9
9
  START_REGEX = /\A\s*/.freeze
10
- END_OF_TERMS_REGEX = /^[\s#*_]*end of terms and conditions\s*$/i.freeze
10
+ END_OF_TERMS_REGEX = /^[\s#*_]*end of terms and conditions[\s#*_]*$/i.freeze
11
11
  REGEXES = {
12
- hrs: /^\s*[=\-\*]{3,}\s*$/,
12
+ bom: /#{START_REGEX}\xEF\xBB\xBF/,
13
+ hrs: /^\s*[=\-*]{3,}\s*$/,
13
14
  all_rights_reserved: /#{START_REGEX}all rights reserved\.?$/i,
14
15
  whitespace: /\s+/,
15
- markdown_headings: /#{START_REGEX}#+/,
16
+ markdown_headings: /^\s*#+/,
16
17
  version: /#{START_REGEX}version.*$/i,
17
18
  span_markup: /[_*~]+(.*?)[_*~]+/,
18
19
  link_markup: /\[(.+?)\]\(.+?\)/,
19
20
  block_markup: /^\s*>/,
20
- border_markup: /^[\*-](.*?)[\*-]$/,
21
- comment_markup: %r{^\s*?[/\*]{1,2}},
21
+ border_markup: /^[*-](.*?)[*-]$/,
22
+ comment_markup: %r{^\s*?[/*]{1,2}},
22
23
  url: %r{#{START_REGEX}https?://[^ ]+\n},
23
- bullet: /\n\n\s*(?:[*-]|\(?[\da-z]{1,2}[)\.])\s+/i,
24
+ bullet: /\n\n\s*(?:[*-]|\(?[\da-z]{1,2}[).])\s+/i,
24
25
  developed_by: /#{START_REGEX}developed by:.*?\n\n/im,
25
- quote_begin: /[`'"‘“]/,
26
- quote_end: /[`'"’”]/,
26
+ cc_dedication: /The\s+text\s+of\s+the\s+Creative\s+Commons.*?Public\s+Domain\s+Dedication./im,
27
+ cc_wiki: /wiki.creativecommons.org/i,
27
28
  cc_legal_code: /^\s*Creative Commons Legal Code\s*$/i,
28
29
  cc0_info: /For more information, please see\s*\S+zero\S+/im,
29
30
  cc0_disclaimer: /CREATIVE COMMONS CORPORATION.*?\n\n/im,
@@ -35,10 +36,7 @@ module Licensee
35
36
  https: { from: /http:/, to: 'https:' },
36
37
  ampersands: { from: '&', to: 'and' },
37
38
  dashes: { from: /(?<!^)([—–-]+)(?!$)/, to: '-' },
38
- quotes: {
39
- from: /#{REGEXES[:quote_begin]}+([\w -]*?\w)#{REGEXES[:quote_end]}+/,
40
- to: '"\1"'
41
- }
39
+ quote: { from: /[`'"‘“’”]/, to: "'" }
42
40
  }.freeze
43
41
 
44
42
  # Legally equivalent words that schould be ignored for comparison
@@ -88,10 +86,10 @@ module Licensee
88
86
  'owner' => 'holder'
89
87
  }.freeze
90
88
  STRIP_METHODS = %i[
89
+ bom
90
+ cc_optional
91
91
  cc0_optional
92
92
  unlicense_optional
93
- hrs
94
- markdown_headings
95
93
  borders
96
94
  title
97
95
  version
@@ -99,8 +97,6 @@ module Licensee
99
97
  copyright
100
98
  title
101
99
  block_markup
102
- span_markup
103
- link_markup
104
100
  developed_by
105
101
  end_of_terms
106
102
  whitespace
@@ -109,35 +105,30 @@ module Licensee
109
105
 
110
106
  # A set of each word in the license, without duplicates
111
107
  def wordset
112
- @wordset ||= content_normalized&.scan(%r{(?:[\w\/](?:'s|(?<=s)')?)+})&.to_set
108
+ @wordset ||= content_normalized&.scan(%r{(?:[\w/-](?:'s|(?<=s)')?)+})&.to_set
113
109
  end
114
110
 
115
- # Number of characteres in the normalized content
111
+ # Number of characters in the normalized content
116
112
  def length
117
113
  return 0 unless content_normalized
118
114
 
119
115
  content_normalized.length
120
116
  end
121
117
 
122
- # Number of characters that could be added/removed to still be
123
- # considered a potential match
124
- def max_delta
125
- @max_delta ||= fields_normalized.size * 10 +
126
- (length * Licensee.inverse_confidence_threshold).to_i
127
- end
128
-
129
118
  # Given another license or project file, calculates the difference in length
130
119
  def length_delta(other)
131
120
  (length - other.length).abs
132
121
  end
133
122
 
134
123
  # Given another license or project file, calculates the similarity
135
- # as a percentage of words in common
124
+ # as a percentage of words in common, minus a tiny penalty that
125
+ # increases with size difference between licenses so that false
126
+ # positives for long licnses are ruled out by this score alone.
136
127
  def similarity(other)
137
128
  overlap = (wordset_fieldless & other.wordset).size
138
129
  total = wordset_fieldless.size + other.wordset.size -
139
130
  fields_normalized_set.size
140
- 100.0 * (overlap * 2.0 / total)
131
+ (overlap * 200.0) / (total + variation_adjusted_length_delta(other) / 4)
141
132
  end
142
133
 
143
134
  # SHA1 of the normalized content
@@ -152,7 +143,7 @@ module Licensee
152
143
  def content_without_title_and_version
153
144
  @content_without_title_and_version ||= begin
154
145
  @_content = nil
155
- ops = %i[html hrs comments markdown_headings title version]
146
+ ops = %i[html hrs comments markdown_headings link_markup title version]
156
147
  ops.each { |op| strip(op) }
157
148
  _content
158
149
  end
@@ -162,7 +153,7 @@ module Licensee
162
153
  @content_normalized ||= begin
163
154
  @_content = content_without_title_and_version.downcase
164
155
 
165
- (NORMALIZATIONS.keys + %i[spelling bullets]).each { |op| normalize(op) }
156
+ (NORMALIZATIONS.keys + %i[spelling span_markup bullets]).each { |op| normalize(op) }
166
157
  STRIP_METHODS.each { |op| strip(op) }
167
158
 
168
159
  _content
@@ -190,12 +181,10 @@ module Licensee
190
181
  text.gsub!(/([^\n])\n([^\n])/, '\1 \2')
191
182
 
192
183
  text = text.split("\n").collect do |line|
193
- if line =~ REGEXES[:hrs]
184
+ if line =~ REGEXES[:hrs] || line.length <= line_width
194
185
  line
195
- elsif line.length > line_width
196
- line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip
197
186
  else
198
- line
187
+ line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip
199
188
  end
200
189
  end * "\n"
201
190
 
@@ -237,9 +226,7 @@ module Licensee
237
226
  meth = "strip_#{regex_or_sym}"
238
227
  return send(meth) if respond_to?(meth, true)
239
228
 
240
- unless REGEXES[regex_or_sym]
241
- raise ArgumentError, "#{regex_or_sym} is an invalid regex reference"
242
- end
229
+ raise ArgumentError, "#{regex_or_sym} is an invalid regex reference" unless REGEXES[regex_or_sym]
243
230
 
244
231
  regex_or_sym = REGEXES[regex_or_sym]
245
232
  end
@@ -248,9 +235,7 @@ module Licensee
248
235
  end
249
236
 
250
237
  def strip_title
251
- while _content =~ ContentHelper.title_regex
252
- strip(ContentHelper.title_regex)
253
- end
238
+ strip(ContentHelper.title_regex) while _content =~ ContentHelper.title_regex
254
239
  end
255
240
 
256
241
  def strip_borders
@@ -278,6 +263,13 @@ module Licensee
278
263
  strip(REGEXES[:cc0_disclaimer])
279
264
  end
280
265
 
266
+ def strip_cc_optional
267
+ return unless _content.include? 'creative commons'
268
+
269
+ strip(REGEXES[:cc_dedication])
270
+ strip(REGEXES[:cc_wiki])
271
+ end
272
+
281
273
  def strip_unlicense_optional
282
274
  return unless _content.include? 'unlicense'
283
275
 
@@ -289,7 +281,7 @@ module Licensee
289
281
  @_content = body
290
282
  end
291
283
 
292
- def strip_span_markup
284
+ def normalize_span_markup
293
285
  normalize(REGEXES[:span_markup], '\1')
294
286
  end
295
287
 
@@ -299,7 +291,7 @@ module Licensee
299
291
 
300
292
  def strip_html
301
293
  return unless respond_to?(:filename) && filename
302
- return unless File.extname(filename) =~ /\.html?/i
294
+ return unless /\.html?/i.match?(File.extname(filename))
303
295
 
304
296
  require 'reverse_markdown'
305
297
  @_content = ReverseMarkdown.convert(_content, unknown_tags: :bypass)
@@ -323,7 +315,7 @@ module Licensee
323
315
  end
324
316
 
325
317
  def normalize_bullets
326
- normalize(REGEXES[:bullet], "\n\n* ")
318
+ normalize(REGEXES[:bullet], "\n\n- ")
327
319
  normalize(/\)\s+\(/, ')(')
328
320
  end
329
321
 
@@ -340,5 +332,17 @@ module Licensee
340
332
  def fields_normalized_set
341
333
  @fields_normalized_set ||= fields_normalized.to_set
342
334
  end
335
+
336
+ def variation_adjusted_length_delta(other)
337
+ delta = length_delta(other)
338
+
339
+ # The content helper mixin is used in different objects
340
+ # Licenses have a more advanced SPDX alt. segement-based delta.
341
+ # Use that if it's present, otherwise, just return the simple delta.
342
+ return delta unless respond_to?(:spdx_alt_segments, true)
343
+
344
+ adjusted_delta = delta - [fields_normalized.size, spdx_alt_segments].max * 4
345
+ adjusted_delta.positive? ? adjusted_delta : 0
346
+ end
343
347
  end
344
348
  end
@@ -13,7 +13,7 @@ module Licensee
13
13
  value.to_h
14
14
  else
15
15
  value
16
- end
16
+ end
17
17
  end
18
18
 
19
19
  hash
@@ -4,6 +4,7 @@ require 'uri'
4
4
 
5
5
  module Licensee
6
6
  class InvalidLicense < ArgumentError; end
7
+
7
8
  class License
8
9
  @all = {}
9
10
  @keys_licenses = {}
@@ -26,9 +27,11 @@ module Licensee
26
27
  output.reject!(&:hidden?) unless options[:hidden]
27
28
  output.reject!(&:pseudo_license?) unless options[:pseudo]
28
29
  output.sort_by!(&:key)
29
- return output if options[:featured].nil?
30
-
31
- output.select { |l| l.featured? == options[:featured] }
30
+ if options[:featured].nil?
31
+ output
32
+ else
33
+ output.select { |l| l.featured? == options[:featured] }
34
+ end
32
35
  end
33
36
  end
34
37
 
@@ -53,14 +56,17 @@ module Licensee
53
56
  end
54
57
 
55
58
  def license_dir
56
- dir = ::File.dirname(__FILE__)
57
- ::File.expand_path '../../vendor/choosealicense.com/_licenses', dir
59
+ ::File.expand_path '../../vendor/choosealicense.com/_licenses', __dir__
58
60
  end
59
61
 
60
62
  def license_files
61
63
  @license_files ||= Dir.glob("#{license_dir}/*.txt")
62
64
  end
63
65
 
66
+ def spdx_dir
67
+ ::File.expand_path '../../vendor/license-list-XML/src', __dir__
68
+ end
69
+
64
70
  private
65
71
 
66
72
  def licenses
@@ -82,7 +88,7 @@ module Licensee
82
88
  # `other` - The project had a license, but we were not able to detect it
83
89
  # `no-license` - The project is not licensed (e.g., all rights reserved)
84
90
  #
85
- # Note: A lack of detected license will be a nil license
91
+ # NOTE: A lack of detected license will be a nil license
86
92
  PSEUDO_LICENSES = %w[other no-license].freeze
87
93
 
88
94
  # Default options to use when retrieving licenses via #all
@@ -93,7 +99,7 @@ module Licensee
93
99
  }.freeze
94
100
 
95
101
  SOURCE_PREFIX = %r{https?://(?:www\.)?}i.freeze
96
- SOURCE_SUFFIX = %r{(?:\.html?|\.txt|\/)(?:\?[^\s]*)?}i.freeze
102
+ SOURCE_SUFFIX = %r{(?:\.html?|\.txt|/)(?:\?[^\s]*)?}i.freeze
97
103
 
98
104
  HASH_METHODS = %i[
99
105
  key spdx_id meta url rules fields other? gpl? lgpl? cc?
@@ -154,9 +160,7 @@ module Licensee
154
160
  key_regex = Regexp.new string, 'i'
155
161
 
156
162
  parts = [title_regex, key_regex]
157
- if meta.nickname
158
- parts.push Regexp.new meta.nickname.sub(/\bGNU /i, '(?:GNU )?')
159
- end
163
+ parts.push Regexp.new meta.nickname.sub(/\bGNU /i, '(?:GNU )?') if meta.nickname
160
164
 
161
165
  @title_regex = Regexp.union parts
162
166
  end
@@ -173,8 +177,8 @@ module Licensee
173
177
  return @source_regex if defined? @source_regex
174
178
  return unless meta.source
175
179
 
176
- source = meta.source.dup.sub(/\A#{SOURCE_PREFIX}/, '')
177
- source = source.sub(/#{SOURCE_SUFFIX}\z/, '')
180
+ source = meta.source.dup.sub(/\A#{SOURCE_PREFIX}/o, '')
181
+ source = source.sub(/#{SOURCE_SUFFIX}\z/o, '')
178
182
 
179
183
  escaped_source = Regexp.escape(source)
180
184
  @source_regex = /#{SOURCE_PREFIX}#{escaped_source}(?:#{SOURCE_SUFFIX})?/i
@@ -244,9 +248,7 @@ module Licensee
244
248
  # Raw content of license file, including YAML front matter
245
249
  def raw_content
246
250
  return if pseudo_license?
247
- unless File.exist?(path)
248
- raise Licensee::InvalidLicense, "'#{key}' is not a valid license key"
249
- end
251
+ raise Licensee::InvalidLicense, "'#{key}' is not a valid license key" unless File.exist?(path)
250
252
 
251
253
  @raw_content ||= File.read(path, encoding: 'utf-8')
252
254
  end
@@ -260,5 +262,17 @@ module Licensee
260
262
  def yaml
261
263
  @yaml ||= parts[1] if parts
262
264
  end
265
+
266
+ def spdx_alt_segments
267
+ @spdx_alt_segments ||= begin
268
+ path = File.expand_path "#{spdx_id}.xml", Licensee::License.spdx_dir
269
+ raw_xml = File.read(path, encoding: 'utf-8')
270
+ text = raw_xml.match(%r{<text>(.*)</text>}m)[1]
271
+ text.gsub!(%r{<copyrightText>.*?</copyrightText>}m, '')
272
+ text.gsub!(%r{<titleText>.*?</titleText>}m, '')
273
+ text.gsub!(%r{<optional.*?>.*?</optional>}m, '')
274
+ text.scan(/<alt .*?>/m).size
275
+ end
276
+ end
263
277
  end
264
278
  end
@@ -12,6 +12,7 @@ module Licensee
12
12
  autoload :Exact, 'licensee/matchers/exact'
13
13
  autoload :Gemspec, 'licensee/matchers/gemspec'
14
14
  autoload :NpmBower, 'licensee/matchers/npm_bower'
15
+ autoload :NuGet, 'licensee/matchers/nuget'
15
16
  autoload :Package, 'licensee/matchers/package'
16
17
  autoload :Reference, 'licensee/matchers/reference'
17
18
  autoload :Spdx, 'licensee/matchers/spdx'
@@ -5,7 +5,7 @@ module Licensee
5
5
  class Cabal < Licensee::Matchers::Package
6
6
  # While we could parse the cabal file, prefer
7
7
  # a lenient regex for speed and security. Moar parsing moar problems.
8
- LICENSE_REGEX = /^\s*license\s*\:\s*([a-z\-0-9\.]+)\s*$/ix.freeze
8
+ LICENSE_REGEX = /^\s*license\s*:\s*([a-z\-0-9.]+)\s*$/ix.freeze
9
9
  LICENSE_CONVERSIONS = {
10
10
  'GPL-2' => 'GPL-2.0',
11
11
  'GPL-3' => 'GPL-3.0',