metadata-json-lint 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a8b581daaa67e2771ff6140c639af6f1329e8d73
4
- data.tar.gz: 8328a6afa75a9c140d4caea7645d1cac11c81678
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NTcyZGJkMmRhYjQ4YzU5NjYyODc3MmQ4MDcyOGQ5NWVlODA5NjFkNQ==
5
+ data.tar.gz: !binary |-
6
+ OWQ4YmQzYjQ2ZDkxNzA2MDA2NzVhZjczODg0ZWQ3OTk5YjA1OTk5ZA==
5
7
  SHA512:
6
- metadata.gz: 36fea1589e860d39f2142bdf2ccca9789faba173d2e576d8566e03f29e01b092c5748c110b76049af65d5a269e33d5c5928d330c082e742260b59145e710cbbc
7
- data.tar.gz: 226c601914ce93265675c2473589892581a804f5c5d56c7cfa725db89b139b3bc46bf018365794907f79d83579b9990c9b03a340c3eb96eec77130a7c35d3d88
8
+ metadata.gz: !binary |-
9
+ NjUzZmVlNGExZjU2ZjA1ZjFmZmU5MWU3NmNjZTc1YTNhMDNmOGIyYjM2MmFk
10
+ YWZmMjZlYjY1MzgzYzJlZDA4Yzg3ZTUyMWI0Mjk5MTUyMTU5ZTE1YzIxYjE0
11
+ N2M4MjE5MGZlZTYxNDVmMDI2ODU1OTQ3YzA0NWE3YzZiNDRhMzk=
12
+ data.tar.gz: !binary |-
13
+ NzAxYjEwZjEzOTIyZjgzNzg4ZWRkZThjMDZhZDYwMTNjNDgxMTZlYzNhMzc4
14
+ MmZlZDNkNGUzMWNmYWNiN2JmMTE2ZjJjN2Q0NDExZDA1NDA3ZTI4N2MxODFl
15
+ ZjMwNDI5ZDhlMDA2ZWY2OTA4MjExNjIyM2FjZGQ3YjllOTU3MTY=
@@ -1,15 +1,12 @@
1
1
  require 'json'
2
2
  require 'spdx-licenses'
3
3
  require 'optparse'
4
- require 'metadata-json-lint/semantic/version'
5
- require 'metadata-json-lint/semantic/version_range'
6
4
 
7
5
  module MetadataJsonLint
8
6
  def run
9
7
  options = {
10
- :fail_on_warnings => true,
11
- :strict_license => true,
12
- :strict_dependency => false
8
+ :fail_on_warnings => true,
9
+ :strict_license => true
13
10
  }
14
11
 
15
12
  OptionParser.new do |opts|
@@ -19,10 +16,6 @@ module MetadataJsonLint
19
16
  options[:strict_license] = v
20
17
  end
21
18
 
22
- opts.on("--[no-]strict-dependency", "Strict dependency version checking") do |v|
23
- options[:strict_dependency] = v
24
- end
25
-
26
19
  opts.on("--[no-]fail-on-warnings", "Fail on any warnings") do |v|
27
20
  options[:fail_on_warnings] = v
28
21
  end
@@ -70,15 +63,6 @@ module MetadataJsonLint
70
63
  dep_names << dep['name']
71
64
  end
72
65
 
73
- # Check for open endend versions in dependencies.
74
- # https://docs.puppetlabs.com/puppet/latest/reference/modules_publishing.html#dependencies-in-metadatajson
75
- deps.each do |dep|
76
- if Semantic::VersionRange.parse(dep['version_requirement']).open_end?
77
- puts "Warning: Dependency #{dep['name']} has an open ended dependency version requirement #{dep['version_requirement']}"
78
- error_state = true if @options[:strict_dependency]
79
- end
80
- end
81
-
82
66
  # Deprecated fields
83
67
  # From: https://docs.puppetlabs.com/puppet/latest/reference/modules_publishing.html#write-a-metadatajson-file
84
68
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metadata-json-lint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Spencer Krum
@@ -15,42 +15,28 @@ dependencies:
15
15
  name: spdx-licenses
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ~>
19
19
  - !ruby/object:Gem::Version
20
20
  version: '1.0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - "~>"
