Skip to content
This repository has been archived by the owner on Oct 10, 2021. It is now read-only.

Commit

Permalink
Merge pull request #33 from NthPortal/convert2
Browse files Browse the repository at this point in the history
Improve conversions
  • Loading branch information
NthPortal committed Sep 10, 2017
2 parents d89309b + 151f531 commit 865c70f
Show file tree
Hide file tree
Showing 42 changed files with 470 additions and 354 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@ project/project
!LICENSE
!*.md
!.travis.yml
!.coveralls.yml
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ scala:
- 2.12.0
- 2.12.1
- 2.12.2
- 2.12.3
jdk:
- oraclejdk8
cache:
Expand Down
10 changes: 7 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,26 @@ organization := "com.nthportal"
name := "versions"
description := "A Scala library for representing versions as objects."

val rawVersion = "2.1.0"
val rawVersion = "3.0.0"
isSnapshot := true
version := rawVersion + { if (isSnapshot.value) "-SNAPSHOT" else "" }

scalaVersion := "2.12.2"
scalaVersion := "2.12.3"
crossScalaVersions := Seq(
"2.12.0",
"2.12.1",
"2.12.2"
"2.12.2",
"2.12.3"
)

libraryDependencies ++= Seq(
"com.nthportal" %% "convert" % "0.3.0",
"com.nthportal" %% "extra-predef" % "1.+",
"org.scalatest" %% "scalatest" % "3.0.+" % Test
)

autoAPIMappings := true

