Skip to content

Commit

Permalink
Merge pull request #1 from morgen-peschke/integration
Browse files Browse the repository at this point in the history
Release 0.0.1
  • Loading branch information
morgen-peschke authored Aug 15, 2022
2 parents dc44040 + 3af1936 commit 0f71ca7
Show file tree
Hide file tree
Showing 18 changed files with 400 additions and 177 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
target/
*~
.idea
out
1 change: 1 addition & 0 deletions .mill-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.10.5
56 changes: 56 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
version = 3.5.9
runner.dialect = scala213
fileOverride {
"glob:**/src-2.12/**" {
runner.dialect = scala212
}
}

style = default
maxColumn = 80

project.git = true
project.excludeFilters = []

assumeStandardLibraryStripMargin = true

align {
preset = some
stripMargin = true
openParenCallSite = false
openParenDefnSite = false
openParenTupleSite = true
closeParenSite = true
beforeOpenParenCallSite = true
beforeOpenParenDefnSite = true
arrowEnumeratorGenerator = true
tokens = [ ":", "=", "=>", "->", "<-", "//" ]
}

danglingParentheses {
defnSite = false
callSite = true
ctrlSite = true
tupleSite = true
}

newlines {
beforeOpenParenDefnSite = fold
sometimesBeforeColonInMethodReturnType = true
alwaysBeforeElseAfterCurlyIf = true
inInterpolation = avoid
beforeTypeBounds = unfold
beforeCurlyLambdaParams = multilineWithCaseOnly
afterCurlyLambdaParams = squash
implicitParamListModifierPrefer = before
avoidForSimpleOverflow=[tooLong,punct,slc]
}

includeNoParensInSelectChains = true

optIn {
breakChainOnFirstMethodDot = true
breaksInsideChains = true
}

importSelectors = singleLine
49 changes: 28 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,44 @@ Common utility libraries for Scala, mostly small stuff I don't want to have mult

## Installation

Currently it's not yet on maven, but it can be referenced from github using `sbt`.

```sbtshell
lazy val root =
(project in file("."))
.dependsOn(scalaCommons)
...
### SBT
```
libraryDependencies += Seq(
"com.github.morgen-peschke" % "commons-core" % "0.0.1",
"com.github.morgen-peschke" % "commons-collections" % "0.0.1"
)
```

lazy val scalaCommons = RootProject(uri("git://github.com/morgen-peschke/scala-commons.git#v1.0.1"))
### Mill
```
def ivyDeps = Agg(
ivy"com.github.morgen-peschke::commons-core:0.0.1",
ivy"com.github.morgen-peschke::commons-collections:0.0.1"
)
```

[JitPack](https://jitpack.io/) is another (possibly better) option:
## SubModules

```sbtshell
resolvers += "jitpack" at "https://jitpack.io"
### `commons-core`

libraryDependencies += "com.github.morgen-peschke" % "scala-commons" % "v1.0.1"
```
This is a home for the most generic of utilities.

## Highlights
#### `Complete`

### `TakeUntil`
A placeholder indicating completion, which provides a work-around for the type issues which can arise when returning
things like `Future[Unit]`.

An alternative to `GenTraversable#takeWhile`, which is primarily differentiated on two points:
This is very similar to `akka.Done`, and exists as a lightweight alternative to the same.

### `commons-collections`

Helpers and extensons for working with the Scala standard library.

#### `TakeUntil`

An alternative to `IterableOnce#takeWhile`, which is primarily differentiated on two points:
1. The elements are consumed until the predicate is true, rather than while the predicate is true, so the logic is
reversed.
2. The final element is also taken.

### `Complete`

A placeholder indicating completion, which provides a work-around for the type issues which can arise when returning
things like `Future[Unit]`. Check the docs for more details.

This is very similar to `akka.Done`, and exists as a lightweight alternative to the same.
31 changes: 0 additions & 31 deletions build.sbt

This file was deleted.

68 changes: 68 additions & 0 deletions build.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import mill._, scalalib._, scalafmt._
import mill.scalalib.publish._

val Scala12 = "2.12.16"
val Scala13 = "2.13.8"

trait CommonModule extends CrossScalaModule with ScalafmtModule with PublishModule {
def publishVersion = "0.0.1"

def pomSettings = PomSettings(
description = "Scala Commons - common utilities for Scala projects",
organization = "com.github.morgen-peschke",
url = "https://github.com/morgen-peschke/scala-commons",
licenses = Seq(License.MIT),
versionControl = VersionControl.github("morgen-peschke", "scala-commons"),
developers = Seq(
Developer("morgen-peschke", "Morgen Peschke", "https://github.com/morgen-peschke")
)
)

def crossScalaVersion: String

def commonScalacOptions = Seq(
"-encoding",
"UTF-8",
"-deprecation",
"-unchecked",
"-feature",
"-Ywarn-unused",
"-Ywarn-dead-code",
"-Ywarn-value-discard",
"-Xfatal-warnings"
)

def versionSpecificOptions(version: String) = version match {
case Scala12 => Seq(
"-Ywarn-adapted-args",
"-Ywarn-inaccessible",
"-Ywarn-unused-import",
"-Ypartial-unification"
)
case _ => Seq()
}

def scalacOptions = commonScalacOptions ++ versionSpecificOptions(crossScalaVersion)

def scalaDocOptions = Seq("-no-link-warnings")
}

