Skip to content

Commit 776d7a6

Browse files
authored
Documentation site overhaul (#576)
1 parent b48b559 commit 776d7a6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+2231
-569
lines changed

.travis.yml

+8
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,11 @@ before_cache:
3232
- du -h -d 2 $HOME/.sbt/
3333
- find $HOME/.sbt -name "*.lock" -type f -delete
3434
- find $HOME/.ivy2/cache -name "ivydata-*.properties" -type f -delete
35+
36+
notifications:
37+
webhooks:
38+
urls:
39+
- https://webhooks.gitter.im/e/83f5f34730d7a004992f
40+
on_success: change
41+
on_failure: always
42+
on_start: never

CONTRIBUTING.md

+73-7
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,85 @@ position: 5
77

88
# Contributing to Algebird
99

10-
This page lists recommendations and requirements for how to best contribute to Algebird.
10+
This page lists recommendations and requirements for how to best contribute to Algebird. We strive to obey these as best as possible. As always, thanks for contributing--we hope these guidelines make it easier and shed some light on our approach and processes.
1111

12-
We strive to obey these as best as possible. As always, thanks for contributing--we hope these guidelines make it easier and shed some light on our approach and processes.
12+
## Key branches
1313

14-
### Key branches
1514
- `master` is the latest, deployed version.
1615
- `develop` is where development happens and all pull requests should be submitted.
1716

18-
### Pull requests
17+
## Pull requests
1918

20-
- Submit pull requests against the `develop` branch.
21-
- Try not to pollute your pull request with unintended changes--keep them simple and small.
19+
Submit pull requests against the `develop` branch. Try not to pollute your pull request with unintended changes. Keep it simple and small.
2220

23-
### License
21+
## Contributing Documentation
22+
23+
The documentation for Algebird's website is stored in the `docs/src/main/tut` directory of the [docs subproject](https://github.com/twitter/algebird/tree/develop/docs).
24+
25+
Algebird's documentation is powered by [sbt-microsites](https://47deg.github.io/sbt-microsites/) and [tut](https://github.com/tpolecat/tut). `tut` compiles any code that appears in the documentation, ensuring that snippets and examples won't go out of date.
26+
27+
We would love your help making our documentation better. If you see a page that's empty or needs work, please send us a pull request making it better. If you contribute a new data structure to Algebird, please add a corresponding documentation page. To do this, you'll need to:
28+
29+
- Add a new Markdown file to `docs/src/main/tut/datatypes` with the following format:
30+
31+
```markdown
32+
---
33+
layout: docs
34+
title: "<Your Page Title>"
35+
section: "data"
36+
source: "algebird-core/src/main/scala/com/twitter/algebird/<YourDataType>.scala"
37+
scaladoc: "#com.twitter.algebird.<YourDataType>"
38+
---
39+
40+
# Your Data Type
41+
42+
.....
43+
```
44+
45+
- Make sure to add some code examples! Any code block of this form will get compiled using `tut`:
46+
47+
48+
```toot:book
49+
<your code>
50+
```
51+
52+
(Please replace `toot` with `tut`!) `tut` will evaluate your code as if you'd pasted it into a REPL and insert each line's results in the output. State persists across `tut` code blocks, so feel free to alternate code blocks with text discussion. See the [tut README](https://github.com/tpolecat/tut) for more information on the various options you can use to customize your code blocks.
53+
- Add your page to the appropriate section in [the menu](https://github.com/twitter/algebird/tree/develop/docs/src/main/resources/microsite/data/menu.yml)
54+
55+
### Generating the Site
56+
57+
run `sbt docs/makeMicrosite` to generate a local copy of the microsite.
58+
59+
### Previewing the site
60+
61+
1. Install jekyll locally, depending on your platform, you might do this with any of the following commands:
62+
63+
```
64+
yum install jekyll
65+
apt-get install jekyll
66+
gem install jekyll
67+
```
68+
69+
2. In a shell, navigate to the generated site directory in `docs/target/site`
70+
3. Start jekyll with `jekyll serve --incremental`
71+
4. Navigate to http://127.0.0.1:4000/algebird/ in your browser
72+
5. Make changes to your site, and run `sbt docs/makeMicrosite` to regenerate the site. The changes should be reflected as soon as `sbt docs/makeMicrosite` completes.
73+
74+
## Post-release
75+
76+
After the release occurs, you will need to update the documentation. Here is a list of the places that will definitely need to be updated:
77+
78+
* `README.md`: update version numbers
79+
* `CHANGES.md`: summarize changes since last release
80+
81+
(Other changes may be necessary, especially for large releases.)
82+
83+
You can get a list of changes between release tags `v0.1.2` and `v0.2.0` via `git log v0.1.2..v0.2.0`. Scanning this list of commit messages is a good way to get a summary of what happened, although it does not account for conversations that occured on Github.
84+
85+
Once the relevant documentation changes have been committed, new [release notes](https://github.com/twitter/algebird/releases) should be added. You can add a release by clicking the "Draft a new release" button on that page, or if the relevant release already exists, you can click "Edit release".
86+
87+
The website should then be updated via `sbt docs/publishMicrosite`.
88+
89+
## License
2490
2591
By contributing your code, you agree to license your contribution under the terms of the [APLv2](LICENSE).

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
Abstract algebra for Scala. This code is targeted at building aggregation systems (via [Scalding](https://github.com/twitter/scalding) or [Apache Storm](http://storm.apache.org/)). It was originally developed as part of Scalding's Matrix API, where Matrices had values which are elements of Monoids, Groups, or Rings. Subsequently, it was clear that the code had broader application within Scalding and on other projects within Twitter.
1111

12-
See the [current API documentation](http://twitter.github.com/algebird) for more information.
12+
See the [Algebird website](https://twitter.github.io/algebird) for more information.
1313

1414
### What can you do with this code?
1515

@@ -61,7 +61,7 @@ A list of contributors to the project can be found here: [Contributors](https://
6161

6262
## Maven
6363

64-
Algebird modules are available on maven central. The current groupid and version for all modules is, respectively, `"com.twitter"` and `0.11.0`.
64+
Algebird modules are available on maven central. The current groupid and version for all modules is, respectively, `"com.twitter"` and `0.12.2`.
6565

6666
Current published artifacts are
6767

algebird-core/src/main/scala/com/twitter/algebird/ExpHist.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ object ExpHist {
194194

195195
// Drops all buckets with an expired timestamp, based on the
196196
// configured window and the supplied current time.
197-
def dropExpired(buckets: Vector[Bucket], currTime: Timestamp): (Long, Vector[Bucket]) =
197+
private[algebird] def dropExpired(buckets: Vector[Bucket], currTime: Timestamp): (Long, Vector[Bucket]) =
198198
ExpHist.dropExpired(buckets, expiration(currTime))
199199

200200
/**
@@ -225,7 +225,7 @@ object ExpHist {
225225
* @param cutoff buckets with ts <= cutoff are expired
226226
* @return the sum of evicted bucket sizes and the unexpired buckets
227227
*/
228-
def dropExpired(buckets: Vector[Bucket], cutoff: Timestamp): (Long, Vector[Bucket]) = {
228+
private[algebird] def dropExpired(buckets: Vector[Bucket], cutoff: Timestamp): (Long, Vector[Bucket]) = {
229229
val (dropped, remaining) = buckets.reverse.span(_.timestamp <= cutoff)
230230
(dropped.map(_.size).sum, remaining.reverse)
231231
}

algebird-core/src/main/scala/com/twitter/algebird/SummingIterator.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import scala.annotation.tailrec
2929

3030
/**
3131
* Creates an Iterator that emits partial sums of an input Iterator[V].
32-
* Generally this is useful to change from processing individiual V's to
32+
* Generally this is useful to change from processing individual Vs to
3333
* possibly blocks of V @see SummingQueue or a cache of recent Keys in
3434
* a V=Map[K,W] case: @see SummingCache
3535
*/

algebird-core/src/main/scala/com/twitter/algebird/macros/Cuber.scala

-81
Original file line numberDiff line numberDiff line change
@@ -31,38 +31,6 @@ trait Cuber[I] {
3131
def apply(in: I): TraversableOnce[K]
3232
}
3333

34-
/**
35-
* Given a TupleN, produces a sequence of (N + 1) tuples each of arity N
36-
* such that, for all k from 0 to N, there is a tuple with k Somes
37-
* followed by (N - k) Nones.
38-
*
39-
* This is useful for comparing some metric across multiple layers of
40-
* some hierarchy.
41-
* For example, suppose we have some climate data represented as
42-
* case class Data(continent: String, country: String, city: String, temperature: Double)
43-
* and we want to know the average temperatures of
44-
* - each continent
45-
* - each (continent, country) pair
46-
* - each (continent, country, city) triple
47-
*
48-
* Here we desire the (continent, country) and (continent, country, city)
49-
* pair because, for example, if we grouped by city instead of by
50-
* (continent, country, city), we would accidentally combine the results for
51-
* Paris, Texas and Paris, France.
52-
*
53-
* Then we could do
54-
* > import com.twitter.algebird.macros.Roller.roller
55-
* > val data: List[Data]
56-
* > val averageTemps: Map[(Option[String], Option[String], Option[String]), Double] =
57-
* > data.flatMap { d => roller((d.continent, d.country, d.city)).map((_, d)) }
58-
* > .groupBy(_._1)
59-
* > .mapValues { xs => val temps = xs.map(_.temperature); temps.sum / temps.length }
60-
*/
61-
trait Roller[I] {
62-
type K
63-
def apply(in: I): TraversableOnce[K]
64-
}
65-
6634
object Cuber {
6735
implicit def cuber[T]: Cuber[T] = macro cuberImpl[T]
6836

@@ -110,52 +78,3 @@ object Cuber {
11078
c.Expr[Cuber[T]](cuber)
11179
}
11280
}
113-
114-
object Roller {
115-
implicit def roller[T]: Roller[T] = macro rollerImpl[T]
116-
117-
def rollerImpl[T](c: Context)(implicit T: c.WeakTypeTag[T]): c.Expr[Roller[T]] = {
118-
import c.universe._
119-
120-
ensureCaseClass(c)
121-
122-
val params = getParams(c)
123-
val arity = params.length
124-
if (arity > 22)
125-
c.abort(c.enclosingPosition, s"Cannot create Roller for $T because it has more than 22 parameters.")
126-
if (arity == 0)
127-
c.abort(c.enclosingPosition, s"Cannot create Roller for $T because it has no parameters.")
128-
129-
val tupleName = {
130-
val types = getParamTypes(c)
131-
val optionTypes = types.map { t => tq"_root_.scala.Option[$t]" }
132-
val tupleType = newTypeName(s"Tuple${arity}")
133-
tq"_root_.scala.$tupleType[..$optionTypes]"
134-
}
135-
136-
val somes = params.zip(Stream.from(1)).map {
137-
case (param, index) =>
138-
val name = newTermName(s"some$index")
139-
q"val $name = _root_.scala.Some(in.$param)"
140-
}
141-
142-
val items = (0 to arity).map { i =>
143-
val args = (1 to arity).map { index =>
144-
val some = newTermName(s"some$index")
145-
if (index <= i) q"$some" else q"_root_.scala.None"
146-
}
147-
q"new K(..$args)"
148-
}
149-
150-
val roller = q"""
151-
new _root_.com.twitter.algebird.macros.Roller[${T}] {
152-
type K = $tupleName
153-
def apply(in: ${T}): _root_.scala.Seq[K] = {
154-
..$somes
155-
Seq(..$items)
156-
}
157-
}
158-
"""
159-
c.Expr[Roller[T]](roller)
160-
}
161-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.twitter.algebird.macros
2+
3+
import scala.language.experimental.{ macros => sMacros }
4+
import scala.reflect.macros.Context
5+
import scala.reflect.runtime.universe._
6+
7+
/**
8+
* Given a TupleN, produces a sequence of (N + 1) tuples each of arity N
9+
* such that, for all k from 0 to N, there is a tuple with k Somes
10+
* followed by (N - k) Nones.
11+
*
12+
* This is useful for comparing some metric across multiple layers of
13+
* some hierarchy.
14+
* For example, suppose we have some climate data represented as
15+
* case class Data(continent: String, country: String, city: String, temperature: Double)
16+
* and we want to know the average temperatures of
17+
* - each continent
18+
* - each (continent, country) pair
19+
* - each (continent, country, city) triple
20+
*
21+
* Here we desire the (continent, country) and (continent, country, city)
22+
* pair because, for example, if we grouped by city instead of by
23+
* (continent, country, city), we would accidentally combine the results for
24+
* Paris, Texas and Paris, France.
25+
*
26+
* Then we could do
27+
* > import com.twitter.algebird.macros.Roller.roller
28+
* > val data: List[Data]
29+
* > val averageTemps: Map[(Option[String], Option[String], Option[String]), Double] =
30+
* > data.flatMap { d => roller((d.continent, d.country, d.city)).map((_, d)) }
31+
* > .groupBy(_._1)
32+
* > .mapValues { xs => val temps = xs.map(_.temperature); temps.sum / temps.length }
33+
*/
34+
trait Roller[I] {
35+
type K
36+
def apply(in: I): TraversableOnce[K]
37+
}
38+
39+
object Roller {
40+
implicit def roller[T]: Roller[T] = macro rollerImpl[T]
41+
42+
def rollerImpl[T](c: Context)(implicit T: c.WeakTypeTag[T]): c.Expr[Roller[T]] = {
43+
import c.universe._
44+
45+
ensureCaseClass(c)
46+
47+
val params = getParams(c)
48+
val arity = params.length
49+
if (arity > 22)
50+
c.abort(c.enclosingPosition, s"Cannot create Roller for $T because it has more than 22 parameters.")
51+
if (arity == 0)
52+
c.abort(c.enclosingPosition, s"Cannot create Roller for $T because it has no parameters.")
53+
54+
val tupleName = {
55+
val types = getParamTypes(c)
56+
val optionTypes = types.map { t => tq"_root_.scala.Option[$t]" }
57+
val tupleType = newTypeName(s"Tuple${arity}")
58+
tq"_root_.scala.$tupleType[..$optionTypes]"
59+
}
60+
61+
val somes = params.zip(Stream.from(1)).map {
62+
case (param, index) =>
63+
val name = newTermName(s"some$index")
64+
q"val $name = _root_.scala.Some(in.$param)"
65+
}
66+
67+
val items = (0 to arity).map { i =>
68+
val args = (1 to arity).map { index =>
69+
val some = newTermName(s"some$index")
70+
if (index <= i) q"$some" else q"_root_.scala.None"
71+
}
72+
q"new K(..$args)"
73+
}
74+
75+
val roller = q"""
76+
new _root_.com.twitter.algebird.macros.Roller[${T}] {
77+
type K = $tupleName
78+
def apply(in: ${T}): _root_.scala.Seq[K] = {
79+
..$somes
80+
Seq(..$items)
81+
}
82+
}
83+
"""
84+
c.Expr[Roller[T]](roller)
85+
}
86+
}

algebird-test/src/test/scala/com/twitter/algebird/CombinatorTest.scala

+10-17
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,17 @@ class CombinatorTest extends CheckProperties {
2828
Arbitrary.arbitrary[T].map { t => Max(t) }
2929
}
3030

31-
implicit val sg: Semigroup[(Max[Int], List[Int])] =
32-
new SemigroupCombinator({ (m: Max[Int], l: List[Int]) =>
33-
val sortfn = { (i: Int) => i % (scala.math.sqrt(m.get.toLong - Int.MinValue).toInt + 1) }
34-
l.sortWith { (l, r) =>
35-
val (sl, sr) = (sortfn(l), sortfn(r))
36-
if (sl == sr) l < r else sl < sr
37-
}
38-
})
31+
private def fold(m: Max[Int], l: List[Int]): List[Int] = {
32+
val sortfn = { (i: Int) => i % (scala.math.sqrt(m.get.toLong - Int.MinValue).toInt + 1) }
33+
l.sortWith { (l, r) =>
34+
val (sl, sr) = (sortfn(l), sortfn(r))
35+
if (sl == sr) l < r else sl < sr
36+
}
37+
}
38+
39+
implicit val sg: Semigroup[(Max[Int], List[Int])] = new SemigroupCombinator(fold)
40+
implicit val mond: Monoid[(Max[Int], List[Int])] = new MonoidCombinator(fold)
3941

40-
implicit val mond: Monoid[(Max[Int], List[Int])] =
41-
new MonoidCombinator({ (m: Max[Int], l: List[Int]) =>
42-
val sortfn = { (i: Int) => i % (scala.math.sqrt(m.get.toLong - Int.MinValue).toInt + 1) }
43-
l.sortWith { (l, r) =>
44-
val (sl, sr) = (sortfn(l), sortfn(r))
45-
if (sl == sr) l < r else sl < sr
46-
}
47-
})
4842
// Make sure the lists start sorted:
4943
implicit def pairArb(implicit lista: Arbitrary[List[Int]]): Arbitrary[(Max[Int], List[Int])] =
5044
Arbitrary {
@@ -84,5 +78,4 @@ class CombinatorTest extends CheckProperties {
8478
property("MonoidCombinator with top-K forms a Monoid") {
8579
monoidLaws[(Map[Int, Int], Set[Int])]
8680
}
87-
8881
}

0 commit comments

Comments
 (0)