Skip to content

Commit 8f624e5

Browse files
committed
Completed documentation, some slight tweaks
1 parent bf78784 commit 8f624e5

File tree

2 files changed

+122
-6
lines changed

2 files changed

+122
-6
lines changed

Semantic Versioning/Conveniences.swift

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ func isAscending<T: Comparable>(_ lhs: T?, _ rhs: T?, isLessThanNil: (T) -> Bool
8383

8484

8585
extension Sequence {
86+
/// A different syntax for `Swift.zip(_:_:)`. See `Swift.zip(_:_:)` for the exact behavior.
87+
///
88+
/// - Parameter other: The other sequence to zip this one with
89+
/// - Returns: This sequence zipped with the other one
8690
func zip<Other: Sequence>(with other: Other) -> Zip2Sequence<Self, Other> {
8791
return Swift.zip(self, other)
8892
}
@@ -91,19 +95,31 @@ extension Sequence {
9195

9296

9397
extension ComparisonResult {
94-
public static let lhsHasPrecedence = ComparisonResult.orderedDescending
95-
public static let rhsHasPrecedence = ComparisonResult.orderedAscending
98+
/// A semantic alias for `.orderedDescending`
99+
public static var lhsHasPrecedence: ComparisonResult { return .orderedDescending }
100+
101+
/// A semantic alias for `.orderedAscending`
102+
public static var rhsHasPrecedence: ComparisonResult { return .orderedAscending }
96103
}
97104

98105

99106

107+
/// The old Objective-C style of `Comparable`, where the comparison operaton returns `<`, `==`, or `>`
100108
protocol ObjcComparable {
109+
/// Compares this and the other objects, and returns the comparison result
110+
///
111+
/// - Parameter other: The object to compare to this one
112+
/// - Returns: The result of the comparison
101113
func compare(to other: Self) -> ComparisonResult
102114
}
103115

104116

105117

106118
extension UInt: ObjcComparable {
119+
/// Compares this to the other `UInt`
120+
///
121+
/// - Parameter other: The `UInt` to compare to this one
122+
/// - Returns: The result of the comparison
107123
func compare(to other: UInt) -> ComparisonResult {
108124
if self == other {
109125
return .orderedSame
@@ -120,6 +136,10 @@ extension UInt: ObjcComparable {
120136

121137

122138
extension Int: ObjcComparable {
139+
/// Compares this to the other `Int`
140+
///
141+
/// - Parameter other: The `Int` to compare to this one
142+
/// - Returns: The result of the comparison
123143
func compare(to other: Int) -> ComparisonResult {
124144
if self == other {
125145
return .orderedSame

Semantic Versioning/Semantic Version.swift

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,22 @@ extension SemanticVersion: Comparable {
277277
}
278278

279279

280+
/// Determines whether the given two semantic versions are equivalent. Equivalence is implied by the precedence
281+
/// rules laid out in SemVer 2.0.0 paragraph 11: https://semver.org/spec/v2.0.0.html#spec-item-11
282+
///
283+
/// Note that they don't have to be __equal__, in the traditional sense. For instance, `"1.0" == "1.0.0"` and
284+
/// `"1.2.3+45" == "1.2.3+67"`.
285+
///
286+
/// - Parameters:
287+
/// - lhs: The first version to compare
288+
/// - rhs: The second version to compare
289+
/// - Returns: `true` if the two versions are equivalent
280290
public static func ==(lhs: SemanticVersion, rhs: SemanticVersion) -> Bool {
281291
return lhs.major == rhs.major
282292
&& lhs.minor == rhs.minor
283293
&& isEquivalent(lhs.patch, rhs.patch, isEquivalentToNil: { $0 == 0 })
284294
&& isEquivalent(lhs.preRelease, rhs.preRelease, isEquivalentToNil: { $0 == "" })
295+
// According to https://semver.org/spec/v2.0.0.html#spec-item-11, "Build metadata does not figure into precedence"
285296
}
286297
}
287298

@@ -322,44 +333,76 @@ public extension SemanticVersion.Extension {
322333

323334

324335

336+
/// Creates a string of period-separated identifiers, so `["public", "RC", "1"]` would become `"public.RC.1"`
325337
public var description: String {
326338
return identifiers.joined(separator: ".")
327339
}
340+
341+
342+
/// Creates a string suitable for naïve concatenation with a semantic version string.
343+
/// For example, a pre-release extension like `["RC", "1"]` would become `"-RC.1"`, and a build like
344+
/// `["2018", "01", "15"]` would become `"+2018.01.15"`.
328345
public var descriptionWithPrefix: String {
329346
return "\(type(of: self).prefix)\(description)"
330347
}
331348

332349

350+
/// Creates a new extension by converting the given array into an array of strings
351+
///
352+
/// - Parameter identifiers: Soon-to-be identifiers
333353
public init(identifiers: [CustomStringConvertible]) {
334354
self.init(identifiers: identifiers.map { $0.description })
335355
}
336356

337357

358+
#if swift(>=4)
359+
/// Creates a new extension by separating the given raw string by any periods in it
360+
///
361+
/// - Parameter rawString: A raw representation of a semantic version string.
362+
/// This should match the regex `/^[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*$/`.
338363
public init(_ rawString: Substring) {
339364
self.init(identifiers: rawString.split(separator: ".").map { String($0) })
340365
}
366+
#endif
341367

342368

369+
/// Creates a new extension by separating the given raw string by any periods in it
370+
///
371+
/// - Parameter rawString: A raw representation of a semantic version string.
372+
/// This should match the regex `/^[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*$/`.
343373
public init(_ rawString: String) {
344374
self.init(identifiers: rawString.split(separator: ".").map { String($0) })
345375
}
346376

347377

378+
/// Creates a new extension by converting the given varargs into an array of strings
379+
///
380+
/// - Parameter identifiers: Soon-to-be identifiers
348381
public init(_ identifiers: CustomStringConvertible...) {
349382
self.init(identifiers: identifiers)
350383
}
351384

352385

386+
/// Creates a new extension by converting the given array/varargs into an array of strings
387+
///
388+
/// - Parameter identifiers: Soon-to-be identifiers
353389
public init(arrayLiteral elements: CustomStringConvertible...) {
354390
self.init(identifiers: elements)
355391
}
356392

357393

394+
/// Creaetes a new extension by converting the given integer into a string and assuming that is the only identifier
395+
///
396+
/// - Parameter value: The only identifier, to become a string
358397
public init(integerLiteral value: UInt) {
359-
self.init(value)
398+
self.init(identifiers: [value])
360399
}
361400

362401

402+
/// Creates a new extension by separating the given raw string by any periods in it
403+
///
404+
/// - Parameter rawString: A raw representation of a semantic version string.
405+
/// This should match the regex `/^[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*$/`.
363406
public init(stringLiteral value: String) {
364407
self.init(value)
365408
}
@@ -369,11 +412,27 @@ public extension SemanticVersion.Extension {
369412

370413
public extension SemanticVersion.Extension {
371414

415+
/// Determines whether the given two SemVer extensions are in ascending order. This attempts to exactly match the
416+
/// behavior described in the SemVer 2.0.0 spec paragraph 11: https://semver.org/spec/v2.0.0.html#spec-item-11
417+
///
418+
/// - Parameters:
419+
/// - lhs: The first extension to compare
420+
/// - rhs: The second extension to compare
421+
/// - Returns: `true` iff `lhs` is less than, or has lower precedence than, `rhs`. If they have the same
422+
/// precedence, this will still return `false`.
423+
/// - Note: To determine the exact order, use `compare(lhs:rhs:)`
372424
public static func <(lhs: Self, rhs: Self) -> Bool {
373425
return compare(lhs: lhs, rhs: rhs) == .orderedAscending
374426
}
375427

376428

429+
/// Compares two SemVer extensions and returns the determined order. This attempts to exactly match the
430+
/// behavior described in the SemVer 2.0.0 spec paragraph 11: https://semver.org/spec/v2.0.0.html#spec-item-11
431+
///
432+
/// - Parameters:
433+
/// - lhs: The first extension to compare
434+
/// - rhs: The second extension to compare
435+
/// - Returns: The order of the extensions
377436
public static func compare(lhs: Self, rhs: Self) -> ComparisonResult {
378437

379438
if lhs == rhs {
@@ -424,6 +483,12 @@ public extension SemanticVersion.Extension {
424483
}
425484

426485

486+
/// Determines whether one SemVer 2.0.0 extension is equal to another
487+
///
488+
/// - Parameters:
489+
/// - lhs: One extension
490+
/// - rhs: Another extension
491+
/// - Returns: `true` iff the given two extensions are equal
427492
public static func ==(lhs: Self, rhs: Self) -> Bool {
428493
let (lhsIds, rhsIds) = (lhs.identifiers, rhs.identifiers)
429494
return lhsIds.count == rhsIds.count && !lhsIds.zip(with: rhsIds).contains(where: { $0.0 != $0.1 })
@@ -434,25 +499,56 @@ public extension SemanticVersion.Extension {
434499

435500
private extension NSTextCheckingResult {
436501

437-
func group(_ groupIndex: Int, in string: String) -> Substring? {
502+
#if swift(>=4)
503+
typealias StringOrSubstring = Substring
504+
#else
505+
typealias StringOrSubstring = String
506+
#endif
507+
508+
/// Finds the group located at the given index in this text checking result, within the given string
509+
///
510+
/// - Parameters:
511+
/// - groupIndex: The index of the group
512+
/// - string: The string to search
513+
/// - Returns: The substring at the given group index, or `nil` if there is none
514+
func group(_ groupIndex: Int, in string: String) -> StringOrSubstring? {
438515
guard let range = self.range(at: groupIndex).orNil else {
439516
return nil
440517
}
441518
return _group(range: range, in: string)
442519
}
443520

521+
/// Finds the group with the given name in this text checking result, within the given string
522+
///
523+
/// - Parameters:
524+
/// - groupName: The name of the group
525+
/// - string: The string to search
526+
/// - Returns: The substring at the given group index, or `nil` if there is none
444527
@available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *)
445-
func group(_ groupName: String, in string: String) -> Substring? {
528+
func group(_ groupName: String, in string: String) -> StringOrSubstring? {
446529
guard let range = self.range(withName: groupName).orNil else {
447530
return nil
448531
}
449532
return _group(range: range, in: string)
450533
}
451534

452535

453-
private func _group(range: NSRange, in string: String) -> Substring? {
536+
/// The base of the other `group(_:in:)` functions; simply returns the substring of the given string at the given
537+
/// range, iff that range is valid. If the range is invalid (e.g. if it's not inside the string or location is `NSNotFound`)
538+
///
539+
/// - Parameters:
540+
/// - range: The range of characters to return
541+
/// - string: The string to search
542+
/// - Returns: The substring at the given range, or `nil` if there is none
543+
private func _group(range: NSRange, in string: String) -> StringOrSubstring? {
544+
guard range.location != NSNotFound else {
545+
return nil
546+
}
454547
let startingIndex = string.index(string.startIndex, offsetBy: range.location)
455548
let endingIndex = string.index(startingIndex, offsetBy: range.length)
549+
guard string.endIndex >= endingIndex else {
550+
return nil
551+
}
456552
return string[startingIndex..<endingIndex]
457553
}
458554
}

0 commit comments

Comments
 (0)