spdx 2.0.12 → 4.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +71 -5
- data/exceptions.json +2 -2
- data/lib/spdx.rb +69 -189
- data/lib/spdx/version.rb +1 -1
- data/lib/spdx_grammar.rb +54 -9
- data/lib/spdx_parser.rb +37 -8
- data/lib/spdx_parser.treetop +34 -17
- data/licenses.json +703 -433
- data/spdx.gemspec +1 -2
- data/spec/spdx_spec.rb +114 -199
- metadata +3 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b14167134c0066ee60871b43ae1c92508f21f923ff46c6bc71a14a556b3ed73
|
4
|
+
data.tar.gz: dcb5aa6f11173a6f88cd036911e1f97211043a8f012984fc8bc0a40311f4886b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4d00a4d70c1e83b0d5c2f3703c7037fa0f28febf7d1990b6a1e685a3237b4127cc2645e093592809c33eaff33940d83a690e14dedb0f3b19f38263de975ecaf
|
7
|
+
data.tar.gz: 0a64315cec604a279b1f8be2f1d646341e9e9a62471cb3e4d9a2bfdf4fe15a307403ecc8fe8a182a67114731a05c333e25e0a424016bae0e920151a9c69b4fc0
|
data/README.md
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
# [Spdx](http://libraries.io/rubygems/spdx) - A SPDX license
|
2
|
-
|
3
|
-
This gem allows you to find the closest match using [FuzzyMatch](https://github.com/seamusabshere/fuzzy_match) in the [spdx-licenses](https://github.com/domcleal/spdx-licenses) list for similar (not necessarily exact) license names.
|
1
|
+
# [Spdx](http://libraries.io/rubygems/spdx) - A SPDX license parser
|
4
2
|
|
3
|
+
This gem allows you validate and parse spdx expressions. It also contains (relatively) up to date license and license exception lists from https://github.com/spdx/license-list-data/tree/master/json
|
5
4
|
## Installation
|
6
5
|
|
7
6
|
Add this line to your application's Gemfile:
|
@@ -21,14 +20,81 @@ Or install it yourself as:
|
|
21
20
|
## Usage
|
22
21
|
|
23
22
|
```ruby
|
24
|
-
Spdx.
|
23
|
+
Spdx.valid?("(MIT OR AGPL-3.0+)")
|
24
|
+
=> true
|
25
|
+
```
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
Spdx.parse("MIT OR AGPL-3.0+")
|
29
|
+
=> LogicalOr+OrExpression4 offset=0, "MIT OR AGPL-3.0+":
|
30
|
+
License+LicenseId0 offset=0, "MIT" (idstring)
|
31
|
+
LicensePlus+SimpleExpression0 offset=7, "AGPL-3.0+" (license_id):
|
32
|
+
License+LicenseId0 offset=7, "AGPL-3.0" (idstring)
|
33
|
+
```
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
Spdx.normalize("Mit OR agpl-3.0+ AND APACHE-2.0")
|
37
|
+
=> "MIT OR (AGPL-3.0+ AND Apache-2.0)"
|
38
|
+
|
39
|
+
Spdx.normalize("Mit OR agpl-3.0+ AND APACHE-2.0", top_level_parens: true)
|
40
|
+
=> "(MIT OR (AGPL-3.0+ AND Apache-2.0))"
|
41
|
+
```
|
42
|
+
|
43
|
+
### Nodes
|
44
|
+
|
45
|
+
Parsed SPDX license expressions can be a number of various nodes. Each of these nodes share a few methods, most notably `text_value` which contains the text that spans that node, and `licenses` which contains an array of individual licenses used in that portion of the expression. Below are the nodes in more detail, and their additional methods.
|
46
|
+
|
47
|
+
#### `License`
|
48
|
+
|
49
|
+
This node represents a single license, and is the result of the most simple form of expression, e.g. `Spdx.parse("MIT")`. It can also be found as a child node of other nodes.
|
50
|
+
|
51
|
+
#### `LicensePlus`
|
52
|
+
|
53
|
+
This node represents the current version of a license or any later version, e.g. `Spdx.parse("CDDL-1.0+")`. The inner license node can be found via the `child` method.
|
54
|
+
|
55
|
+
#### `LicenseRef`
|
56
|
+
|
57
|
+
This node represents a reference to a license not defined in the SPDX license list, e.g. `Spdx.parse("LicenseRef-23")`.
|
58
|
+
|
59
|
+
#### `DocumentRef`
|
60
|
+
|
61
|
+
Similar to `LicenseRef`, this node also represents a reference to a license not defined in the SPDX license list, e.g. `Spdx.parse("DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2")`.
|
62
|
+
|
63
|
+
#### `LicenseException`
|
64
|
+
|
65
|
+
This node represents an exception to a license. See `With`.
|
66
|
+
|
67
|
+
#### `With`
|
68
|
+
|
69
|
+
This node represents a license with an SPDX-defined license exception, e.g. `Spdx.parse("GPL-2.0-or-later WITH Bison-exception-2.2")`. This node has two extra methods, `license` and `exception`, which return the nodes for the license portion of the expression and the exception portion of the expression, respectively.
|
70
|
+
|
71
|
+
#### `LogicalAnd`
|
72
|
+
|
73
|
+
This node represents an "AND" expression, e.g. `Spdx.parse("LGPL-2.1-only AND MIT")`. This node has two extra methods, `left` and `right`, which return the node for the left side of the expression and the node for the right side of the expression, respectively. Any node can be the child of `LogicalAnd`, including `LogicalAnd`/`LogicalOr`.
|
74
|
+
|
75
|
+
`Spdx.parse("(MIT AND GPL-1.0) OR MPL-2.0 AND Apache-2.0")` would result in the following tree:
|
76
|
+
|
77
|
+
```txt
|
78
|
+
LogicalOr
|
79
|
+
├── LogicalAnd
|
80
|
+
│ ├── License (MIT)
|
81
|
+
│ └── License (GPL-1.0)
|
82
|
+
└── LogicalAnd
|
83
|
+
├── License (MPL-2.0)
|
84
|
+
└── License Apache-2.0
|
25
85
|
```
|
26
86
|
|
87
|
+
#### `LogicalOr`
|
88
|
+
|
89
|
+
The same as `LogicalAnd`, but for "OR" expressions.
|
90
|
+
|
27
91
|
## Testing
|
28
92
|
|
29
93
|
Run the tests with:
|
30
94
|
|
31
|
-
|
95
|
+
```sh
|
96
|
+
bundle exec rspec
|
97
|
+
```
|
32
98
|
|
33
99
|
## Contributing
|
34
100
|
|
data/exceptions.json
CHANGED
data/lib/spdx.rb
CHANGED
@@ -1,187 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "spdx/version"
|
4
|
-
require "fuzzy_match"
|
5
4
|
require "spdx_parser"
|
6
5
|
require "json"
|
7
6
|
require_relative "exception"
|
8
7
|
require_relative "license"
|
9
8
|
|
10
|
-
# Fuzzy matcher for licenses to SPDX standard licenses
|
11
9
|
module Spdx
|
12
|
-
def self.find(name)
|
13
|
-
name = name.strip
|
14
|
-
return nil if commercial?(name)
|
15
|
-
return nil if non_spdx?(name)
|
16
|
-
|
17
|
-
search(name)
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.search(name)
|
21
|
-
lookup(name) ||
|
22
|
-
find_by_special_case(name) ||
|
23
|
-
closest(name)
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.commercial?(name)
|
27
|
-
name.casecmp("commercial").zero?
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.non_spdx?(name)
|
31
|
-
["standard pil license"].include? name.downcase
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.lookup(name)
|
35
|
-
return false if name.nil?
|
36
|
-
return lookup_license(name) if license_exists?(name)
|
37
|
-
|
38
|
-
lowercase = licenses.keys.sort.find { |k| k.casecmp(name).zero? }
|
39
|
-
lookup_license(lowercase) if lowercase
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.closest(name)
|
43
|
-
name.gsub!(/#{stop_words.join('|')}/i, "")
|
44
|
-
name.gsub!(/(\d)/, ' \1 ')
|
45
|
-
best_match = fuzzy_match(name)
|
46
|
-
return nil unless best_match
|
47
|
-
|
48
|
-
lookup(best_match) || find_by_name(best_match)
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.matches(name, max_distance = 40)
|
52
|
-
names.map { |key| [key, Text::Levenshtein.distance(name, key)] }
|
53
|
-
.select { |arr| arr[1] <= max_distance }
|
54
|
-
.sort_by { |arr| arr[1] }
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.fuzzy_match(name)
|
58
|
-
FuzzyMatch.new(names).find(name, must_match_at_least_one_word: true)
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.stop_words
|
62
|
-
%w[version software the or right all]
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.find_by_name(name)
|
66
|
-
match = licenses.find { |_k, v| v["name"] == name }
|
67
|
-
lookup(match[0]) if match
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.find_by_special_case(name)
|
71
|
-
gpl = gpl_match(name)
|
72
|
-
return gpl if gpl
|
73
|
-
|
74
|
-
lookup(special_cases[name.downcase.strip])
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.gpl_match(name)
|
78
|
-
match = name.match(/^(l|a)?gpl-?\s?_?v?(1|2|3)\.?(\d)?(\+)?$/i)
|
79
|
-
return unless match
|
80
|
-
|
81
|
-
lookup "#{match[1]}GPL-#{match[2]}.#{match[3] || 0}#{match[4]}"
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.special_cases
|
85
|
-
{
|
86
|
-
"perl_5" => "Artistic-1.0-Perl",
|
87
|
-
"bsd3" => "BSD-3-Clause",
|
88
|
-
"bsd" => "BSD-3-Clause",
|
89
|
-
"bsd license" => "BSD-3-Clause",
|
90
|
-
"new bsd license" => "BSD-3-Clause",
|
91
|
-
"gnu gpl v2" => "GPL-2.0-only",
|
92
|
-
"gpl" => "GPL-2.0+",
|
93
|
-
"gpl-2 | gpl-3 [expanded from: gpl (≥ 2.0)]" => "GPL-2.0+",
|
94
|
-
"gpl-2 | gpl-3 [expanded from: gpl]" => "GPL-2.0+",
|
95
|
-
"gpl-2 | gpl-3 [expanded from: gpl (≥ 2)]" => "GPL-2.0+",
|
96
|
-
"gpl-2 | gpl-3" => "GPL-2.0+",
|
97
|
-
"gplv2 or later" => "GPL-2.0+",
|
98
|
-
"the gpl v3" => "GPL-3.0",
|
99
|
-
"gpl (≥ 3)" => "GPL-3.0+",
|
100
|
-
"mpl2.0" => "mpl-2.0",
|
101
|
-
"mpl1" => "mpl-1.0",
|
102
|
-
"mpl1.0" => "mpl-1.0",
|
103
|
-
"mpl1.1" => "mpl-1.1",
|
104
|
-
"mpl2" => "mpl-2.0",
|
105
|
-
"gnu lesser general public license" => "LGPL-2.1+",
|
106
|
-
"lgplv2 or later" => "LGPL-2.1+",
|
107
|
-
"gpl2 w/ cpe" => "GPL-2.0-with-classpath-exception",
|
108
|
-
"new bsd license (gpl-compatible)" => "BSD-3-Clause",
|
109
|
-
"public domain" => "Unlicense",
|
110
|
-
"cc0" => "CC0-1.0",
|
111
|
-
"artistic_2" => "Artistic-2.0",
|
112
|
-
"artistic_1" => "Artistic-1.0",
|
113
|
-
"alv2" => "Apache-2.0",
|
114
|
-
"asl" => "Apache-2.0",
|
115
|
-
"asl 2.0" => "Apache-2.0",
|
116
|
-
"mpl 2.0" => "MPL-2.0",
|
117
|
-
"publicdomain" => "Unlicense",
|
118
|
-
"unlicensed" => "Unlicense",
|
119
|
-
"psfl" => "Python-2.0",
|
120
|
-
"psf" => "Python-2.0",
|
121
|
-
"psf 2" => "Python-2.0",
|
122
|
-
"psf 2.0" => "Python-2.0",
|
123
|
-
"asl2" => "Apache-2.0",
|
124
|
-
"al2" => "Apache-2.0",
|
125
|
-
"aslv2" => "Apache-2.0",
|
126
|
-
"apache_2_0" => "Apache-2.0",
|
127
|
-
"apache_v2" => "Apache-2.0",
|
128
|
-
"zpl 1.1" => "ZPL-1.1",
|
129
|
-
"zpl 2.0" => "ZPL-2.0",
|
130
|
-
"zpl 2.1" => "ZPL-2.1",
|
131
|
-
"lgpl_2_1" => "LGPL-2.1",
|
132
|
-
"lgpl_v2_1" => "LGPL-2.1",
|
133
|
-
"lgpl version 3" => "LGPL-3.0",
|
134
|
-
"gnu lgpl v3+" => "LGPL-3.0",
|
135
|
-
"gnu lgpl" => "LGPL-2.1+",
|
136
|
-
"cc by-sa 4.0" => "CC-BY-SA-4.0",
|
137
|
-
"cc by-nc-sa 3.0" => "CC-BY-NC-SA-3.0",
|
138
|
-
"cc by-sa 3.0" => "CC-BY-SA-3.0",
|
139
|
-
"mpl v2.0" => "MPL-2.0",
|
140
|
-
"mplv2.0" => "MPL-2.0",
|
141
|
-
"mplv2" => "MPL-2.0",
|
142
|
-
"cpal v1.0" => "CPAL-1.0",
|
143
|
-
"cddl 1.0" => "CDDL-1.0",
|
144
|
-
"cddl 1.1" => "CDDL-1.1",
|
145
|
-
"epl" => "EPL-1.0",
|
146
|
-
"mit-license" => "MIT",
|
147
|
-
"(mit or x11)" => "MIT",
|
148
|
-
"iscl" => "ISC",
|
149
|
-
"wtf" => "WTFPL",
|
150
|
-
"2-clause bsdl" => "BSD-2-clause",
|
151
|
-
"3-clause bsdl" => "BSD-3-clause",
|
152
|
-
"2-clause bsd" => "BSD-2-clause",
|
153
|
-
"3-clause bsd" => "BSD-3-clause",
|
154
|
-
"bsd 3-clause" => "BSD-3-clause",
|
155
|
-
"bsd 2-clause" => "BSD-2-clause",
|
156
|
-
"two-clause bsd-style license" => "BSD-2-clause",
|
157
|
-
"bsd style" => "BSD-3-clause",
|
158
|
-
"cc0 1.0 universal (cc0 1.0) public domain dedication" => "CC0-1.0",
|
159
|
-
"common development and distribution license 1.0 (cddl-1.0)" => "CDDL-1.0",
|
160
|
-
"european union public licence 1.0 (eupl 1.0)" => "EUPL-1.0",
|
161
|
-
"european union public licence 1.1 (eupl 1.1)" => "EUPL-1.1",
|
162
|
-
"european union public licence 1.2 (eupl 1.2)" => "EUPL-1.2",
|
163
|
-
"vovida software license 1.0" => "VSL-1.0",
|
164
|
-
"w3c license" => "W3C",
|
165
|
-
"zlib/libpng license" => "zlib-acknowledgement",
|
166
|
-
"gnu general public license (gpl)" => "GPL-2.0+",
|
167
|
-
"gnu general public license v2 (gplv2)" => "GPL-2.0",
|
168
|
-
"gnu general public license v2 or later (gplv2+)" => "GPL-2.0+",
|
169
|
-
"gnu general public license v3 (gplv3)" => "GPL-3.0",
|
170
|
-
"gnu general public license v3 or later (gplv3+)" => "GPL-3.0+",
|
171
|
-
"gnu lesser general public license v2 (lgplv2)" => "LGPL-2.0",
|
172
|
-
"gnu lesser general public license v2 or later (lgplv2+)" => "LGPL-2.0+",
|
173
|
-
"gnu lesser general public license v3 (lgplv3)" => "LGPL-3.0",
|
174
|
-
"gnu lesser general public license v3 or later (lgplv3+)" => "LGPL-3.0+",
|
175
|
-
"gnu library or lesser general public license (lgpl)" => "LGPL-2.0+",
|
176
|
-
"netscape public License (npl)" => "NPL-1.1",
|
177
|
-
"apache software license" => "Apache-2.0",
|
178
|
-
"academic free license (afl)" => "AFL-3.0",
|
179
|
-
"gnu free documentation license (fdl)" => "GFDL-1.3",
|
180
|
-
"sun industry standards source license (sissl)" => "SISSL-1.2",
|
181
|
-
"zope public license" => "ZPL-2.1",
|
182
|
-
}
|
183
|
-
end
|
184
|
-
|
185
10
|
def self.names
|
186
11
|
(licenses.keys + licenses.map { |_k, v| v["name"] }).sort
|
187
12
|
end
|
@@ -190,6 +15,7 @@ module Spdx
|
|
190
15
|
unless defined?(@exceptions)
|
191
16
|
data = JSON.parse(File.read(File.expand_path("../exceptions.json", __dir__)))
|
192
17
|
@exceptions = {}
|
18
|
+
|
193
19
|
data["exceptions"].each do |details|
|
194
20
|
id = details.delete("licenseExceptionId")
|
195
21
|
@exceptions[id] = details
|
@@ -199,27 +25,18 @@ module Spdx
|
|
199
25
|
end
|
200
26
|
|
201
27
|
def self.license_exists?(id)
|
202
|
-
licenses.key?(id.to_s)
|
203
|
-
end
|
204
|
-
|
205
|
-
def self.lookup_license(id)
|
206
|
-
json = licenses[id.to_s]
|
207
|
-
Spdx::License.new(id.to_s, json["name"], json["isOsiApproved"]) if json
|
208
|
-
end
|
209
|
-
|
210
|
-
def self.lookup_exception(id)
|
211
|
-
json = exceptions[id.to_s]
|
212
|
-
Spdx::Exception.new(id.to_s, json["name"], json["isDeprecatedLicenseId"]) if json
|
28
|
+
licenses.key?(id.to_s) || licenses_downcase.key?(id.to_s.downcase)
|
213
29
|
end
|
214
30
|
|
215
31
|
def self.exception_exists?(id)
|
216
|
-
exceptions.key?(id.to_s)
|
32
|
+
exceptions.key?(id.to_s) || exceptions_downcase.key?(id.to_s.downcase)
|
217
33
|
end
|
218
34
|
|
219
35
|
def self.licenses
|
220
36
|
unless defined?(@licenses)
|
221
37
|
data = JSON.parse(File.read(File.expand_path("../licenses.json", __dir__)))
|
222
38
|
@licenses = {}
|
39
|
+
|
223
40
|
data["licenses"].each do |details|
|
224
41
|
id = details.delete("licenseId")
|
225
42
|
@licenses[id] = details
|
@@ -228,7 +45,70 @@ module Spdx
|
|
228
45
|
@licenses
|
229
46
|
end
|
230
47
|
|
231
|
-
def self.
|
48
|
+
def self.licenses_downcase
|
49
|
+
unless defined?(@licenses_downcase)
|
50
|
+
@licenses_downcase = {}
|
51
|
+
licenses.keys.each { |key| @licenses_downcase[key.downcase] = key }
|
52
|
+
end
|
53
|
+
@licenses_downcase
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.exceptions_downcase
|
57
|
+
unless defined?(@exceptions_downcase)
|
58
|
+
@exceptions_downcase = {}
|
59
|
+
exceptions.keys.each { |key| @exceptions_downcase[key.downcase] = key }
|
60
|
+
end
|
61
|
+
@exceptions_downcase
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.normalize(spdx_string, top_level_parens: false)
|
65
|
+
normalize_tree(SpdxParser.parse(spdx_string), parens: top_level_parens)
|
66
|
+
end
|
67
|
+
|
68
|
+
private_class_method def self.normalize_tree(node, parens: true)
|
69
|
+
case node
|
70
|
+
when SpdxGrammar::LogicalAnd
|
71
|
+
left = normalize_tree(node.left)
|
72
|
+
right = normalize_tree(node.right)
|
73
|
+
if parens
|
74
|
+
"(#{left} AND #{right})"
|
75
|
+
else
|
76
|
+
"#{left} AND #{right}"
|
77
|
+
end
|
78
|
+
when SpdxGrammar::LogicalOr
|
79
|
+
left = normalize_tree(node.left)
|
80
|
+
right = normalize_tree(node.right)
|
81
|
+
if parens
|
82
|
+
"(#{left} OR #{right})"
|
83
|
+
else
|
84
|
+
"#{left} OR #{right}"
|
85
|
+
end
|
86
|
+
when SpdxGrammar::With
|
87
|
+
license = normalize_tree(node.license)
|
88
|
+
exception = normalize_tree(node.exception)
|
89
|
+
if parens
|
90
|
+
"(#{license} WITH #{exception})"
|
91
|
+
else
|
92
|
+
"#{license} WITH #{exception}"
|
93
|
+
end
|
94
|
+
when SpdxGrammar::None
|
95
|
+
"NONE"
|
96
|
+
when SpdxGrammar::NoAssertion
|
97
|
+
"NOASSERTION"
|
98
|
+
when SpdxGrammar::License
|
99
|
+
licenses_downcase[node.text_value.downcase]
|
100
|
+
when SpdxGrammar::LicensePlus
|
101
|
+
"#{normalize_tree(node.child)}+"
|
102
|
+
when SpdxGrammar::LicenseRef
|
103
|
+
node.text_value
|
104
|
+
when SpdxGrammar::DocumentRef
|
105
|
+
node.text_value
|
106
|
+
when SpdxGrammar::LicenseException
|
107
|
+
exceptions_downcase[node.text_value.downcase]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.valid?(spdx_string)
|
232
112
|
return false unless spdx_string.is_a?(String)
|
233
113
|
|
234
114
|
SpdxParser.parse(spdx_string)
|
@@ -237,7 +117,7 @@ module Spdx
|
|
237
117
|
false
|
238
118
|
end
|
239
119
|
|
240
|
-
def self.
|
120
|
+
def self.parse(spdx_string)
|
241
121
|
SpdxParser.parse(spdx_string)
|
242
122
|
end
|
243
123
|
end
|
data/lib/spdx/version.rb
CHANGED
data/lib/spdx_grammar.rb
CHANGED
@@ -1,19 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SpdxGrammar
|
4
|
-
class
|
4
|
+
class LogicalBinary < Treetop::Runtime::SyntaxNode
|
5
|
+
# Used internally
|
6
|
+
|
5
7
|
def licenses
|
6
|
-
|
8
|
+
(left.licenses + right.licenses).uniq
|
9
|
+
end
|
10
|
+
|
11
|
+
def left
|
12
|
+
elements[0]
|
13
|
+
end
|
14
|
+
|
15
|
+
def right
|
16
|
+
elements[1]
|
7
17
|
end
|
8
18
|
end
|
9
19
|
|
10
|
-
class
|
20
|
+
class LogicalAnd < LogicalBinary
|
11
21
|
end
|
12
22
|
|
13
|
-
class
|
23
|
+
class LogicalOr < LogicalBinary
|
14
24
|
end
|
15
25
|
|
16
26
|
class With < Treetop::Runtime::SyntaxNode
|
27
|
+
def licenses
|
28
|
+
license.licenses
|
29
|
+
end
|
30
|
+
|
31
|
+
def license
|
32
|
+
elements[0]
|
33
|
+
end
|
34
|
+
|
35
|
+
def exception
|
36
|
+
elements[1]
|
37
|
+
end
|
17
38
|
end
|
18
39
|
|
19
40
|
class None < Treetop::Runtime::SyntaxNode
|
@@ -30,20 +51,44 @@ module SpdxGrammar
|
|
30
51
|
|
31
52
|
class License < Treetop::Runtime::SyntaxNode
|
32
53
|
def licenses
|
33
|
-
text_value
|
54
|
+
[text_value]
|
34
55
|
end
|
35
56
|
end
|
36
57
|
|
37
|
-
class
|
38
|
-
|
58
|
+
class LicensePlus < Treetop::Runtime::SyntaxNode
|
59
|
+
def licenses
|
60
|
+
child.licenses
|
61
|
+
end
|
62
|
+
|
63
|
+
def child
|
64
|
+
elements[0]
|
65
|
+
end
|
39
66
|
end
|
40
67
|
|
41
|
-
class
|
68
|
+
class LicenseRef < Treetop::Runtime::SyntaxNode
|
42
69
|
def licenses
|
43
|
-
|
70
|
+
[text_value]
|
44
71
|
end
|
45
72
|
end
|
46
73
|
|
74
|
+
class DocumentRef < Treetop::Runtime::SyntaxNode
|
75
|
+
def licenses
|
76
|
+
[text_value]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class LicenseException < Treetop::Runtime::SyntaxNode
|
81
|
+
# TODO: actually do license exceptions
|
82
|
+
end
|
83
|
+
|
84
|
+
class GroupedExpression < Treetop::Runtime::SyntaxNode
|
85
|
+
# Used internally
|
86
|
+
end
|
87
|
+
|
88
|
+
class Operand < Treetop::Runtime::SyntaxNode
|
89
|
+
# Used internally
|
90
|
+
end
|
91
|
+
|
47
92
|
class SpdxParseError < StandardError
|
48
93
|
end
|
49
94
|
end
|