Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

migrate to mdoc from tut #542

Merged
merged 1 commit into from
Mar 14, 2020
Merged
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
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,19 @@ sbt textLint src/introduction.md
# リンク切れ確認
sbt textLinkTest

# tutキャッシュなしのビルド
# mdocのビルド
sbt textBuildHtml

# 全ての検査を実行した後にビルド
sbt textBuildAllWithCheck
```

### tut
### mdoc

[tut](https://github.com/tpolecat/tut)という、Scalaコードを書くと、そのコードのチェックや
[mdoc](https://scalameta.org/mdoc/))という、Scalaコードを書くと、そのコードのチェックや
元のソースとなるmarkdownファイルから、実行後の出力を付け加えたmarkdownに変換してくれるツールを使用している。
Scalaのコード例をテキスト中に書く場合は、使用可能な箇所では出来る限りtutを使うこと
tut自体の具体的な使用方法は、tutのREADMEなどを参照すること
Scalaのコード例をテキスト中に書く場合は、使用可能な箇所では出来る限りmdocを使うこと
mdoc自体の具体的な使用方法は、mdocのREADMEなどを参照すること

### gitbookで特別視されるファイルについて

Expand Down
8 changes: 4 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ name := "textbook"

scalaVersion := "2.12.8"

enablePlugins(TutPlugin)
enablePlugins(MdocPlugin)

tutSourceDirectory := srcDir
mdocIn := srcDir

tutTargetDirectory := compiledSrcDir
mdocOut := compiledSrcDir

libraryDependencies ++= Seq(
"org.scala-sbt" % "sbt" % sbtVersion.value,
"org.mockito" % "mockito-core" % "3.3.3",
"org.scalacheck" %% "scalacheck" % "1.14.3",
"org.scalatest" %% "scalatest" % "3.1.1" // tutで使うので、テストライブラリだが、わざとcompileスコープ
"org.scalatest" %% "scalatest" % "3.1.1" // mdocで使うので、テストライブラリだが、わざとcompileスコープ
)

GitBook.settings
Expand Down
15 changes: 6 additions & 9 deletions project/GitBook.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sbt._
import sbt.io.IO
import tut.TutPlugin.autoImport._
import mdoc.MdocPlugin.autoImport._
import scala.sys.process.Process

object GitBook extends NpmCliBase {
Expand All @@ -21,19 +21,16 @@ object GitBook extends NpmCliBase {

lazy val textPluginInstall = taskKey[Unit]("install GitBook plugin")
lazy val textHelpGitBook = taskKey[Unit]("help GitBook")
lazy val textBuildHtmlQuick = inputKey[Unit]("build GitBook to html with tut cache")
lazy val textBuildHtmlQuick = inputKey[Unit]("build GitBook to html with mdoc cache")
lazy val textBuildHtml = inputKey[Unit]("build GitBook to html")
lazy val textBuildEpub = inputKey[Unit]("build GitBook to epub")
lazy val textBuildPdf = inputKey[Unit]("build GitBook to pdf")

private[this] val mdocTask = mdoc.toTask("")

val settings = Seq(
textPluginInstall := printRun(Process(s"$gitbookBin install")),
textHelpGitBook := printRun(Process(s"$gitbookBin help")),
textBuildHtml := buildBook(Format.Html).dependsOn(tut).evaluated,
textBuildEpub := buildBook(Format.Epub).dependsOn(tut).evaluated,
textBuildPdf := sys.error("pdf-convertで利用するcalibreがcentOS6で上手く動かないので停止中"),

// キャッシュ付きのtutを利用する
textBuildHtmlQuick := buildBook(Format.Html).dependsOn(tutQuick).evaluated
textBuildHtml := buildBook(Format.Html).dependsOn(mdocTask).evaluated,
textBuildEpub := buildBook(Format.Epub).dependsOn(mdocTask).evaluated
)
}
2 changes: 1 addition & 1 deletion project/NpmCliBase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ trait NpmCliBase {
// gitbookのビルドの起点/成果物が入るディレクトリ(gitbook/_book/index.html, gitbook/scala_text.epubが生成される)
val bookDestDir = file("gitbook")

// tutで処理済みのmarkdownファイルが入るディレクトリ。これがgitbook buildされる
// mdocで処理済みのmarkdownファイルが入るディレクトリ。これがgitbook buildされる
// book.jsonのrootにも指定されている。
val compiledSrcDir = bookDestDir

Expand Down
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
logLevel := Level.Warn

addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.6.13")
addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.1.1" )
12 changes: 6 additions & 6 deletions src/basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ scala>

まずは定番のHello, World!を表示させてみましょう。

```tut
```scala mdoc:nest
println("Hello, World!")
```

無事、Hello, World!が表示されるはずです。次にちょっと入力を変えて、`println()`をはずしてみましょう。
さて、どうなるでしょうか。