26
- - !ruby/object:Gem::Version
27
- version: '1.0'
28
- - !ruby/object:Gem::Dependency
29
- name: semantic
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - "~>"
33
- - !ruby/object:Gem::Version
34
- version: '1.0'
35
- type: :runtime
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - "~>"
25
+ - - ~>
40
26
  - !ruby/object:Gem::Version
41
27
  version: '1.0'
42
28
  - !ruby/object:Gem::Dependency
43
29
  name: json
44
30
  requirement: !ruby/object:Gem::Requirement
45
31
  requirements:
46
- - - ">="
32
+ - - ! '>='
47
33
  - !ruby/object:Gem::Version
48
34
  version: '0'
49
35
  type: :runtime
50
36
  prerelease: false
51
37
  version_requirements: !ruby/object:Gem::Requirement
52
38
  requirements:
53
- - - ">="
39
+ - - ! '>='
54
40
  - !ruby/object:Gem::Version
55
41
  version: '0'
56
42
  description: Utility to verify Puppet metadata.json files
@@ -60,25 +46,9 @@ executables:
60
46
  extensions: []
61
47
  extra_rdoc_files: []
62
48
  files:
63
- - ".gitignore"
64
- - Gemfile
65
- - LICENSE
66
- - README.md
67
49
  - bin/metadata-json-lint
68
50
  - lib/metadata-json-lint/rake_task.rb
69
- - lib/metadata-json-lint/semantic/version.rb
70
- - lib/metadata-json-lint/semantic/version_range.rb
71
51
  - lib/metadata_json_lint.rb
72
- - metadata-json-lint.gemspec
73
- - tests/metadata-bad_license.json
74
- - tests/metadata-broken.json
75
- - tests/metadata-duplicate-dep.json
76
- - tests/metadata-multiple_problems.json
77
- - tests/metadata-noname.json
78
- - tests/metadata-openenddep.json
79
- - tests/metadata-perfect.json
80
- - tests/metadata-types.json
81
- - tests/test.sh
82
52
  homepage: http://github.com/nibalizer/metadata-json-lint
83
53
  licenses:
84
54
  - Apache-2.0
@@ -89,12 +59,12 @@ require_paths:
89
59
  - lib
90
60
  required_ruby_version: !ruby/object:Gem::Requirement
91
61
  requirements:
92
- - - ">="
62
+ - - ! '>='
93
63
  - !ruby/object:Gem::Version
94
64
  version: '0'
95
65
  required_rubygems_version: !ruby/object:Gem::Requirement
96
66
  requirements:
97
- - - ">="
67
+ - - ! '>='
98
68
  - !ruby/object:Gem::Version
99
69
  version: '0'
