Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
target/
.bsp/
.idea/
.idea_modules/
atlassian-ide-plugin.xml
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Installation

```
resolvers += "Agilogy GitLab" at "https://gitlab.com/api/v4/groups/583742/-/packages/maven"

libraryDependencies += "com.agilogy" %% "uris" % "0.3"
```

## Publishing

To publish this package to Agilogy's Package Registry, set the `GITLAB_DEPLOY_TOKEN` environment variable and then run the following command in sbt:

```
sbt:uris> +publish
```
36 changes: 17 additions & 19 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import com.typesafe.sbt.SbtScalariform.ScalariformKeys
import scalariform.formatter.preferences._
import com.gilcloud.sbt.gitlab.{GitlabCredentials,GitlabPlugin}

organization := "com.agilogy"

name := "uris"

scalaVersion := "2.12.6"
scalaVersion := "2.12.13"

crossScalaVersions := Seq("2.11.7", "2.12.6")
crossScalaVersions := Seq("2.12.13")

libraryDependencies += "org.scalactic" %% "scalactic" % "3.0.1"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test"

libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.13.4" % "test"

// --> Linters
Expand Down Expand Up @@ -80,26 +80,24 @@ ScalariformKeys.preferences := ScalariformKeys.preferences.value

Seq(preferences)

// --> bintray

bintrayRepository := "scala"

bintrayOrganization := Some("agilogy")
// --> gitlab

bintrayPackageLabels := Seq("scala")
GitlabPlugin.autoImport.gitlabGroupId := None
GitlabPlugin.autoImport.gitlabProjectId := Some(26236490)
GitlabPlugin.autoImport.gitlabDomain := "gitlab.com"

licenses += ("Apache-2.0", url("https://www.apache.org/licenses/LICENSE-2.0.html"))
GitlabPlugin.autoImport.gitlabCredentials := {
val token = sys.env.get("GITLAB_DEPLOY_TOKEN") match {
case Some(token) => token
case None =>
sLog.value.warn(s"Environment variable GITLAB_DEPLOY_TOKEN is undefined, 'publish' will fail.")
""
}
Some(GitlabCredentials("Deploy-Token", token))
}

// <-- bintray
// <-- gitlab

enablePlugins(GitVersioning)

git.useGitDescribe := true

publishMavenStyle := isSnapshot.value

publishTo := {
val nexus = "http://188.166.95.201:8081/content/repositories/snapshots"
if (isSnapshot.value) Some("snapshots" at nexus)
else publishTo.value
}
6 changes: 0 additions & 6 deletions project/bintray.sbt

This file was deleted.

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.16
sbt.version=1.4.9
10 changes: 6 additions & 4 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ resolvers += Classpaths.sbtPluginReleases

addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.1")

addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.1.0")
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.2.5")

addSbtPlugin("org.wartremover" % "sbt-wartremover" % "2.2.0")
addSbtPlugin("org.wartremover" % "sbt-wartremover" % "2.2.1")

addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0")

addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.0")
addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.3")

addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.9.3")
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0")

addSbtPlugin("com.gilcloud" % "sbt-gitlab" % "0.0.6")
8 changes: 4 additions & 4 deletions src/main/scala/com/agilogy/uri/Authority.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package com.agilogy.uri

import scala.util.{Failure, Success, Try}
import scala.util.{ Failure, Success, Try }

sealed abstract case class UserInfo private(stringValue: String) extends UriPart
sealed abstract case class UserInfo private (stringValue: String) extends UriPart

object UserInfo {
def apply(s: String): UserInfo = new UserInfo(Encoder.normalize(s)) {}
}

abstract case class Port private(intValue: Int) {
abstract case class Port private (intValue: Int) {
val stringValue: String = intValue.toString
val asciiStringValue: String = stringValue
}
Expand Down Expand Up @@ -66,7 +66,7 @@ object Authority {
}

def parseTry(s: String): Try[Authority] = parse(s) match {
case Left(e) => Failure(AuthorityParseException(e))
case Left(e) => Failure(AuthorityParseException(e))
case Right(r) => Success(r)
}
}
2 changes: 1 addition & 1 deletion src/main/scala/com/agilogy/uri/Encoder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.agilogy.uri

import java.text.Normalizer

import scala.util.{Failure, Success, Try}
import scala.util.{ Failure, Success, Try }