```tut
```scala mdoc:nest
"Hello, World!"
```

Expand Down Expand Up @@ -87,7 +87,7 @@ res2: Int = 3
この機能はREPLで少し長いプログラムを入力するときに便利ですので、活用していきましょう。Int型には他にも`+`,`-`,`*`,`/`といった
演算子が用意されており、次のようにして使うことができます。

```tut
```scala mdoc:nest
1 + 2

2 * 2
Expand All @@ -101,7 +101,7 @@ res2: Int = 3
見ればわかるように、`Double`という`Int`と異なる型が用意されています。`dbl.asInstanceOf[Int]`のようにキャストして型を変換することが
できますが、その場合、浮動小数点数の小数の部分が切り捨てられることに注意してください。

```tut
```scala mdoc:nest
1.0 + 2.0

2.2 * 2
Expand Down Expand Up @@ -153,7 +153,7 @@ Javaのfinalな変数と同じように考えれば良いでしょう。
それでは、変数を使ってみることにします。Scalaでは基本的に、`var`はあまり使わず`val`のみでプログラミングします。これは**Scalaでプログラミングをする上で大変重要なことなので**忘れない
ようにしてください。

```tut
```scala mdoc:nest
val x = 3 * 2
```

Expand Down Expand Up @@ -195,7 +195,7 @@ x: Int = 12

のようにします。

```tut
```scala mdoc:nest
val x: Int = 3 * 3
```

Expand Down
53 changes: 29 additions & 24 deletions src/case-class-and-pattern-matching.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

簡単なケースクラスによるデータ型を定義してみます。

```tut:silent
```scala mdoc:nest:silent
sealed abstract class DayOfWeek
case object Sunday extends DayOfWeek
case object Monday extends DayOfWeek
Expand All @@ -20,7 +20,7 @@ case object Saturday extends DayOfWeek
これは、一週間の曜日を表すデータ型です。CやJavaの`enum`に似ていますね。実際、同じように使うことができます。
たとえば、以下のように`DayOfWeek`型の変数に`Sunday`を代入することができます。

```tut:silent
```scala mdoc:nest:silent
val x: DayOfWeek = Sunday
```

Expand All @@ -37,7 +37,7 @@ val x: DayOfWeek = Sunday

のようになります。`DayOfWeek`の場合、次のようにして使うことができます。

