versionian 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/README.adoc +874 -0
- data/Rakefile +12 -0
- data/docs/Gemfile +8 -0
- data/docs/_guides/custom-schemes.adoc +110 -0
- data/docs/_guides/index.adoc +12 -0
- data/docs/_pages/component-types.adoc +151 -0
- data/docs/_pages/declarative-schemes.adoc +260 -0
- data/docs/_pages/index.adoc +15 -0
- data/docs/_pages/range-matching.adoc +102 -0
- data/docs/_pages/schemes.adoc +68 -0
- data/docs/_references/api.adoc +251 -0
- data/docs/_references/index.adoc +13 -0
- data/docs/_references/schemes.adoc +410 -0
- data/docs/_tutorials/getting-started.adoc +119 -0
- data/docs/_tutorials/index.adoc +11 -0
- data/docs/index.adoc +287 -0
- data/lib/versionian/component_definition.rb +71 -0
- data/lib/versionian/component_types/base.rb +19 -0
- data/lib/versionian/component_types/date_part.rb +41 -0
- data/lib/versionian/component_types/enum.rb +32 -0
- data/lib/versionian/component_types/float.rb +23 -0
- data/lib/versionian/component_types/hash.rb +21 -0
- data/lib/versionian/component_types/integer.rb +23 -0
- data/lib/versionian/component_types/postfix.rb +51 -0
- data/lib/versionian/component_types/prerelease.rb +70 -0
- data/lib/versionian/component_types/registry.rb +35 -0
- data/lib/versionian/component_types/string.rb +21 -0
- data/lib/versionian/errors/invalid_scheme_error.rb +7 -0
- data/lib/versionian/errors/invalid_version_error.rb +7 -0
- data/lib/versionian/errors/parse_error.rb +7 -0
- data/lib/versionian/parsers/declarative.rb +214 -0
- data/lib/versionian/scheme_loader.rb +102 -0
- data/lib/versionian/scheme_registry.rb +34 -0
- data/lib/versionian/schemes/calver.rb +94 -0
- data/lib/versionian/schemes/composite.rb +82 -0
- data/lib/versionian/schemes/declarative.rb +138 -0
- data/lib/versionian/schemes/pattern.rb +236 -0
- data/lib/versionian/schemes/semantic.rb +136 -0
- data/lib/versionian/schemes/solover.rb +121 -0
- data/lib/versionian/schemes/wendtver.rb +141 -0
- data/lib/versionian/version.rb +6 -0
- data/lib/versionian/version_component.rb +28 -0
- data/lib/versionian/version_identifier.rb +121 -0
- data/lib/versionian/version_range.rb +61 -0
- data/lib/versionian/version_scheme.rb +68 -0
- data/lib/versionian.rb +64 -0
- data/lib/versius.rb +5 -0
- data/sig/versius.rbs +4 -0
- metadata +157 -0
data/Rakefile
ADDED
data/docs/Gemfile
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Custom Schemes
|
|
4
|
+
nav_order: 1
|
|
5
|
+
parent: Guides
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
= Creating Custom Schemes
|
|
9
|
+
|
|
10
|
+
== General
|
|
11
|
+
|
|
12
|
+
You can create custom versioning schemes by subclassing `Versionian::VersionScheme` or using declarative YAML configuration.
|
|
13
|
+
|
|
14
|
+
== Declarative YAML approach
|
|
15
|
+
|
|
16
|
+
For most custom schemes, the declarative YAML approach is recommended:
|
|
17
|
+
|
|
18
|
+
[source,yaml]
|
|
19
|
+
----
|
|
20
|
+
. Example scheme defined at `my_scheme.yaml`
|
|
21
|
+
----
|
|
22
|
+
[source,yaml]
|
|
23
|
+
----
|
|
24
|
+
name: my_yaml_scheme
|
|
25
|
+
type: declarative
|
|
26
|
+
description: My custom version scheme
|
|
27
|
+
components:
|
|
28
|
+
- name: major
|
|
29
|
+
type: integer
|
|
30
|
+
separator: "."
|
|
31
|
+
- name: minor
|
|
32
|
+
type: integer
|
|
33
|
+
separator: "."
|
|
34
|
+
- name: patch
|
|
35
|
+
type: integer
|
|
36
|
+
----
|
|
37
|
+
|
|
38
|
+
[source,ruby]
|
|
39
|
+
----
|
|
40
|
+
scheme = Versionian::SchemeLoader.from_yaml_file('my_scheme.yaml')
|
|
41
|
+
Versionian.register_scheme(:my_scheme, scheme)
|
|
42
|
+
|
|
43
|
+
version = scheme.parse("1.2.3")
|
|
44
|
+
puts version.major # => 1
|
|
45
|
+
puts version.minor # => 2
|
|
46
|
+
----
|
|
47
|
+
|
|
48
|
+
== Ruby class approach
|
|
49
|
+
|
|
50
|
+
For complex versioning schemes, you can create custom scheme classes in Ruby.
|
|
51
|
+
|
|
52
|
+
[source,ruby]
|
|
53
|
+
----
|
|
54
|
+
class FloatVerScheme < Versionian::VersionScheme
|
|
55
|
+
def initialize(name: :floatver, description: "Float-based versioning")
|
|
56
|
+
super
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def parse(version_string)
|
|
60
|
+
float_value = Float(version_string)
|
|
61
|
+
Versionian::VersionIdentifier.new(
|
|
62
|
+
raw_string: version_string,
|
|
63
|
+
scheme: self,
|
|
64
|
+
components: [],
|
|
65
|
+
comparable_array: [float_value]
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def compare_arrays(a, b)
|
|
70
|
+
a.first <=> b.first # Direct float comparison
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def render(version)
|
|
74
|
+
version.raw_string
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Register and use
|
|
79
|
+
Versionian.register_scheme(:floatver, FloatVerScheme.new)
|
|
80
|
+
----
|
|
81
|
+
|
|
82
|
+
== Required methods
|
|
83
|
+
|
|
84
|
+
A custom scheme must implement:
|
|
85
|
+
|
|
86
|
+
[cols="2,3"]
|
|
87
|
+
|===
|
|
88
|
+
|Method |Description
|
|
89
|
+
|
|
90
|
+
|#parse(string)
|
|
91
|
+
|Parse version string and return VersionIdentifier
|
|
92
|
+
|
|
93
|
+
|#compare_arrays(a, b)
|
|
94
|
+
|Compare two comparable arrays
|
|
95
|
+
|
|
96
|
+
|#valid?(string)
|
|
97
|
+
|Check if string is valid for this scheme
|
|
98
|
+
|===
|
|
99
|
+
|
|
100
|
+
== Registering custom schemes
|
|
101
|
+
|
|
102
|
+
[source,ruby]
|
|
103
|
+
----
|
|
104
|
+
# Register with Versionian
|
|
105
|
+
Versionian.register_scheme(:my_scheme, MyScheme.new)
|
|
106
|
+
|
|
107
|
+
# Use like built-in schemes
|
|
108
|
+
scheme = Versionian.get_scheme(:my_scheme)
|
|
109
|
+
version = scheme.parse("1.2.3")
|
|
110
|
+
----
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Component Types
|
|
4
|
+
nav_order: 3
|
|
5
|
+
parent: Core Topics
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
= Component Types
|
|
9
|
+
|
|
10
|
+
== Overview
|
|
11
|
+
|
|
12
|
+
Versionian provides an extensible component type system that allows different versioning
|
|
13
|
+
schemes to parse and compare version components according to their specific rules.
|
|
14
|
+
|
|
15
|
+
== Built-in Component Types
|
|
16
|
+
|
|
17
|
+
=== Integer
|
|
18
|
+
|
|
19
|
+
Numeric sequence components (major, minor, patch, etc.)
|
|
20
|
+
|
|
21
|
+
[source,ruby]
|
|
22
|
+
----
|
|
23
|
+
component = Versionian::ComponentTypes::Integer.parse("42", definition)
|
|
24
|
+
component.value # => 42
|
|
25
|
+
|
|
26
|
+
# Comparison is numeric
|
|
27
|
+
component.to_comparable(42, definition) # => 42
|
|
28
|
+
----
|
|
29
|
+
|
|
30
|
+
=== Float
|
|
31
|
+
|
|
32
|
+
IEEE754 floating point numbers.
|
|
33
|
+
|
|
34
|
+
[source,ruby]
|
|
35
|
+
----
|
|
36
|
+
component = Versionian::ComponentTypes::Float.parse("3.14", definition)
|
|
37
|
+
component.value # => 3.14
|
|
38
|
+
----
|
|
39
|
+
|
|
40
|
+
=== String
|
|
41
|
+
|
|
42
|
+
Arbitrary text components.
|
|
43
|
+
|
|
44
|
+
[source,ruby]
|
|
45
|
+
----
|
|
46
|
+
component = Versionian::ComponentTypes::String.parse("beta", definition)
|
|
47
|
+
component.value # => "beta"
|
|
48
|
+
----
|
|
49
|
+
|
|
50
|
+
=== Enum
|
|
51
|
+
|
|
52
|
+
Ordered stages (alpha, beta, rc, stable, etc.)
|
|
53
|
+
|
|
54
|
+
[source,ruby]
|
|
55
|
+
----
|
|
56
|
+
definition = Versionian::ComponentDefinition.new(
|
|
57
|
+
name: :stage,
|
|
58
|
+
type: :enum,
|
|
59
|
+
values: [:alpha, :beta, :rc, :stable],
|
|
60
|
+
order: [:alpha, :beta, :rc, :stable]
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
component = Versionian::ComponentTypes::Enum.parse("beta", definition)
|
|
64
|
+
component.value # => :beta
|
|
65
|
+
|
|
66
|
+
# Comparison uses order array index
|
|
67
|
+
component.to_comparable(:beta, definition) # => 1
|
|
68
|
+
component.to_comparable(:rc, definition) # => 2
|
|
69
|
+
----
|
|
70
|
+
|
|
71
|
+
=== DatePart
|
|
72
|
+
|
|
73
|
+
Calendar components (year, month, day, week, etc.) with range validation.
|
|
74
|
+
|
|
75
|
+
[source,ruby]
|
|
76
|
+
----
|
|
77
|
+
definition = Versionian::ComponentDefinition.new(
|
|
78
|
+
name: :month,
|
|
79
|
+
type: :date_part,
|
|
80
|
+
subtype: :month
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
component = Versionian::ComponentTypes::DatePart.parse("06", definition)
|
|
84
|
+
component.value # => 6
|
|
85
|
+
|
|
86
|
+
# Validates ranges (month: 1-12, day: 1-31, etc.)
|
|
87
|
+
----
|
|
88
|
+
|
|
89
|
+
=== Prerelease
|
|
90
|
+
|
|
91
|
+
SemVer-style prerelease identifiers (alpha.1, beta.2, etc.)
|
|
92
|
+
|
|
93
|
+
[source,ruby]
|
|
94
|
+
----
|
|
95
|
+
component = Versionian::ComponentTypes::Prerelease.parse("alpha.1", definition)
|
|
96
|
+
component.value # => [:alpha, 1]
|
|
97
|
+
|
|
98
|
+
# Comparison follows SemVer rules
|
|
99
|
+
component.to_comparable(:alpha.1, definition) # => [:alpha, 1]
|
|
100
|
+
----
|
|
101
|
+
|
|
102
|
+
=== Postfix
|
|
103
|
+
|
|
104
|
+
SoloVer-style postfixes (+hotfix, -beta, etc.)
|
|
105
|
+
|
|
106
|
+
[source,ruby]
|
|
107
|
+
----
|
|
108
|
+
component = Versionian::ComponentTypes::Postfix.parse("+hotfix", definition)
|
|
109
|
+
component.value # => {prefix: "+", identifier: "hotfix"}
|
|
110
|
+
----
|
|
111
|
+
|
|
112
|
+
=== Hash
|
|
113
|
+
|
|
114
|
+
Git commit hashes or similar identifiers.
|
|
115
|
+
|
|
116
|
+
[source,ruby]
|
|
117
|
+
----
|
|
118
|
+
component = Versionian::ComponentTypes::Hash.parse("abc123def", definition)
|
|
119
|
+
component.value # => "abc123def"
|
|
120
|
+
|
|
121
|
+
# Compares by length first, then lexicographically
|
|
122
|
+
component.to_comparable("abc123def", definition) # => [9, "abc123def"]
|
|
123
|
+
----
|
|
124
|
+
|
|
125
|
+
== Custom Component Types
|
|
126
|
+
|
|
127
|
+
You can register your own component types:
|
|
128
|
+
|
|
129
|
+
[source,ruby]
|
|
130
|
+
----
|
|
131
|
+
module Versionian
|
|
132
|
+
module ComponentTypes
|
|
133
|
+
class CustomType < Base
|
|
134
|
+
def self.parse(value, definition)
|
|
135
|
+
# Parse logic here
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def self.to_comparable(value, definition)
|
|
139
|
+
# Return comparable value
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def self.format(value)
|
|
143
|
+
# Format for display
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Register the type
|
|
150
|
+
Versionian::ComponentTypes.register(:custom, Versionian::ComponentTypes::CustomType)
|
|
151
|
+
----
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Declarative Schemes
|
|
4
|
+
nav_order: 2
|
|
5
|
+
parent: Core Topics
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
= Declarative Schemes
|
|
9
|
+
|
|
10
|
+
== General
|
|
11
|
+
|
|
12
|
+
Declarative schemes define version formats using segment definitions instead of regular expressions. Each component specifies its type, separator, prefix, and optional status, allowing the parser to extract components in O(n) time.
|
|
13
|
+
|
|
14
|
+
Benefits over regex-based patterns:
|
|
15
|
+
|
|
16
|
+
* **No ReDoS vulnerabilities** - State machine parsing is immune to catastrophic backtracking
|
|
17
|
+
* **O(n) performance** - Single pass through the string
|
|
18
|
+
* **Declarative syntax** - Clear, readable component definitions
|
|
19
|
+
* **Type-aware parsing** - Each component type handles its own validation
|
|
20
|
+
|
|
21
|
+
== YAML schema
|
|
22
|
+
|
|
23
|
+
[source,yaml]
|
|
24
|
+
----
|
|
25
|
+
name: my_scheme <1>
|
|
26
|
+
type: declarative <2>
|
|
27
|
+
description: Custom scheme <3>
|
|
28
|
+
components: <4>
|
|
29
|
+
- name: major
|
|
30
|
+
type: integer
|
|
31
|
+
separator: "." <5>
|
|
32
|
+
- name: minor
|
|
33
|
+
type: integer
|
|
34
|
+
separator: "." <6>
|
|
35
|
+
- name: patch
|
|
36
|
+
type: integer <7>
|
|
37
|
+
----
|
|
38
|
+
<1> Unique scheme identifier (symbol).
|
|
39
|
+
<2> Scheme type: `declarative`.
|
|
40
|
+
<3> Optional description of the scheme.
|
|
41
|
+
<4> Array of component definitions in order.
|
|
42
|
+
<5> Separator that precedes this component.
|
|
43
|
+
<6> Each segment can have its own separator.
|
|
44
|
+
<7> Last segment typically has no separator.
|
|
45
|
+
|
|
46
|
+
Where,
|
|
47
|
+
|
|
48
|
+
`name`:: Symbol identifier for the scheme.
|
|
49
|
+
`type`:: Scheme type (`declarative`).
|
|
50
|
+
`description`:: Human-readable description.
|
|
51
|
+
`components`:: Array of component definitions.
|
|
52
|
+
|
|
53
|
+
.Component attributes
|
|
54
|
+
|
|
55
|
+
[cols="1,1"]
|
|
56
|
+
|===
|
|
57
|
+
|Attribute |Purpose
|
|
58
|
+
|
|
59
|
+
|name
|
|
60
|
+
|Component name (symbol)
|
|
61
|
+
|
|
62
|
+
|type
|
|
63
|
+
|Component type (integer, string, enum, date_part, etc.)
|
|
64
|
+
|
|
65
|
+
|separator
|
|
66
|
+
|String that precedes this component (e.g., `"."`)
|
|
67
|
+
|
|
68
|
+
|prefix
|
|
69
|
+
|String that identifies an optional component (e.g., `"-"`, `"+"`)
|
|
70
|
+
|
|
71
|
+
|optional
|
|
72
|
+
|Boolean: true if component may be absent
|
|
73
|
+
|
|
74
|
+
|include_prefix_in_value
|
|
75
|
+
|Boolean: include prefix in value for component type parsing
|
|
76
|
+
|
|
77
|
+
|subtype
|
|
78
|
+
|For date_part: `year`, `month`, `day`, `week`
|
|
79
|
+
|
|
80
|
+
|values
|
|
81
|
+
|For enum type: allowed values
|
|
82
|
+
|
|
83
|
+
|order
|
|
84
|
+
|For enum type: comparison order
|
|
85
|
+
|
|
86
|
+
|validate
|
|
87
|
+
|Hash with `min`/`max` validation rules
|
|
88
|
+
|===
|
|
89
|
+
|
|
90
|
+
== Loading declarative schemes
|
|
91
|
+
|
|
92
|
+
[source,ruby]
|
|
93
|
+
----
|
|
94
|
+
# Load from YAML file
|
|
95
|
+
scheme = Versionian::SchemeLoader.from_yaml_file('schemes/custom.yaml')
|
|
96
|
+
|
|
97
|
+
# Register for use
|
|
98
|
+
Versionian.register_scheme(:custom, scheme)
|
|
99
|
+
|
|
100
|
+
# Use the scheme
|
|
101
|
+
version = scheme.parse("1.2.3")
|
|
102
|
+
puts version.major # => 1
|
|
103
|
+
----
|
|
104
|
+
|
|
105
|
+
== Examples
|
|
106
|
+
|
|
107
|
+
=== Semantic versioning
|
|
108
|
+
|
|
109
|
+
[source,yaml]
|
|
110
|
+
----
|
|
111
|
+
name: semantic
|
|
112
|
+
type: declarative
|
|
113
|
+
description: Semantic versioning
|
|
114
|
+
components:
|
|
115
|
+
- name: major
|
|
116
|
+
type: integer
|
|
117
|
+
separator: "."
|
|
118
|
+
- name: minor
|
|
119
|
+
type: integer
|
|
120
|
+
separator: "."
|
|
121
|
+
- name: patch
|
|
122
|
+
type: integer
|
|
123
|
+
- name: prerelease
|
|
124
|
+
type: string
|
|
125
|
+
prefix: "-"
|
|
126
|
+
optional: true
|
|
127
|
+
- name: build
|
|
128
|
+
type: string
|
|
129
|
+
prefix: "+"
|
|
130
|
+
optional: true
|
|
131
|
+
----
|
|
132
|
+
|
|
133
|
+
Usage:
|
|
134
|
+
|
|
135
|
+
[source,ruby]
|
|
136
|
+
----
|
|
137
|
+
scheme = Versionian::SchemeLoader.from_yaml_file('schemes/semantic.yaml')
|
|
138
|
+
|
|
139
|
+
v = scheme.parse("1.2.3-alpha.1+build.123")
|
|
140
|
+
v.major # => 1
|
|
141
|
+
v.minor # => 2
|
|
142
|
+
v.patch # => 3
|
|
143
|
+
v.prerelease # => "alpha.1"
|
|
144
|
+
v.build # => "build.123"
|
|
145
|
+
|
|
146
|
+
# Optional components are nil when absent
|
|
147
|
+
v = scheme.parse("1.2.3")
|
|
148
|
+
v.prerelease # => nil
|
|
149
|
+
v.build # => nil
|
|
150
|
+
----
|
|
151
|
+
|
|
152
|
+
=== Calendar versioning
|
|
153
|
+
|
|
154
|
+
[source,yaml]
|
|
155
|
+
----
|
|
156
|
+
name: calver
|
|
157
|
+
type: declarative
|
|
158
|
+
description: Calendar versioning YYYY.MM.DD
|
|
159
|
+
components:
|
|
160
|
+
- name: year
|
|
161
|
+
type: date_part
|
|
162
|
+
subtype: year
|
|
163
|
+
separator: "."
|
|
164
|
+
- name: month
|
|
165
|
+
type: date_part
|
|
166
|
+
subtype: month
|
|
167
|
+
separator: "."
|
|
168
|
+
- name: day
|
|
169
|
+
type: date_part
|
|
170
|
+
subtype: day
|
|
171
|
+
----
|
|
172
|
+
|
|
173
|
+
Usage:
|
|
174
|
+
|
|
175
|
+
[source,ruby]
|
|
176
|
+
----
|
|
177
|
+
scheme = Versionian::SchemeLoader.from_yaml_file('schemes/calver.yaml')
|
|
178
|
+
|
|
179
|
+
v = scheme.parse("2024.01.17")
|
|
180
|
+
v.year # => 2024
|
|
181
|
+
v.month # => 1 (not "01")
|
|
182
|
+
v.day # => 17
|
|
183
|
+
|
|
184
|
+
# Invalid dates raise ParseError
|
|
185
|
+
scheme.parse("2024.13.17") # => Invalid month '13'
|
|
186
|
+
scheme.parse("2024.02.30") # => Invalid day '30'
|
|
187
|
+
----
|
|
188
|
+
|
|
189
|
+
=== SoloVer with postfix
|
|
190
|
+
|
|
191
|
+
[source,yaml]
|
|
192
|
+
----
|
|
193
|
+
name: solover
|
|
194
|
+
type: declarative
|
|
195
|
+
description: Single number with optional postfix
|
|
196
|
+
components:
|
|
197
|
+
- name: number
|
|
198
|
+
type: integer
|
|
199
|
+
- name: postfix
|
|
200
|
+
type: postfix
|
|
201
|
+
prefix: "+"
|
|
202
|
+
optional: true
|
|
203
|
+
include_prefix_in_value: true <1>
|
|
204
|
+
----
|
|
205
|
+
<1> Postfix type handles prefix internally, so include it in the value.
|
|
206
|
+
|
|
207
|
+
Usage:
|
|
208
|
+
|
|
209
|
+
[source,ruby]
|
|
210
|
+
----
|
|
211
|
+
scheme = Versionian::SchemeLoader.from_yaml_file('schemes/solover.yaml')
|
|
212
|
+
|
|
213
|
+
v = scheme.parse("5")
|
|
214
|
+
v.number # => 5
|
|
215
|
+
v.postfix # => nil
|
|
216
|
+
|
|
217
|
+
v = scheme.parse("5+hotfix")
|
|
218
|
+
v.number # => 5
|
|
219
|
+
v.postfix # => {:prefix=>"+", :identifier=>"hotfix"}
|
|
220
|
+
|
|
221
|
+
v = scheme.parse("5-beta")
|
|
222
|
+
v.number # => 5
|
|
223
|
+
v.postfix # => {:prefix=>"-", :identifier=>"beta"}
|
|
224
|
+
----
|
|
225
|
+
|
|
226
|
+
=== Enum with custom ordering
|
|
227
|
+
|
|
228
|
+
[source,yaml]
|
|
229
|
+
----
|
|
230
|
+
name: stage
|
|
231
|
+
type: declarative
|
|
232
|
+
description: Release stage with ordering
|
|
233
|
+
components:
|
|
234
|
+
- name: major
|
|
235
|
+
type: integer
|
|
236
|
+
separator: "."
|
|
237
|
+
- name: minor
|
|
238
|
+
type: integer
|
|
239
|
+
separator: "."
|
|
240
|
+
- name: stage
|
|
241
|
+
type: enum
|
|
242
|
+
prefix: "-"
|
|
243
|
+
optional: true
|
|
244
|
+
values: [alpha, beta, rc, stable]
|
|
245
|
+
order: [alpha, beta, rc, stable]
|
|
246
|
+
----
|
|
247
|
+
|
|
248
|
+
Usage:
|
|
249
|
+
|
|
250
|
+
[source,ruby]
|
|
251
|
+
----
|
|
252
|
+
scheme = Versionian::SchemeLoader.from_yaml_file('schemes/stage.yaml')
|
|
253
|
+
|
|
254
|
+
v = scheme.parse("1.2.0-beta")
|
|
255
|
+
v.stage # => :beta
|
|
256
|
+
|
|
257
|
+
# Comparison respects order
|
|
258
|
+
scheme.compare("1.2.0-alpha", "1.2.0-beta") # => -1 (alpha < beta)
|
|
259
|
+
scheme.compare("1.2.0-rc", "1.2.0-stable") # => -1 (rc < stable)
|
|
260
|
+
----
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Overview
|
|
4
|
+
nav_order: 1
|
|
5
|
+
has_children: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
= Core Topics
|
|
9
|
+
|
|
10
|
+
Overview of Versionian's core concepts and features.
|
|
11
|
+
|
|
12
|
+
* link:schemes.html[Version Schemes] - Supported versioning schemes
|
|
13
|
+
* link:declarative-schemes.html[Declarative Schemes] - Custom segment-based schemes
|
|
14
|
+
* link:component-types.html[Component Types] - Type system reference
|
|
15
|
+
* link:range-matching.html[Range Matching] - Version range queries
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Range Matching
|
|
4
|
+
nav_order: 4
|
|
5
|
+
parent: Core Topics
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
= Range Matching
|
|
9
|
+
|
|
10
|
+
== Overview
|
|
11
|
+
|
|
12
|
+
Versionian supports matching versions against range specifications, useful for
|
|
13
|
+
dependency constraints, feature flags, and version compatibility checks.
|
|
14
|
+
|
|
15
|
+
== Range Types
|
|
16
|
+
|
|
17
|
+
[cols="2,3"]
|
|
18
|
+
|===
|
|
19
|
+
|Type |Description
|
|
20
|
+
|
|
21
|
+
|:equals
|
|
22
|
+
|Matches a specific version exactly
|
|
23
|
+
|
|
24
|
+
|:before
|
|
25
|
+
|Matches versions less than the boundary
|
|
26
|
+
|
|
27
|
+
|:after
|
|
28
|
+
|Matches versions greater than or equal to the boundary
|
|
29
|
+
|
|
30
|
+
|:between
|
|
31
|
+
|Matches versions within an inclusive range
|
|
32
|
+
|===
|
|
33
|
+
|
|
34
|
+
== Creating Ranges
|
|
35
|
+
|
|
36
|
+
[source,ruby]
|
|
37
|
+
----
|
|
38
|
+
scheme = Versionian.get_scheme(:semantic)
|
|
39
|
+
|
|
40
|
+
# Exact version
|
|
41
|
+
equals_range = Versionian::VersionRange.new(:equals, scheme, version: "1.12.0")
|
|
42
|
+
|
|
43
|
+
# Before a version
|
|
44
|
+
before_range = Versionian::VersionRange.new(:before, scheme, version: "2.0.0")
|
|
45
|
+
|
|
46
|
+
# After a version (inclusive)
|
|
47
|
+
after_range = Versionian::VersionRange.new(:after, scheme, version: "1.12.0")
|
|
48
|
+
|
|
49
|
+
# Between two versions
|
|
50
|
+
between_range = Versionian::VersionRange.new(:between, scheme, from: "1.12.0", to: "2.0.0")
|
|
51
|
+
----
|
|
52
|
+
|
|
53
|
+
== Matching Versions
|
|
54
|
+
|
|
55
|
+
[source,ruby]
|
|
56
|
+
----
|
|
57
|
+
range = Versionian::VersionRange.new(:after, scheme, version: "1.12.0")
|
|
58
|
+
|
|
59
|
+
range.matches?("1.13.0") # => true
|
|
60
|
+
range.matches?("1.12.0") # => true (inclusive)
|
|
61
|
+
range.matches?("1.11.0") # => false
|
|
62
|
+
----
|
|
63
|
+
|
|
64
|
+
== Scheme Methods
|
|
65
|
+
|
|
66
|
+
You can also use the scheme's `matches_range?` method:
|
|
67
|
+
|
|
68
|
+
[source,ruby]
|
|
69
|
+
----
|
|
70
|
+
scheme.matches_range?("1.12.0", range) # => true
|
|
71
|
+
----
|
|
72
|
+
|
|
73
|
+
== Use Cases
|
|
74
|
+
|
|
75
|
+
=== Dependency Constraints
|
|
76
|
+
|
|
77
|
+
[source,ruby]
|
|
78
|
+
----
|
|
79
|
+
require 'version'
|
|
80
|
+
|
|
81
|
+
MIN_VERSION = VersionRange.new(:after, scheme, version: "1.0.0")
|
|
82
|
+
MAX_VERSION = VersionRange.new(:before, scheme, version: "2.0.0")
|
|
83
|
+
|
|
84
|
+
def compatible?(version_string)
|
|
85
|
+
scheme.matches_range?(version_string, MIN_VERSION) &&
|
|
86
|
+
scheme.matches_range?(version_string, MAX_VERSION)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
compatible?("1.5.0") # => true
|
|
90
|
+
compatible?("2.0.0") # => false
|
|
91
|
+
----
|
|
92
|
+
|
|
93
|
+
=== Feature Flags
|
|
94
|
+
|
|
95
|
+
[source,ruby]
|
|
96
|
+
----
|
|
97
|
+
FEATURE_VERSION = VersionRange.new(:after, scheme, version: "2.0.0")
|
|
98
|
+
|
|
99
|
+
def new_feature_available?(current_version)
|
|
100
|
+
scheme.matches_range?(current_version, FEATURE_VERSION)
|
|
101
|
+
end
|
|
102
|
+
----
|