From cb0e6c3e754595fa565ceb1e6019bcdb788c275c Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Thu, 12 Jan 2017 13:43:21 +0100 Subject: Add `site.posts` and make DefaultParams typesafe --- .../dotty/tools/dottydoc/staticsite/BlogPost.scala | 56 ++++++++++++++++++++++ .../tools/dottydoc/staticsite/DefaultParams.scala | 37 ++++++++++++++ .../tools/dottydoc/staticsite/MapOperations.scala | 25 ++++++++++ .../src/dotty/tools/dottydoc/staticsite/Site.scala | 40 +++++++++------- 4 files changed, 142 insertions(+), 16 deletions(-) create mode 100644 doc-tool/src/dotty/tools/dottydoc/staticsite/BlogPost.scala create mode 100644 doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala create mode 100644 doc-tool/src/dotty/tools/dottydoc/staticsite/MapOperations.scala (limited to 'doc-tool') diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/BlogPost.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/BlogPost.scala new file mode 100644 index 000000000..4683ed5f9 --- /dev/null +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/BlogPost.scala @@ -0,0 +1,56 @@ +package dotty.tools +package dottydoc +package staticsite + +import java.io.{ File => JFile } +import java.util.{ List => JList, Map => JMap } + +import dotc.config.Printers.dottydoc + +import MapOperations._ + +class BlogPost( + val title: String, + val url: String, + val date: String, + val content: String, + firstParagraph: String, + val excerptSep: Option[String], + val categories: JList[String] +) { + import scala.collection.JavaConverters._ + lazy val excerpt: String = excerptSep match { + case Some(str) => content.split(str).head + case _ => firstParagraph + } + + lazy val toMap: JMap[String, AnyRef] = Map( + "title" -> title, + "date" -> date, + "url" -> url, + "excerpt" -> excerpt, + "excerpt_separator" -> excerptSep.getOrElse(""), + "content" -> content, + "categories" -> categories + ).asJava +} + +object BlogPost { + val extract = """(\d\d\d\d)-(\d\d)-(\d\d)-(.*)\.(md|html)""".r + def apply(file: JFile, page: Page): BlogPost = { + def report(key: String, fallback: String = "") = { + /*dottydoc.*/println(s"couldn't find page.$key in ${file.getName}") + fallback + } + + // Relying on the person using this class to pass a valid `file` + val extract(year, month, day, name, _) = file.getName + val title = page.yaml.getString("title").getOrElse(report("title", name)) + val url = page.yaml.getString("url").getOrElse(report("url")) + val date = page.yaml.getString("date").getOrElse(s"$year-$month-$day 00:00:00") + val excerptSep = page.yaml.getString("excerpt_separator") + val categories = page.yaml.list("categories") + + new BlogPost(title, url, date, page.html, page.firstParagraph, excerptSep, categories) + } +} diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala new file mode 100644 index 000000000..d0f49100c --- /dev/null +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/DefaultParams.scala @@ -0,0 +1,37 @@ +package dotty.tools +package dottydoc +package staticsite + +import java.util.{ List => JList } + +case class DefaultParams( + docs: JList[_], + page: PageInfo, + site: SiteInfo +) { + + import scala.collection.JavaConverters._ + def toMap: Map[String, AnyRef] = Map( + "docs" -> docs, + "page" -> Map( + "url" -> page.url, + "path" -> page.path + ), + "site" -> Map( + "baseurl" -> site.baseurl, + "posts" -> site.posts.map(_.toMap) + ).asJava + ) + + def withPosts(posts: Array[BlogPost]): DefaultParams = + copy(site = SiteInfo(site.baseurl, posts)) + + def withUrl(url: String): DefaultParams = + copy(page = PageInfo(url)) +} + +case class PageInfo(url: String) { + val path: Array[String] = url.split('/').reverse.drop(1) +} + +case class SiteInfo(baseurl: String, posts: Array[BlogPost]) diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/MapOperations.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/MapOperations.scala new file mode 100644 index 000000000..9dd88cb67 --- /dev/null +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/MapOperations.scala @@ -0,0 +1,25 @@ +package dotty.tools +package dottydoc +package staticsite + +import java.util.{ List => JList, Map => JMap } + +/** A simple wrapper for Maps to impose a certain degree of typesafety */ +object MapOperations { + implicit class SaferMap(val map: Map[String, AnyRef]) extends AnyVal { + // `AnyRef` is actually `String | JList[String]` + def getString(str: String): Option[String] = map.get(str).flatMap { + case res: String => Some(res) + case _ => None + } + + def getList(str: String): Option[JList[String]] = map.get(str).flatMap { + case res: JList[String] @unchecked => Some(res) + case _ => None + } + + def string(str: String): String = getString(str).getOrElse("") + def list(str: String): JList[String] = getList(str).getOrElse(new java.util.ArrayList[String]) + } +} + diff --git a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala index 1b40ddaea..21abeda38 100644 --- a/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala +++ b/doc-tool/src/dotty/tools/dottydoc/staticsite/Site.scala @@ -57,6 +57,20 @@ case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder { _blogposts } + protected lazy val blogInfo: Array[BlogPost] = + blogposts + .map { file => + val BlogPost.extract(year, month, day, name, ext) = file.getName + val fileContents = Source.fromFile(file).mkString + val params = defaultParams(file, 2).withUrl(s"/blog/$year/$month/$day/$name.html").toMap + val page = + if (ext == "md") new MarkdownPage(fileContents, params, includes) + else new HtmlPage(fileContents, params, includes) + BlogPost(file, page) + } + .sortBy(_.date) + .reverse + // FileSystem getter private[this] val fs = FileSystems.getDefault @@ -87,7 +101,7 @@ case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder { this } - def defaultParams(pageLocation: JFile, additionalDepth: Int = 0): Map[String, AnyRef] = { + private def defaultParams(pageLocation: JFile, additionalDepth: Int = 0): DefaultParams = { import scala.collection.JavaConverters._ val pathFromRoot = stripRoot(pageLocation) val baseUrl: String = { @@ -96,14 +110,7 @@ case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder { "../" * (assetLen - rootLen - 1 + additionalDepth) + "." } - Map( - "docs" -> docs, - "page" -> Map( - "url" -> pathFromRoot, - "path" -> pathFromRoot.split('/').reverse.drop(1) - ), - "site" -> Map("baseurl" -> baseUrl).asJava - ) + DefaultParams(docs, PageInfo(pathFromRoot), SiteInfo(baseUrl, Array())) } /** Generate HTML files from markdown and .html sources */ @@ -113,9 +120,10 @@ case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder { else compilableFiles.foreach { asset => val pathFromRoot = stripRoot(asset) val fileContents = Source.fromFile(asset).mkString + val params = defaultParams(asset).withPosts(blogInfo).toMap val page = - if (asset.getName.endsWith(".md")) new MarkdownPage(fileContents, defaultParams(asset), includes) - else new HtmlPage(fileContents, defaultParams(asset), includes) + if (asset.getName.endsWith(".md")) new MarkdownPage(fileContents, params, includes) + else new HtmlPage(fileContents, params, includes) val renderedPage = render(page) val source = new ByteArrayInputStream(renderedPage.getBytes(StandardCharsets.UTF_8)) @@ -128,11 +136,12 @@ case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder { def generateBlog(outDir: JFile = new JFile(root.getAbsolutePath + "/_site"))(implicit ctx: Context): Unit = { blogposts.foreach { file => - val Post(year, month, day, name, ext) = file.getName + val BlogPost.extract(year, month, day, name, ext) = file.getName val fileContents = Source.fromFile(file).mkString + val params = defaultParams(file, 2).withPosts(blogInfo).toMap val page = - if (ext == "md") new MarkdownPage(fileContents, defaultParams(file, 2), includes) - else new HtmlPage(fileContents, defaultParams(file, 2), includes) + if (ext == "md") new MarkdownPage(fileContents, params, includes) + else new HtmlPage(fileContents, params, includes) val source = new ByteArrayInputStream(render(page).getBytes(StandardCharsets.UTF_8)) val target = mkdirs(fs.getPath(outDir.getAbsolutePath, "blog", year, month, day, name + ".html")) @@ -162,7 +171,6 @@ case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder { f.getAbsolutePath.drop(rootLen) } - private[this] val Post = """(\d\d\d\d)-(\d\d)-(\d\d)-(.*)\.(md|html)""".r // Initialization of `staticAssets` and `compilableAssets`, and `blogPosts`: private[this] var _staticAssets: Array[JFile] = _ private[this] var _compilableFiles: Array[JFile] = _ @@ -181,7 +189,7 @@ case class Site(val root: JFile, val docs: JList[_]) extends ResourceFinder { // Collect posts from ./blog/_posts def collectPosts(file: JFile): Option[JFile] = file.getName match { - case Post(year, month, day, name, ext) => Some(file) + case BlogPost.extract(year, month, day, name, ext) => Some(file) case _ => None } -- cgit v1.2.3