```tut
```scala mdoc:nest
x match {
case Sunday => 1
case Monday => 2
Expand All @@ -64,7 +64,7 @@ x match {
二項演算の結果として小数が現れた場合は小数部を切り捨てることとします。これを表すデータ型
をScalaで定義すると次のようになります。

```tut:silent
```scala mdoc:nest:silent
sealed abstract class Exp
case class Add(lhs: Exp, rhs: Exp) extends Exp
case class Sub(lhs: Exp, rhs: Exp) extends Exp
Expand All @@ -76,14 +76,14 @@ case class Lit(value: Int) extends Exp
全てのデータ型に`case`修飾子がついているので、これらのデータ型はパターンマッチングのパターンとして使うことができます。
この定義から、`1 + ((2 * 3) / 2)`という式を表すノードを構築します。

```tut
```scala mdoc:nest
val example = Add(Lit(1), Div(Mul(Lit(2), Lit(3)), Lit(2)))
```

この`example`ノードを元に四則演算を定義する関数を定義してみます。関数の定義の
詳細は後ほど説明しますが、ここでは雰囲気だけをつかんでください。

```tut
```scala mdoc:nest
def eval(exp: Exp): Int = exp match {
case Add(l, r) => eval(l) + eval(r)
case Sub(l, r) => eval(l) - eval(r)
Expand All @@ -95,7 +95,7 @@ def eval(exp: Exp): Int = exp match {

この定義をREPLに読み込ませて、`eval(example)`として、

```tut
```scala mdoc:nest
eval(example)
```

Expand Down Expand Up @@ -124,13 +124,13 @@ It would fail on the following input: Lit(_)

たとえば、次のようなケースクラス`Point`があったとします。

```tut
```scala mdoc:nest
case class Point(x: Int, y: Int)
```

このケースクラス`Point`に対して、

```tut
```scala mdoc:nest
val Point(x, y) = Point(10, 20)
```

Expand Down Expand Up @@ -171,7 +171,7 @@ res5: Boolean = false
クラスに実装を足すことでも同等の振る舞いを持たせることもできます。
例えば、前節で定義した`Point`をケースクラスを使わずに定義するとしたら、次のようになるでしょう。

```tut
```scala mdoc:nest
class Point(val x: Int, val y: Int) {
override def equals(that: Any): Boolean = that match {
case thatPoint: Point =>
Expand Down Expand Up @@ -209,15 +209,15 @@ object Point {

`DayOfWeek`型を使って、ある日の次の曜日を返すメソッド`nextDayOfWeek`

```tut:silent
```scala mdoc:nest:silent
def nextDayOfWeek(d: DayOfWeek): DayOfWeek = ???
```

をパターンマッチを用いて定義してみましょう。

<!-- begin answer id="answer_ex1" style="display:none" -->

```tut:silent
```scala mdoc:nest:silent
def nextDayOfWeek(d: DayOfWeek): DayOfWeek = d match {
case Sunday => Monday
case Monday => Tuesday
Expand All @@ -229,7 +229,7 @@ def nextDayOfWeek(d: DayOfWeek): DayOfWeek = d match {
}
```

```tut
```scala mdoc:nest
nextDayOfWeek(Sunday)
nextDayOfWeek(Monday)
nextDayOfWeek(Saturday)
Expand All @@ -241,15 +241,15 @@ nextDayOfWeek(Saturday)

二分木(子の数が最大で2つであるような木構造)を表す型`Tree`と`Branch`, `Empty`を考えます:

```tut:silent
```scala mdoc:nest:silent
sealed abstract class Tree
case class Branch(value: Int, left: Tree, right: Tree) extends Tree
case object Empty extends Tree
```

子が2つで左の子の値が`2`、右の子の値が`3`、自分自身の値が`1`の木構造はたとえば次のようにして定義することができます。

```tut
```scala mdoc:nest
val tree: Tree = Branch(1, Branch(2, Empty, Empty), Branch(3, Empty, Empty))
```

Expand All @@ -259,7 +259,7 @@ val tree: Tree = Branch(1, Branch(2, Empty, Empty), Branch(3, Empty, Empty))
2. 最小値を求める`min`メソッド:
3. 深さを求める`depth`メソッド:

```tut:silent
```scala mdoc:nest:silent
def max(tree: Tree): Int = ???
def min(tree: Tree): Int = ???
def depth(tree: Tree): Int = ???
Expand Down Expand Up @@ -296,15 +296,15 @@ depth(Branch(10, Branch(20,

となるような木構造に変換する`sort`メソッド:

```tut:silent
```scala mdoc:nest:silent
def sort(tree: Tree): Tree = ???
```

を定義してみましょう。なお、`sort`メソッドは、葉ノードでないノードの個数と値が同じであれば元の構造と同じでなくても良いものとします。

<!-- begin answer id="answer_ex2" style="display:none" -->

```tut:silent
```scala mdoc:nest:silent
object BinaryTree {
sealed abstract class Tree
case class Branch(value: Int, left: Tree, right: Tree) extends Tree
Expand Down Expand Up @@ -382,9 +382,14 @@ object BinaryTree {
}
```

```tut:invisible
```scala mdoc:nest:invisible
import org.scalacheck._, Arbitrary.arbitrary

def test[G] (g: Gen[G])(f: G => Boolean) = {
val result = Prop.forAll(g)(f).apply(Gen.Parameters.default)
assert(result.success, result)
}

val nonEmptyTreeGen: Gen[BinaryTree.Tree] = {

lazy val branchGen: Gen[BinaryTree.Tree] = for{
Expand All @@ -402,11 +407,11 @@ val nonEmptyTreeGen: Gen[BinaryTree.Tree] = {
branchGen
}

Testing.test(nonEmptyTreeGen){ tree =>
test(nonEmptyTreeGen){ tree =>
BinaryTree.max(tree) == BinaryTree.toList(tree).max
}

Testing.test(nonEmptyTreeGen){ tree =>
test(nonEmptyTreeGen){ tree =>
BinaryTree.min(tree) == BinaryTree.toList(tree).min
}
```
Expand All @@ -419,7 +424,7 @@ Testing.test(nonEmptyTreeGen){ tree =>
これまでの説明の中で、無名関数とパターンマッチングについて説明してきましたが、この2つの機能を組み合わせた
部分関数(PartialFunction)がScalaには存在します。説明の前に、まず、具体的なユースケースを挙げます:

```tut
```scala mdoc:nest
List(1, 2, 3, 4, 5).collect { case i if i % 2 == 1 => i * 2 }
```

Expand Down Expand Up @@ -455,7 +460,7 @@ i % 2 == 1
が生成されるのであって、通常の `FunctionN` 型が要求されたときには、違う意味を持つということです。たとえば、以下のような
定義があったとします。

```tut
```scala mdoc:nest
val even: Int => Boolean = {
case i if i % 2 == 0 => true
case _ => false
Expand All @@ -464,7 +469,7 @@ val even: Int => Boolean = {

このとき、この定義は、無名関数とパターンマッチを組み合わせたものと同じ意味になります。この点にだけ注意してください。

```tut
```scala mdoc:nest
val even: Int => Boolean = (x => x match {
case i if i % 2 == 0 => true
case _ => false
Expand Down
Loading