scalacOptions ++= {
if (isSnapshot.value) Seq()
else scalaVersion.value split '.' map { _.toInt } match {
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version = 0.13.15
sbt.version = 0.13.16
39 changes: 16 additions & 23 deletions src/main/scala/com/nthportal/versions/ExtendedVersionBase.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.nthportal
package versions

import com.nthportal.convert.Convert

import scala.language.higherKinds

/**
Expand Down Expand Up @@ -30,49 +32,40 @@ trait ExtendedVersionBase[V <: VersionBase[V, EV], E, EV[X] <: ExtendedVersionBa
*
* @param companion a [[ExtendedVersionCompanion companion]] of the type
* of version to which this should be converted
* @param c the `Convert` to use
* @return this version converted to the other type, if it can be
* represented by the other type
* @throws IllegalArgumentException if this version cannot be converted
* to the other type
* @throws scala.IllegalArgumentException if this version cannot be converted
* to the other type (when `c` is `Convert.Valid`)
*/
@throws[IllegalArgumentException]("if this version cannot be converted to the other type")
def to[V2 <: VersionBase[V2, EV2], EV2[X] <: ExtendedVersionBase[V2, X, EV2]]
(companion: ExtendedVersionCompanion[V2, EV2]): EV2[E] = {
if (companion eq version.extendedCompanion) this.asInstanceOf[EV2[E]]
else companion(version to companion.baseCompanion, extension, extensionDef)
}

/**
* Converts this extended version to another type, if possible.
*
* @param companion a [[ExtendedVersionCompanion companion]] of the type
* of version to which this should be converted
* @return an [[Option]] containing this version converted to
* the other type, if it can be represented by the other type
*/
def toOptionOf[V2 <: VersionBase[V2, EV2], EV2[X] <: ExtendedVersionBase[V2, X, EV2]]
(companion: ExtendedVersionCompanion[V2, EV2]): Option[EV2[E]] = {
if (companion eq version.extendedCompanion) Some(this.asInstanceOf[EV2[E]])
else version toOptionOf companion.baseCompanion map { companion(_, extension, extensionDef) }
(companion: ExtendedVersionCompanion[V2, EV2])(implicit c: Convert): c.Result[EV2[E]] = {
import c._
conversion {
if (companion eq version.extendedCompanion) this.asInstanceOf[EV2[E]]
else companion(unwrap(version to companion.baseCompanion), extension, extensionDef)
}
}

/**
* Compares two extended versions. Adheres to the general contract
* of `compare` as defined in [[scala.math.Ordered.compare]].
*
* `that` MUST have the same [[Ordering]] in its extension definition as `this`.
* `that` MUST have the same [[scala.Ordering Ordering]] in its extension
* definition as `this`.
*
* @param that the extended version to compare to this
* @throws IllegalArgumentException if the other extended version does not have
* the same extension ordering as this
* @throws scala.IllegalArgumentException if the other extended version does not have
* the same extension ordering as this
* @return the result of comparing `this` with `that`
*/
@throws[IllegalArgumentException]("if the other extended version does not have the same extension ordering as this")
override def compare(that: EV[E]): Int = {
require(extensionDef.ordering == that.extensionDef.ordering,
"cannot compare extended versions with different extension orderings")
implicit val eOrd = extensionDef.ordering
(this.version compare that.version) thenCompare(this.extension, that.extension)
(this.version compare that.version) thenCompare (this.extension, that.extension)
}

override def toString = s"$version${extensionDef.extToString(extension)}"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
package com.nthportal.versions

import com.nthportal.convert.Convert

import scala.language.higherKinds

/**
* A companion object for an extended version.
*
* @param c a [[VersionCompanion]] for the version component of the
* extended version
* @param companion a [[VersionCompanion]] for the version component of the
* extended version
* @tparam V the type of the version component of the extended version
* @tparam EV the type of the extended version
*/
abstract class ExtendedVersionCompanion[V <: VersionBase[V, EV], EV[E] <: ExtendedVersionBase[V, E, EV]]
(c: VersionCompanion[V, EV]) {
(companion: VersionCompanion[V, EV]) {
/**
* Returns the [[VersionCompanion companion object]] for
* non-extended versions.
*
* @return the companion object for non-extended versions
*/
private[versions] final def baseCompanion: VersionCompanion[V, EV] = c
private[versions] final def baseCompanion: VersionCompanion[V, EV] = companion

/**
* Creates an extended version from a version, extension, and
Expand All @@ -36,57 +38,51 @@ abstract class ExtendedVersionCompanion[V <: VersionBase[V, EV], EV[E] <: Extend
* Parses a string into an extended version.
*
* @param version the string to parse
* @param c the `Convert` to use
* @param ed the [[ExtensionDef extension definition]]
* @param ep a [[ExtensionParser parser]] for extensions
* @tparam E the type of the extension
* @throws VersionFormatException if the given string is not a valid extended version
* (when `c` is `Convert.Valid`)
* @return the extended version represented by the string
*/
@throws[VersionFormatException]("if the given string is not a valid extended version")
def parseVersion[E](@deprecatedName('v, since = "1.3.0") version: String)
(implicit ed: ExtensionDef[E],
ep: ExtensionParser[E]): EV[E] = {
version.split("-", 2) match {
case Array(ver, extension) =>
try {
c.parseVersion(ver) -- ep.parse(extension)
} catch {
case e: IllegalArgumentException => throw new VersionFormatException(version, e)
def parseVersion[E](version: String)
(implicit c: Convert,
ed: ExtensionDef[E],
ep: ExtensionParser[E]): c.Result[EV[E]] = {
import c._
conversion {
import AutoUnwrap._
version.split("-", 2) match {
case Array(ver, extension) =>
try {
companion.parseVersion(ver) -- ep.parse(extension)
} catch {
case e: IllegalArgumentException => fail(new VersionFormatException(version, e))
}
case Array(ver) => ed.default match {
case Some(extension) => companion.parseVersion(ver) -- extension
case None =>
fail(new VersionFormatException(version, new UnsupportedOperationException("No default extension")))
}
case Array(ver) => ed.default match {
case Some(extension) => c.parseVersion(ver) -- extension
case None => throw new VersionFormatException(version, new UnsupportedOperationException("No default extension"))
}
}
}

/**
* Parses a string into an extended version.
*
* @param version the string to parse
* @param ed the [[ExtensionDef extension definition]]
* @param ep a [[ExtensionParser parser]] for extensions
* @tparam E the type of the extension
* @throws VersionFormatException if the given string is not a valid extended version
* @return an [[Option]] containing the extended version represented by the string;
* [[None]] if the string did not represent a valid extended version
*/
def parseAsOption[E](version: String)(implicit ed: ExtensionDef[E], ep: ExtensionParser[E]): Option[EV[E]] = {
formatCheckToOption { parseVersion(version) }
}

/**
* Extracts an extended version from a version string.
*
* @param version the string from which to extract an extended version
* @param ed the [[ExtensionDef extension definition]]
* @param ep a [[ExtensionParser parser]] for extensions
* @tparam E the type of the extension
* @return an [[Option]] containing the version and extension represented
* by the string; [[None]] if the string did not represent a valid
* @return an [[scala.Option Option]] containing the version and extension represented
* by the string; [[scala.None None]] if the string did not represent a valid
* extended version
*/
def unapply[E](version: String)(implicit ed: ExtensionDef[E], ep: ExtensionParser[E]): Option[(V, E)] = {
parseAsOption(version) map { ev => (ev.version, ev.extension) }
import Convert.Any.Implicit.ref
parseVersion(version) map { ev => (ev.version, ev.extension) }
}
}
12 changes: 8 additions & 4 deletions src/main/scala/com/nthportal/versions/ExtensionDef.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,17 @@ final case class ExtensionDef[E](default: Option[E], ordering: Ordering[E]) exte

object ExtensionDef {
/**
* Defines an extension type from an [[Ordered]] type, with no default extension value.
* Defines an extension type from an [[scala.Ordered Ordered]] type,
* with no default extension value.
*
* @tparam E the type of the extension
* @return an extension definition for the given type
*/
def fromOrdered[E <: Ordered[E]]: ExtensionDef[E] = apply(None, _ compare _)

/**
* Defines an extension type from an [[Ordered]] type, with the given default extension value.
* Defines an extension type from an [[scala.Ordered Ordered]] type,
* with the given default extension value.
*
* @param default the default extension value
* @tparam E the type of the extension
Expand All @@ -47,15 +49,17 @@ object ExtensionDef {
def fromOrdered[E <: Ordered[E]](default: E): ExtensionDef[E] = apply(Some(default), _ compare _)

/**
* Defines an extension type from a [[Comparable]] type, with no default extension value.
* Defines an extension type from a [[java.lang.Comparable Comparable]] type,
* with no default extension value.
*
* @tparam E the type of the extension
* @return an extension definition for the given type
*/
def fromComparable[E <: Comparable[E]]: ExtensionDef[E] = apply(None, _ compareTo _)

/**
* Defines an extension type from a [[Comparable]] type, with the given default extension value.
* Defines an extension type from a [[java.lang.Comparable Comparable]] type,
* with the given default extension value.
*
* @param default the default extension value
* @tparam E the type of the extension
Expand Down
8 changes: 5 additions & 3 deletions src/main/scala/com/nthportal/versions/ExtensionParser.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.nthportal.versions

import com.nthportal.convert.Convert

/**
* Something which parses a version extension from a string.
*
Expand All @@ -10,10 +12,10 @@ trait ExtensionParser[E] {
* Parses a version extension from the given string.
*
* @param extension the string representation of the extension
* @throws IllegalArgumentException if the string provided does not
* represent a valid extension
* @throws scala.IllegalArgumentException if the string provided does not
* represent a valid extension
* @return the extension represented by the specified string
*/
@throws[IllegalArgumentException]("if the string provided does not represent a valid extension")
def parse(extension: String): E
def parse(extension: String)(implicit c: Convert): c.Result[E]
}
38 changes: 15 additions & 23 deletions src/main/scala/com/nthportal/versions/VersionBase.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.nthportal.versions

import com.nthportal.convert.Convert

import scala.language.higherKinds

/**
Expand All @@ -10,7 +12,7 @@ import scala.language.higherKinds
*/
trait VersionBase[V <: VersionBase[V, EV], EV[E] <: ExtendedVersionBase[V, E, EV]]
extends Ordered[V]
with Dash[V, EV] {
with Dash[V, EV] {
/**
* Returns the [[VersionCompanion companion object]] for this version.
*
Expand All @@ -27,7 +29,7 @@ trait VersionBase[V <: VersionBase[V, EV], EV[E] <: ExtendedVersionBase[V, E, EV
protected[versions] def extendedCompanion: ExtendedVersionCompanion[V, EV]

/**
* Returns a [[Seq]] representation of this version.
* Returns a [[scala.Seq Seq]] representation of this version.
*
* @return a Seq representation of this version
*/
Expand All @@ -38,35 +40,25 @@ trait VersionBase[V <: VersionBase[V, EV], EV[E] <: ExtendedVersionBase[V, E, EV
*
* @param companion a [[VersionCompanion companion]] of the type of version
* to which this should be converted
* @param c the `Convert` to use
* @return this version converted to the other type, if it can be
* represented by the other type
* @throws IllegalArgumentException if this version cannot be converted
* to the other type
* @throws scala.IllegalArgumentException if this version cannot be converted
* to the other type (when `c` is `Convert.Valid`)
*/
@throws[IllegalArgumentException]("if this version cannot be converted to the other type")
def to[V2 <: VersionBase[V2, EV2], EV2[E] <: ExtendedVersionBase[V2, E, EV2]]
(companion: VersionCompanion[V2, EV2]): V2 = {
if (companion eq this.companion) this.asInstanceOf[V2]
else {
companion.versionFromSeq.applyOrElse(toSeq,
(_: Seq[Int]) => throw new IllegalArgumentException(s"$this cannot be converted to $companion"))
(companion: VersionCompanion[V2, EV2])(implicit c: Convert): c.Result[V2] = {
import c._
conversion {
if (companion eq this.companion) this.asInstanceOf[V2]
else {
companion.versionFromSeq.applyOrElse(toSeq,
(_: Seq[Int]) => fail(new IllegalArgumentException(s"$this cannot be converted to $companion")))
}
}
}

/**
* Converts this version to another type, if possible.
*
* @param companion a [[VersionCompanion companion]] of the type of version
* to which this should be converted
* @return an [[Option]] containing this version converted to
* the other type, if it can be represented by the other type
*/
def toOptionOf[V2 <: VersionBase[V2, EV2], EV2[E] <: ExtendedVersionBase[V2, E, EV2]]
(companion: VersionCompanion[V2, EV2]): Option[V2] = {
if (companion eq this.companion) Some(this.asInstanceOf[V2])
else companion.versionFromSeq.lift(toSeq)
}

override def dash[E](extension: E)(implicit ed: ExtensionDef[E]) = {
extendedCompanion(this.asInstanceOf[V], extension, ed)
}
Expand Down

0 comments on commit 865c70f

Please sign in to comment.