100
70
  requirements: []
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- *.swp
2
- *.swo
3
- *.gem
4
- Gemfile.lock
data/Gemfile DELETED
@@ -1,3 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
data/LICENSE DELETED
@@ -1,13 +0,0 @@
1
- Copyright 2014 HP Development Corporation L.P.
2
-
3
- Licensed under the Apache License, Version 2.0 (the "License");
4
- you may not use this software except in compliance with the License.
5
- You may obtain a copy of the License at
6
-
7
- http://www.apache.org/licenses/LICENSE-2.0
8
-
9
- Unless required by applicable law or agreed to in writing, software
10
- distributed under the License is distributed on an "AS IS" BASIS,
11
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- See the License for the specific language governing permissions and
13
- limitations under the License.
data/README.md DELETED
@@ -1,62 +0,0 @@
1
- metadata-json-linter
2
- --------------------
3
-
4
- Simple tool to validate and lint metadata.json files in Puppet modules.
5
-
6
-
7
-
8
- install
9
- -------
10
-
11
- ```shell
12
- gem install metadata-json-lint
13
- ```
14
-
15
-
16
-
17
- usage
18
- -----
19
-
20
- ```shell
21
- metadata-json-lint /path/too/metadata.json
22
- ```
23
-
24
-
25
-
26
- rake
27
- ----
28
-
29
-
30
- ```ruby
31
- task :metadata do
32
- sh "metadata-json-lint metadata.json"
33
- end
34
- ```
35
-
36
-
37
-
38
- options
39
- -------
40
-
41
-
42
- ```
43
- --no-fail-on-warnings
44
- --strict-dependency
45
- --no-strict-license
46
- ```
47
-
48
-
49
-
50
- contributors
51
- ------------
52
-
53
- A Big thank you to the code contributors:
54
-
55
- Richard Pijnenburg
56
- Dominic Cleal
57
- Igor Galić
58
- Mike Arnold
59
-
60
-
61
-
62
-
@@ -1,170 +0,0 @@
1
- require 'semantic'
2
- module MetadataJsonLint
3
- module Semantic
4
-
5
- # @note Semantic::Version subclasses Numeric so that it has sane Range
6
- # semantics in Ruby 1.9+.
7
- class Version < Numeric
8
- include Comparable
9
-
10
- class ValidationFailure < ArgumentError; end
11
-
12
- class << self
13
- LOOSE_REGEX = /
14
- \A
15
- (\d+)[.](\d+)[.](\d+) # Major . Minor . Patch
16
- (?: [-](.*?))? # Prerelease
17
- (?: [+](.*?))? # Build
18
- \Z
19
- /x
20
-
21
- # Parse a Semantic Version string.
22
- #
23
- # @param ver [String] the version string to parse
24
- # @return [Version] a comparable {Version} object
25
- def parse(ver)
26
- match, major, minor, patch, prerelease, build = *ver.match(LOOSE_REGEX)
27
-
28
- if match.nil?
29
- raise 'Version numbers MUST begin with three dot-separated numbers'
30
- elsif [major, minor, patch].any? { |x| x =~ /^0\d+/ }
31
- raise 'Version numbers MUST NOT contain leading zeroes'
32
- end
33
-
34
- prerelease = parse_prerelease(prerelease) if prerelease
35
- build = parse_build_metadata(build) if build
36
-
37
- self.new(major.to_i, minor.to_i, patch.to_i, prerelease, build)
38
- end
39
-
40
- private
41
- def parse_prerelease(prerelease)
42
- subject = 'Prerelease identifiers'
43
- prerelease = prerelease.split('.', -1)
44
-
45
- if prerelease.empty? or prerelease.any? { |x| x.empty? }
46
- raise "#{subject} MUST NOT be empty"
47
- elsif prerelease.any? { |x| x =~ /[^0-9a-zA-Z-]/ }
48
- raise "#{subject} MUST use only ASCII alphanumerics and hyphens"
49
- elsif prerelease.any? { |x| x =~ /^0\d+$/ }
50
- raise "#{subject} MUST NOT contain leading zeroes"
51
- end
52
-
53
- return prerelease.map { |x| x =~ /^\d+$/ ? x.to_i : x }
54
- end
55
-
56
- def parse_build_metadata(build)
57
- subject = 'Build identifiers'
58
- build = build.split('.', -1)
59
-
60
- if build.empty? or build.any? { |x| x.empty? }
61
- raise "#{subject} MUST NOT be empty"
62
- elsif build.any? { |x| x =~ /[^0-9a-zA-Z-]/ }
63
- raise "#{subject} MUST use only ASCII alphanumerics and hyphens"
64
- end
65
-
66
- return build
67
- end
68
-
69
- def raise(msg)
70
- super ValidationFailure, msg, caller.drop_while { |x| x !~ /\bparse\b/ }
71
- end
72
- end
73
-
74
- attr_reader :major, :minor, :patch
75
-
76
- def initialize(major, minor, patch, prerelease = nil, build = nil)
77
- @major = major
78
- @minor = minor
79
- @patch = patch
80
- @prerelease = prerelease
81
- @build = build
82
- end
83
-
84
- def next(part)
85
- case part
86
- when :major
87
- self.class.new(@major.next, 0, 0)
88
- when :minor
89
- self.class.new(@major, @minor.next, 0)
90
- when :patch
91
- self.class.new(@major, @minor, @patch.next)
92
- end
93
- end
94
-
95
- def prerelease
96
- @prerelease && @prerelease.join('.')
97
- end
98
-
99
- # @return [Boolean] true if this is a stable release
100
- def stable?
101
- @prerelease.nil?
102
- end
103
-
104
- def build
105
- @build && @build.join('.')
106
- end
107
-
108
- def <=>(other)
109
- return self.major <=> other.major unless self.major == other.major
110
- return self.minor <=> other.minor unless self.minor == other.minor
111
- return self.patch <=> other.patch unless self.patch == other.patch
112
- return compare_prerelease(other)
113
- end
114
-
115
- def to_s
116
- "#{major}.#{minor}.#{patch}" +
117
- (@prerelease.nil? || prerelease.empty? ? '' : "-" + prerelease) +
118
- (@build.nil? || build.empty? ? '' : "+" + build )
119
- end
120
-
121
- def hash
122
- self.to_s.hash
123
- end
124
-
125
- private
126
- # This is a hack; tildes sort later than any valid identifier. The
127
- # advantage is that we don't need to handle stable vs. prerelease
128
- # comparisons separately.
129
- @@STABLE_RELEASE = [ '~' ].freeze
130
-
131
- def compare_prerelease(other)
132
- all_mine = @prerelease || @@STABLE_RELEASE
133
- all_yours = other.instance_variable_get(:@prerelease) || @@STABLE_RELEASE
134
-
135
- # Precedence is determined by comparing each dot separated identifier from
136
- # left to right...
137
- size = [ all_mine.size, all_yours.size ].max
138
- Array.new(size).zip(all_mine, all_yours) do |_, mine, yours|
139
-
140
- # ...until a difference is found.
141
- next if mine == yours
142
-
143
- # Numbers are compared numerically, strings are compared ASCIIbetically.
144
- if mine.class == yours.class
145
- return mine <=> yours
146
-
147
- # A larger set of pre-release fields has a higher precedence.
148
- elsif mine.nil?
149
- return -1
150
- elsif yours.nil?
151
- return 1
152
-
153
- # Numeric identifiers always have lower precedence than non-numeric.
154
- elsif mine.is_a? Numeric
155
- return -1
156
- elsif yours.is_a? Numeric
157
- return 1
158
- end
159
- end
160
-
161
- return 0
162
- end
163
-
164
- def first_prerelease
165
- self.class.new(@major, @minor, @patch, [])
166
- end
167
- end
168
- end
169
-
170
- end
@@ -1,423 +0,0 @@
1
- require 'semantic'
2
- module MetadataJsonLint
3
- module Semantic
4
- class VersionRange < Range
5
- class << self
6
- # Parses a version range string into a comparable {VersionRange} instance.
7
- #
8
- # Currently parsed version range string may take any of the following:
9
- # forms:
10
- #
11
- # * Regular Semantic Version strings
12
- # * ex. `"1.0.0"`, `"1.2.3-pre"`
13
- # * Partial Semantic Version strings
14
- # * ex. `"1.0.x"`, `"1"`, `"2.X"`
15
- # * Inequalities
16
- # * ex. `"> 1.0.0"`, `"<3.2.0"`, `">=4.0.0"`
17
- # * Approximate Versions
18
- # * ex. `"~1.0.0"`, `"~ 3.2.0"`, `"~4.0.0"`
19
- # * Inclusive Ranges
20
- # * ex. `"1.0.0 - 1.3.9"`
21
- # * Range Intersections
22
- # * ex. `">1.0.0 <=2.3.0"`
23
- #
24
- # @param range_str [String] the version range string to parse
25
- # @return [VersionRange] a new {VersionRange} instance
26
- def parse(range_str)
27
- partial = '\d+(?:[.]\d+)?(?:[.][x]|[.]\d+(?:[-][0-9a-z.-]*)?)?'
28
- exact = '\d+[.]\d+[.]\d+(?:[-][0-9a-z.-]*)?'
29
-
30
- range = range_str.gsub(/([(><=~])[ ]+/, '\1')
31
- range = range.gsub(/ - /, '#').strip
32
-
33
- return case range
34
- when /\A(#{partial})\Z/i
35
- parse_loose_version_expression($1)
36
- when /\A([><][=]?)(#{exact})\Z/i
37
- parse_inequality_expression($1, $2)
38
- when /\A~(#{partial})\Z/i
39
- parse_reasonably_close_expression($1)
40
- when /\A(#{exact})#(#{exact})\Z/i
41
- parse_inclusive_range_expression($1, $2)
42
- when /[ ]+/
43
- parse_intersection_expression(range)
44
- else
45
- raise ArgumentError
46
- end
47
-
48
- rescue ArgumentError
49
- raise ArgumentError, "Unparsable version range: #{range_str.inspect}"
50
- end
51
-
52
- private
53
-
54
- # Creates a new {VersionRange} from a range intersection expression.
55
- #
56
- # @param expr [String] a range intersection expression
57
- # @return [VersionRange] a version range representing `expr`
58
- def parse_intersection_expression(expr)
59
- expr.split(/[ ]+/).map { |x| parse(x) }.inject { |a,b| a & b }
60
- end
61
-
62
- # Creates a new {VersionRange} from a "loose" description of a Semantic
63
- # Version number.
64
- #
65
- # @see .process_loose_expr
66
- #
67
- # @param expr [String] a "loose" version expression
68
- # @return [VersionRange] a version range representing `expr`
69
- def parse_loose_version_expression(expr)
70
- start, finish = process_loose_expr(expr)
71
-
72
- if start.stable?
73
- start = start.send(:first_prerelease)
74
- end
75
-
76
- if finish.stable?
77
- exclude = true
78
- finish = finish.send(:first_prerelease)
79
- end
80
-
81
- self.new(start, finish, exclude)
82
- end
83
-
84
- # Creates an open-ended version range from an inequality expression.
85
- #
86
- # @overload parse_inequality_expression('<', expr)
87
- # {include:.parse_lt_expression}
88
- #
89
- # @overload parse_inequality_expression('<=', expr)
90
- # {include:.parse_lte_expression}
91
- #
92
- # @overload parse_inequality_expression('>', expr)
93
- # {include:.parse_gt_expression}
94
- #
95
- # @overload parse_inequality_expression('>=', expr)
96
- # {include:.parse_gte_expression}
97
- #
98
- # @param comp ['<', '<=', '>', '>='] an inequality operator
99
- # @param expr [String] a "loose" version expression
100
- # @return [VersionRange] a range covering all versions in the inequality
101
- def parse_inequality_expression(comp, expr)
102
- case comp
103
- when '>'
104
- parse_gt_expression(expr)
105
- when '>='
106
- parse_gte_expression(expr)
107
- when '<'
108
- parse_lt_expression(expr)
109
- when '<='
110
- parse_lte_expression(expr)
111
- end
112
- end
113
-
114
- # Returns a range covering all versions greater than the given `expr`.
115
- #
116
- # @param expr [String] the version to be greater than
117
- # @return [VersionRange] a range covering all versions greater than the
118
- # given `expr`
119
- def parse_gt_expression(expr)
120
- if expr =~ /^[^+]*-/
121
- start = Version.parse("#{expr}.0")
122
- else
123
- start = process_loose_expr(expr).last.send(:first_prerelease)
124
- end
125
-
126
- self.new(start, MAX_VERSION)
127
- end
128
-
129
- # Returns a range covering all versions greater than or equal to the given
130
- # `expr`.
131
- #
132
- # @param expr [String] the version to be greater than or equal to
133
- # @return [VersionRange] a range covering all versions greater than or
134
- # equal to the given `expr`
135
- def parse_gte_expression(expr)
136
- if expr =~ /^[^+]*-/
137
- start = Version.parse(expr)
138
- else
139
- start = process_loose_expr(expr).first.send(:first_prerelease)
140
- end
141
-
142
- self.new(start, MAX_VERSION)
143
- end
144
-
145
- # Returns a range covering all versions less than the given `expr`.
146
- #
147
- # @param expr [String] the version to be less than
148
- # @return [VersionRange] a range covering all versions less than the
149
- # given `expr`
150
- def parse_lt_expression(expr)
151
- if expr =~ /^[^+]*-/
152
- finish = Version.parse(expr)
153
- else
154
- finish = process_loose_expr(expr).first.send(:first_prerelease)
155
- end
156
-
157
- self.new(MIN_VERSION, finish, true)
158
- end
159
-
160
- # Returns a range covering all versions less than or equal to the given
161
- # `expr`.
162
- #
163
- # @param expr [String] the version to be less than or equal to
164
- # @return [VersionRange] a range covering all versions less than or equal
165
- # to the given `expr`
166
- def parse_lte_expression(expr)
167
- if expr =~ /^[^+]*-/
168
- finish = Version.parse(expr)
169
- self.new(MIN_VERSION, finish)
170
- else
171
- finish = process_loose_expr(expr).last.send(:first_prerelease)
172
- self.new(MIN_VERSION, finish, true)
173
- end
174
- end
175
-
176
- # The "reasonably close" expression is used to designate ranges that have
177
- # a reasonable proximity to the given "loose" version number. These take
178
- # the form:
179
- #
180
- # ~[Version]
181
- #
182
- # The general semantics of these expressions are that the given version
183
- # forms a lower bound for the range, and the upper bound is either the
184
- # next version number increment (at whatever precision the expression
185
- # provides) or the next stable version (in the case of a prerelease
186
- # version).
187
- #
188
- # @example "Reasonably close" major version
189
- # "~1" # => (>=1.0.0 <2.0.0)
190
- # @example "Reasonably close" minor version
191
- # "~1.2" # => (>=1.2.0 <1.3.0)
192
- # @example "Reasonably close" patch version
193
- # "~1.2.3" # => (1.2.3)
194
- # @example "Reasonably close" prerelease version
195
- # "~1.2.3-alpha" # => (>=1.2.3-alpha <1.2.4)
196
- #
197
- # @param expr [String] a "loose" expression to build the range around
198
- # @return [VersionRange] a "reasonably close" version range
199
- def parse_reasonably_close_expression(expr)
200
- parsed, succ = process_loose_expr(expr)
201
-
202
- if parsed.stable?
203
- parsed = parsed.send(:first_prerelease)
204
- succ = succ.send(:first_prerelease)
205
- self.new(parsed, succ, true)
206
- else
207
- self.new(parsed, succ.next(:patch).send(:first_prerelease), true)
208
- end
209
- end
210
-
211
- # An "inclusive range" expression takes two version numbers (or partial
212
- # version numbers) and creates a range that covers all versions between
213
- # them. These take the form:
214
- #
215
- # [Version] - [Version]
216
- #
217
- # @param start [String] a "loose" expresssion for the start of the range
218
- # @param finish [String] a "loose" expression for the end of the range
219
- # @return [VersionRange] a {VersionRange} covering `start` to `finish`
220
- def parse_inclusive_range_expression(start, finish)
221
- start, _ = process_loose_expr(start)
222
- _, finish = process_loose_expr(finish)
223
-
224
- start = start.send(:first_prerelease) if start.stable?
225
- if finish.stable?
226
- exclude = true
227
- finish = finish.send(:first_prerelease)
228
- end
229
-
230
- self.new(start, finish, exclude)
231
- end
232
-
233
- # A "loose expression" is one that takes the form of all or part of a
234
- # valid Semantic Version number. Particularly:
235
- #
236
- # * [Major].[Minor].[Patch]-[Prerelease]
237
- # * [Major].[Minor].[Patch]
238
- # * [Major].[Minor]
239
- # * [Major]
240
- #
241
- # Various placeholders are also permitted in "loose expressions"
242
- # (typically an 'x' or an asterisk).
243
- #
244
- # This method parses these expressions into a minimal and maximal version
245
- # number pair.
246
- #
247
- # @todo Stabilize whether the second value is inclusive or exclusive
248
- #
249
- # @param expr [String] a string containing a "loose" version expression
250
- # @return [(VersionNumber, VersionNumber)] a minimal and maximal
251
- # version pair for the given expression
252
- def process_loose_expr(expr)
253
- case expr
254
- when /^(\d+)(?:[.][xX*])?$/
255
- expr = "#{$1}.0.0"
256
- arity = :major
257
- when /^(\d+[.]\d+)(?:[.][xX*])?$/
258
- expr = "#{$1}.0"
259
- arity = :minor
260
- when /^\d+[.]\d+[.]\d+$/
261
- arity = :patch
262
- end
263
-
264
- version = next_version = Version.parse(expr)
265
-
266
- if arity
267
- next_version = version.next(arity)
268
- end
269
-
270
- [ version, next_version ]
271
- end
272
- end
273
-
274
- # Computes the intersection of a pair of ranges. If the ranges have no
275
- # useful intersection, an empty range is returned.
276
- #
277
- # @param other [VersionRange] the range to intersect with
278
- # @return [VersionRange] the common subset
279
- def intersection(other)
280
- raise NOT_A_VERSION_RANGE unless other.kind_of?(VersionRange)
281
-
282
- if self.begin < other.begin
283
- return other.intersection(self)
284
- end
285
-
286
- unless include?(other.begin) || other.include?(self.begin)
287
- return EMPTY_RANGE
288
- end
289
-
290
- endpoint = ends_before?(other) ? self : other
291
- VersionRange.new(self.begin, endpoint.end, endpoint.exclude_end?)
292
- end
293
- alias :& :intersection
294
-
295
- # Returns a string representation of this range, prefering simple common
296
- # expressions for comprehension.
297
- #
298
- # @return [String] a range expression representing this VersionRange
299
- def to_s
300
- start, finish = self.begin, self.end
301
- inclusive = exclude_end? ? '' : '='
302
-
303
- case
304
- when EMPTY_RANGE == self
305
- "<0.0.0"
306
- when exact_version?, patch_version?
307
- "#{ start }"
308
- when minor_version?
309
- "#{ start }".sub(/.0$/, '.x')
310
- when major_version?
311
- "#{ start }".sub(/.0.0$/, '.x')
312
- when open_end? && start.to_s =~ /-.*[.]0$/
313
- ">#{ start }".sub(/.0$/, '')
314
- when open_end?
315
- ">=#{ start }"
316
- when open_begin?
317
- "<#{ inclusive }#{ finish }"
318
- else
319
- ">=#{ start } <#{ inclusive }#{ finish }"
320
- end
321
- end
322
- alias :inspect :to_s
323
-
324
- # The lowest precedence Version possible
325
- MIN_VERSION = Version.new(0, 0, 0, []).freeze
326
-
327
- # The highest precedence Version possible
328
- MAX_VERSION = Version.new((1.0/0.0), 0, 0).freeze
329
-
330
- # Determines whether this {VersionRange} has an earlier endpoint than the
331
- # give `other` range.
332
- #
333
- # @param other [VersionRange] the range to compare against
334
- # @return [Boolean] true if the endpoint for this range is less than or
335
- # equal to the endpoint of the `other` range.
336
- def ends_before?(other)
337
- self.end < other.end || (self.end == other.end && self.exclude_end?)
338
- end
339
-
340
- # Describes whether this range has an upper limit.
341
- # @return [Boolean] true if this range has no upper limit
342
- def open_end?
343
- self.end == MAX_VERSION
344
- end
345
-
346
- # Describes whether this range has a lower limit.
347
- # @return [Boolean] true if this range has no lower limit
348
- def open_begin?
349
- self.begin == MIN_VERSION
350
- end
351
-
352
- # Describes whether this range follows the patterns for matching all
353
- # releases with the same exact version.
354
- # @return [Boolean] true if this range matches only a single exact version
355
- def exact_version?
356
- self.begin == self.end
357
- end
358
-
359
- # Describes whether this range follows the patterns for matching all
360
- # releases with the same major version.
361
- # @return [Boolean] true if this range matches only a single major version
362
- def major_version?
363
- start, finish = self.begin, self.end
364
-
365
- exclude_end? &&
366
- start.major.next == finish.major &&
367
- same_minor? && start.minor == 0 &&
368
- same_patch? && start.patch == 0 &&
369
- [start.prerelease, finish.prerelease] == ['', '']
370
- end
371
-
372
- # Describes whether this range follows the patterns for matching all
373
- # releases with the same minor version.
374
- # @return [Boolean] true if this range matches only a single minor version
375
- def minor_version?
376
- start, finish = self.begin, self.end
377
-
378
- exclude_end? &&
379
- same_major? &&
380
- start.minor.next == finish.minor &&
381
- same_patch? && start.patch == 0 &&
382
- [start.prerelease, finish.prerelease] == ['', '']
383
- end
384
-
385
- # Describes whether this range follows the patterns for matching all
386
- # releases with the same patch version.
387
- # @return [Boolean] true if this range matches only a single patch version
388
- def patch_version?
389
- start, finish = self.begin, self.end
390
-
391
- exclude_end? &&
392
- same_major? &&
393
- same_minor? &&
394
- start.patch.next == finish.patch &&
395
- [start.prerelease, finish.prerelease] == ['', '']
396
- end
397
-
398
- # @return [Boolean] true if `begin` and `end` share the same major verion
399
- def same_major?
400
- self.begin.major == self.end.major
401
- end
402
-
403
- # @return [Boolean] true if `begin` and `end` share the same minor verion
404
- def same_minor?
405
- self.begin.minor == self.end.minor
406
- end
407
-
408
- # @return [Boolean] true if `begin` and `end` share the same patch verion
409
- def same_patch?
410
- self.begin.patch == self.end.patch
411
- end
412
-
413
- undef :to_a
414
-
415
- NOT_A_VERSION_RANGE = ArgumentError.new("value must be a #{VersionRange}")
416
-
417
- public
418
-
419
- # A range that matches no versions
420
- EMPTY_RANGE = VersionRange.parse('< 0.0.0').freeze
421
- end
422
- end
423
- end