object Encoder {
private val subDelims = "!$&'()*+,;=".toSet
Expand Down
54 changes: 27 additions & 27 deletions src/main/scala/com/agilogy/uri/Path.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ object PathType {
}

/**
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
sealed trait Path extends UriPart {
type PathWithSegmentsType <: Path with PathWithSegments

Expand Down Expand Up @@ -46,13 +46,13 @@ object Path {
def apply(s: NonEmptySegment) = RootlessSingleSegmentPath(s)

def apply(s: String): PathRootlessEmpty = Segment(s) match {
case EmptySegment => Path.empty
case EmptySegment => Path.empty
case s: NonEmptySegment => RootlessSingleSegmentPath(s)
}

def absoluteOrEmpty(s: Segment*): PathAbEmpty = {
s match {
case Seq() => empty
case Seq() => empty
case h +: tail => absolute(h, tail: _*)
}
}
Expand Down Expand Up @@ -86,10 +86,10 @@ object Path {
}

/**
* A path that begins with "/" or is empty
*
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
* A path that begins with "/" or is empty
*
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
sealed trait PathAbEmpty extends Path {
type PathWithSegmentsType <: PathAbEmpty with PathWithSegments
}
Expand All @@ -101,12 +101,12 @@ sealed trait PathWithSegments {
}

/**
* A path that begins with "/"
* <p>
* Note that it does NOT correspond to rfc3986's path-absolute, since it may begin with "//"
*
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
* A path that begins with "/"
* <p>
* Note that it does NOT correspond to rfc3986's path-absolute, since it may begin with "//"
*
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
sealed trait AbsolutePath extends PathWithSegments with PathAbEmpty {
type PathWithSegmentsType = NonEmptyAbsolutePath
// def /(s:String): NonEmptyAbsolutePath = this / Segment(s)
Expand All @@ -131,10 +131,10 @@ final case class NonEmptyAbsolutePath(parent: AbsolutePath, segment: Segment) ex
}

/**
* A path that begins with a non empty segment
*
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
* A path that begins with a non empty segment
*
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
sealed trait RootlessPath extends PathRootlessEmpty {

type PathWithSegmentsType = ConsRootlessPath
Expand All @@ -155,8 +155,8 @@ object RootlessPath {
}

/**
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
final case class ConsRootlessPath(parent: RootlessPath, segment: Segment) extends RootlessPath with PathWithSegments {

def /(s: Segment): ConsRootlessPath = ConsRootlessPath(this, s)
Expand All @@ -171,20 +171,20 @@ final case class AbsoluteSingleSegmentPath(segment: Segment) extends AbsolutePat
}

/**
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
final case class RootlessSingleSegmentPath private[uri](segment: NonEmptySegment) extends RootlessPath with PathWithSegments {
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
final case class RootlessSingleSegmentPath private[uri] (segment: NonEmptySegment) extends RootlessPath with PathWithSegments {

override def segments: Seq[Segment] = Seq(segment)

override def /(s: Segment): ConsRootlessPath = ConsRootlessPath(this, s)
}

/**
* The path with zero characters
*
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
* The path with zero characters
*
* @see <a href="https://tools.ietf.org/html/rfc3986#section-3.3">rfc3986#section-3.3</a>
*/
case object EmptyPath extends PathAbEmpty with PathRootlessEmpty {

type PathWithSegmentsType = AbsoluteSingleSegmentPath
Expand Down
19 changes: 9 additions & 10 deletions src/main/scala/com/agilogy/uri/RichUri.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,25 @@ object RichUri {

def apply(scheme: Scheme, authority: Authority, path: PathAbEmpty = Path.empty, query: Option[Query] = None, fragment: Option[Fragment] = None): AuthorityUri = {
(path, query, fragment) match {
case (p: PathAbEmpty, None, None) => AuthorityPathUri(scheme, authority, p)
case (p: PathAbEmpty, Some(q), None) => AuthorityPathQUri(scheme, authority, p, q)
case (p: PathAbEmpty, None, Some(f)) => AuthorityPathFUri(scheme, authority, p, f)
case (p: PathAbEmpty, None, None) => AuthorityPathUri(scheme, authority, p)
case (p: PathAbEmpty, Some(q), None) => AuthorityPathQUri(scheme, authority, p, q)
case (p: PathAbEmpty, None, Some(f)) => AuthorityPathFUri(scheme, authority, p, f)
case (p: PathAbEmpty, Some(q), Some(f)) => AuthorityPathQFUri(scheme, authority, p, q, f)
}
}

def noAuthority(scheme: Scheme, segment: String): NoAuthorityPathUri = {
Path(segment) match {
case Path.empty => NoAuthorityPathUri(scheme)
case Path.empty => NoAuthorityPathUri(scheme)
case p: RootlessPath => NoAuthorityPathUri(scheme, p)
}
}

def noAuthority(scheme: Scheme, path: Path, query: Option[Query] = None, fragment: Option[Fragment] = None): Either[PathStartsWithDoubleSlashInNoAuhtorityUri, NoAuthorityUri] = {
(path, query, fragment) match {
case (_, None, None) => NoAuthorityPathUri(scheme, path)
case (_, Some(q), None) => Right(NoAuthorityPathQUri(scheme, path, q))
case (_, None, Some(f)) => Right(NoAuthorityPathFUri(scheme, path, f))
case (_, None, None) => NoAuthorityPathUri(scheme, path)
case (_, Some(q), None) => Right(NoAuthorityPathQUri(scheme, path, q))
case (_, None, Some(f)) => Right(NoAuthorityPathFUri(scheme, path, f))
case (_, Some(q), Some(f)) => Right(NoAuthorityPathQFUri(scheme, path, q, f))
}
}
Expand Down Expand Up @@ -97,7 +97,7 @@ trait FragmentUri extends RichUri {
override def fragment: Some[Fragment] = Some(theFragment)
}

abstract case class NoAuthorityPathUri private(scheme: Scheme, path: Path) extends NoAuthorityUri with NoQueryFragmentUri[NoAuthorityUri] {
abstract case class NoAuthorityPathUri private (scheme: Scheme, path: Path) extends NoAuthorityUri with NoQueryFragmentUri[NoAuthorityUri] {

override type UQ = NoAuthorityPathQUri
override type UF = NoAuthorityPathFUri
Expand All @@ -122,8 +122,7 @@ object NoAuthorityPathUri {
// If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//").
if (path.stringValue.startsWith("//")) {
Left(PathStartsWithDoubleSlashInNoAuhtorityUri(scheme, path))
}
else {
} else {
Right(new NoAuthorityPathUri(scheme, path) {})
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/com/agilogy/uri/Scheme.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.agilogy.uri

sealed abstract case class Scheme private(stringValue: String) extends UriPart {
sealed abstract case class Scheme private (stringValue: String) extends UriPart {
override def asciiStringValue: String = stringValue
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/com/agilogy/uri/Segment.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sealed trait Segment extends UriPart {
}

// TODO: Enforce segment constraints
sealed abstract case class NonEmptySegment private(stringValue: String) extends Segment
sealed abstract case class NonEmptySegment private (stringValue: String) extends Segment

object NonEmptySegment {
private[uri] def apply(stringValue: String): NonEmptySegment = new NonEmptySegment(Encoder.normalize(stringValue)) {}
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/com/agilogy/uri/Uri.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ trait Uri extends Any with UriReference with UriPart {

override def equals(obj: Any): Boolean = obj match {
case u: Uri => this.stringValue == u.stringValue
case _ => false
case _ => false
}
}

Expand All @@ -49,8 +49,8 @@ object Uri {
def of(scheme: Scheme, authority: Option[Authority], path: Path, query: Option[Query] = None, fragment: Option[Fragment] = None): Either[PathError, RichUri] = {
(authority, path) match {
case (Some(a), p: RootlessPath) => Left(RootlessPathInAuthorityUri(scheme, a, p))
case (Some(a), p: PathAbEmpty) => Right(RichUri(scheme, a, p, query, fragment))
case (None, _) => RichUri.noAuthority(scheme, path, query, fragment)
case (Some(a), p: PathAbEmpty) => Right(RichUri(scheme, a, p, query, fragment))
case (None, _) => RichUri.noAuthority(scheme, path, query, fragment)
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/main/scala/com/agilogy/uri/UriError.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.agilogy.uri

abstract case class UriParseError private(scheme: Option[SchemeError], authority: Option[AuthorityParseError])
abstract case class UriParseError private (scheme: Option[SchemeError], authority: Option[AuthorityParseError])

object UriParseError {
def apply(scheme: Option[SchemeError] = None, authority: Option[AuthorityParseError] = None): UriParseError = {
Expand All @@ -16,11 +16,11 @@ trait SchemeError
case class MissingScheme(uri: String) extends SchemeError

/**
* Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters,
* digits, plus ("+"), period ("."), or hyphen ("-").
*
* @param scheme The illegal scheme
*/
* Scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters,
* digits, plus ("+"), period ("."), or hyphen ("-").
*
* @param scheme The illegal scheme
*/
case class IllegalSchemeName(scheme: String) extends SchemeError

case class AuthorityParseError(authority: String)
Expand Down
3 changes: 1 addition & 2 deletions src/main/scala/com/agilogy/uri/UriParser.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.agilogy.uri

import validation.Validation.{notNull, sequence}
import validation.Validation.{ notNull, sequence }

object UriParser {

Expand Down Expand Up @@ -101,5 +101,4 @@ object UriParser {
Uri.of(s, a, path, query, fragment).right.get
}


}
Loading