object core extends Cross[CoreModule](Scala12, Scala13)
class CoreModule(val crossScalaVersion: String)
extends CommonModule {

def artifactName = "commons-core"
}

object collections extends Cross[CollectionsModule](Scala12, Scala13)
class CollectionsModule(val crossScalaVersion: String)
extends CommonModule {

def artifactName = "commons-collections"

def moduleDeps = Seq(core(crossScalaVersion))

object test extends Tests with TestModule.ScalaTest {
def ivyDeps = Agg(ivy"org.scalatest::scalatest:3.2.13")
}
}
45 changes: 45 additions & 0 deletions collections/src-2.12/peschke/collections/TakeUntil.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package peschke.collections

import scala.annotation.tailrec
import scala.collection.generic.CanBuildFrom
import scala.collection.{TraversableLike, mutable}
import scala.language.higherKinds

/** Provides a reversed alternative to
* [[scala.collection.GenTraversableLike.takeWhile]]
*
* Of particular interest is that [[TakeUntil.takeUntil]] includes the final
* value which caused the predicate to evaluate to `true`.
*/
object TakeUntil {

def takeUntil[E, C[X] <: TraversableLike[X, C[X]], That]
(source: C[E])(p: E => Boolean)(implicit cbf: CanBuildFrom[C[E], E, That])
: That = {
val builder: mutable.Builder[E, That] = cbf()
@tailrec
def loop(remaining: C[E]): That =
remaining.headOption match {
case None => builder.result()
case Some(x) if p(x) =>
builder += x
builder.result()
case Some(x) =>
builder += x
loop(remaining.drop(1))
}

loop(source)
}

object syntax {
implicit class TakeUntilOps[E, C[X] <: TraversableLike[X, C[X]]]
(val source: C[E])
extends AnyVal {
def takeUntil[That](p: E => Boolean)
(implicit cbf: CanBuildFrom[C[E], E, That])
: That =
TakeUntil.takeUntil(source)(p)(cbf)
}
}
}
44 changes: 44 additions & 0 deletions collections/src-2.13/peschke/collections/TakeUntil.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package peschke.collections

import scala.collection.{AbstractView, BuildFrom}

/** Provides a reversed alternative to [[scala.collection.Iterator.takeWhile]]
*
* Of particular interest is that [[TakeUntil.takeUntil]] includes the final
* value which caused the predicate to evaluate to `true`.
*/
object TakeUntil {
def takeUntil[E, C[_] <: IterableOnce[_], Out]
(source: C[E])(stop: E => Boolean)
(implicit bf: BuildFrom[C[E], E, Out], ev: C[E] <:< IterableOnce[E])
: Out =
bf.fromSpecific(source)(new AbstractView[E] {
override def iterator: Iterator[E] = {
Iterator.unfold[E, Iterator[E]](ev(source).iterator) { it =>
it.nextOption() match {
case None => None
case Some(x) if stop(x) => Some(x -> Iterator.empty)
case Some(x) => Some(x -> it)
}
}
}
})

object syntax {
// Can't be an AnyVal style extension method because there's no way to infer the element type without
// breaking the invariant that Value Classes can only wrap a single value.
class TakeUntilOps[E, C[_] <: IterableOnce[_]](source: C[E]) {
def takeUntil[Out]
(stop: E => Boolean)
(implicit bf: BuildFrom[C[E], E, Out], ev: C[E] <:< IterableOnce[E])
: Out =
TakeUntil.takeUntil[E, C, Out](source)(stop)(bf, ev)
}

import scala.language.implicitConversions

implicit def takeUntilOp[E, C[_] <: IterableOnce[_]](source: C[E])
: TakeUntilOps[E, C] =
new TakeUntilOps[E, C](source)
}
}
40 changes: 40 additions & 0 deletions collections/test/src-2.13/peschke/collections/TakeUntilTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package peschke.collections

import peschke.UnitSpec

class TakeUntilTest extends UnitSpec {
import peschke.collections.TakeUntil.syntax._

val input: List[Int] = (0 to 10).toList

"TakeUntil.takeUntilOp" should {
"produce all elements until the predicate is true, and final value" in {
input.takeUntil(_ == 5) mustBe List(0, 1, 2, 3, 4, 5)
}

"produce the entire input, if the predicate is never true" in {
input.takeUntil(_ == 50) mustBe input
}

"not attempt to access past the point where the predicate becomes true" in {
def wentTooFar: LazyList[Int] = fail("Attempted to read too far")

val input: LazyList[Int] = 0 #:: 1 #:: 2 #:: 3 #:: 4 #:: 5 #:: wentTooFar
input.takeUntil(_ == 3).toList mustBe List(0, 1, 2, 3)
}

"be lazy for lazy collections" in {
def wentTooFar: LazyList[Int] = fail("Was not lazy")

val input: LazyList[Int] = 0 #:: 1 #:: wentTooFar

input.takeUntil(_ == 3).headOption.value mustBe 0
}

"infer types correctly" in {
assertResult(true) {
input.takeUntil(5.max(_) != 5) === List(0, 1, 2, 3, 4, 5, 6)
}
}
}
}
7 changes: 7 additions & 0 deletions collections/test/src/peschke/UnitSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package peschke

import org.scalatest.OptionValues
import org.scalatest.matchers.must.Matchers
import org.scalatest.wordspec.AnyWordSpec

trait UnitSpec extends AnyWordSpec with Matchers with OptionValues
Loading

0 comments on commit 0f71ca7

Please sign in to comment.