summaryrefslogtreecommitdiff
path: root/scalalib/src/test/resource/better-files/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'scalalib/src/test/resource/better-files/README.md')
-rw-r--r--scalalib/src/test/resource/better-files/README.md637
1 files changed, 0 insertions, 637 deletions
diff --git a/scalalib/src/test/resource/better-files/README.md b/scalalib/src/test/resource/better-files/README.md
deleted file mode 100644
index 9877c3bc..00000000
--- a/scalalib/src/test/resource/better-files/README.md
+++ /dev/null
@@ -1,637 +0,0 @@
-# better-files [![License][licenseImg]][licenseLink] [![CircleCI][circleCiImg]][circleCiLink] [![Codacy][codacyImg]][codacyLink]
-
-`better-files` is a [dependency-free](project/Dependencies.scala) *pragmatic* [thin Scala wrapper](core/src/main/scala/better/files/File.scala) around [Java NIO](https://docs.oracle.com/javase/tutorial/essential/io/fileio.html).
-
-## Talks [![Gitter][gitterImg]][gitterLink]
- - [ScalaDays NYC 2016][scalaDaysNyc2016Event] ([slides][scalaDaysNyc2016Slides])
-
- <a href="http://www.youtube.com/watch?feature=player_embedded&v=uaYKkpqs6CE" target="_blank">
- <img src="site/tech_talk_preview.png" alt="ScalaDays NYC 2016: Introduction to better-files" width="480" height="360" border="10" />
- </a>
-
- - [ScalaDays Berlin 2016][scalaDaysBerlin2016Event] ([video][scalaDaysBerlin2016Video], [slides][scalaDaysBerlin2016Slides])
- - [Scalæ by the Bay 2016][scalæByTheBay2016Event] ([video][scalæByTheBay2016Video], [slides][scalæByTheBay2016Slides])
-
-## Tutorial [![Scaladoc][scaladocImg]][scaladocLink]
- 0. [Instantiation](#instantiation)
- 0. [Simple I/O](#file-readwrite)
- 0. [Streams](#streams)
- 0. [Encodings](#encodings)
- 0. [Java serialization utils](#java-serialization-utils)
- 0. [Java compatibility](#java-interoperability)
- 0. [Globbing](#globbing)
- 0. [File system operations](#file-system-operations)
- 0. [Temporary files](#temporary-files)
- 0. [UNIX DSL](#unix-dsl)
- 0. [File attributes](#file-attributes)
- 0. [File comparison](#file-comparison)
- 0. [Zip/Unzip](#zip-apis)
- 0. [Automatic Resource Management](#lightweight-arm)
- 0. [Scanner](#scanner)
- 0. [File Monitoring](#file-monitoring)
- 0. [Reactive File Watcher](#akka-file-watcher)
-
-## sbt [![UpdateImpact][updateImpactImg]][updateImpactLink]
-In your `build.sbt`, add this:
-```scala
-libraryDependencies += "com.github.pathikrit" %% "better-files" % version
-```
-To use the [Akka based file monitor](akka), also add this:
-```scala
-libraryDependencies ++= Seq(
- "com.github.pathikrit" %% "better-files-akka" % version,
- "com.typesafe.akka" %% "akka-actor" % "2.5.6"
-)
-```
-Latest `version`: [![Maven][mavenImg]][mavenLink] [![Scaladex][scaladexImg]][scaladexLink]
-
-Although this library is currently only actively developed for Scala 2.12 and 2.13,
-you can find reasonably recent versions of this library for Scala 2.10 and 2.11 [here](https://oss.sonatype.org/#nexus-search;quick~better-files).
-
-## Tests [![codecov][codecovImg]][codecovLink]
-* [FileSpec](core/src/test/scala/better/files/FileSpec.scala)
-* [FileWatcherSpec](akka/src/test/scala/better/files/FileWatcherSpec.scala)
-* [Benchmarks](benchmarks/)
-
-[licenseImg]: https://img.shields.io/github/license/pathikrit/better-files.svg
-[licenseImg2]: https://img.shields.io/:license-mit-blue.svg
-[licenseLink]: LICENSE
-
-[circleCiImg]: https://img.shields.io/circleci/project/pathikrit/better-files/master.svg
-[circleCiImg2]: https://circleci.com/gh/pathikrit/better-files/tree/master.svg
-[circleCiLink]: https://circleci.com/gh/pathikrit/better-files
-
-[codecovImg]: https://img.shields.io/codecov/c/github/pathikrit/better-files/master.svg
-[codecovImg2]: https://codecov.io/github/pathikrit/better-files/coverage.svg?branch=master
-[codecovLink]: http://codecov.io/github/pathikrit/better-files?branch=master
-
-[codacyImg]: https://img.shields.io/codacy/0e2aeb7949bc49e6802afcc43a7a1aa1.svg
-[codacyImg2]: https://api.codacy.com/project/badge/grade/0e2aeb7949bc49e6802afcc43a7a1aa1
-[codacyLink]: https://www.codacy.com/app/pathikrit/better-files/dashboard
-
-[mavenImg]: https://img.shields.io/maven-central/v/com.github.pathikrit/better-files_2.12.svg
-[mavenImg2]: https://maven-badges.herokuapp.com/maven-central/com.github.pathikrit/better-files_2.12/badge.svg
-[mavenLink]: http://search.maven.org/#search%7Cga%7C1%7Cbetter-files
-
-[gitterImg]: https://img.shields.io/gitter/room/pathikrit/better-files.svg
-[gitterImg2]: https://badges.gitter.im/Join%20Chat.svg
-[gitterLink]: https://gitter.im/pathikrit/better-files
-
-[scaladexImg]: https://index.scala-lang.org/pathikrit/better-files/better-files/latest.svg
-[scaladexLink]: https://index.scala-lang.org/pathikrit/better-files
-
-[scaladocImg]: https://www.javadoc.io/badge/com.github.pathikrit/better-files_2.12.svg?color=blue&label=scaladocs
-<!--[scaladocLink]: https://www.javadoc.io/page/com.github.pathikrit/better-files_2.12/latest/better/files/File.html-->
-[scaladocLink]: http://pathikrit.github.io/better-files/latest/api/better/files/File.html
-
-[updateImpactImg]: https://app.updateimpact.com/badge/704376701047672832/root.svg?config=compile
-[updateImpactLink]: https://app.updateimpact.com/latest/704376701047672832/root
-
-[scalaDaysNyc2016Event]: http://event.scaladays.org/scaladays-nyc-2016/#!#schedulePopupExtras-7664
-[scalaDaysNyc2016Video]: https://www.youtube.com/watch?v=uaYKkpqs6CE
-<!--[scalaDaysNyc2016VideoPreview]: http://img.youtube.com/vi/uaYKkpqs6CE/0.jpg-->
-[scalaDaysNyc2016VideoPreview]: site/tech_talk_preview.png
-[scalaDaysNyc2016Slides]: https://slides.com/pathikrit/better-files/
-
-[scalaDaysBerlin2016Event]: http://event.scaladays.org/scaladays-berlin-2016#!#schedulePopupExtras-7668
-[scalaDaysBerlin2016Video]: https://www.youtube.com/watch?v=m2YsD5cgnzI
-[scalaDaysBerlin2016Slides]: https://slides.com/pathikrit/better-files/
-
-[scalæByTheBay2016Event]: http://sched.co/7iUn
-[scalæByTheBay2016Video]: https://www.youtube.com/watch?v=bLiCE6NGjrk&t=251s
-[scalæByTheBay2016Slides]: https://slides.com/pathikrit/better-files/
-
--------
-### Instantiation
-The following are all equivalent:
-```scala
-import better.files._
-import java.io.{File => JFile}
-
-val f = File("/User/johndoe/Documents") // using constructor
-val f1: File = file"/User/johndoe/Documents" // using string interpolator
-val f2: File = "/User/johndoe/Documents".toFile // convert a string path to a file
-val f3: File = new JFile("/User/johndoe/Documents").toScala // convert a Java file to Scala
-val f4: File = root/"User"/"johndoe"/"Documents" // using root helper to start from root
-val f5: File = `~` / "Documents" // also equivalent to `home / "Documents"`
-val f6: File = "/User"/"johndoe"/"Documents" // using file separator DSL
-val f7: File = "/User"/'johndoe/'Documents // same as above but using Symbols instead of Strings
-val f8: File = home/"Documents"/"presentations"/`..` // use `..` to navigate up to parent
-```
-
-**Note**: Rename the import if you think the usage of the class `File` may confuse your teammates:
-```scala
-import better.files.{File => ScalaFile, _}
-import java.io.File
-```
-I personally prefer renaming the Java crap instead:
-```scala
-import better.files._
-import java.io.{File => JFile}
-```
-
-### File Read/Write
-Dead simple I/O:
-```scala
-val file = root/"tmp"/"test.txt"
-file.overwrite("hello")
-file.appendLine().append("world")
-assert(file.contentAsString == "hello\nworld")
-```
-If you are someone who likes symbols, then the above code can also be written as:
-```scala
-import better.files.Dsl.SymbolicOperations
-
-file < "hello" // same as file.overwrite("hello")
-file << "world" // same as file.appendLines("world")
-assert(file! == "hello\nworld")
-```
-Or even, right-associatively:
-```scala
-import better.files.Dsl.SymbolicOperations
-
-"hello" `>:` file
-"world" >>: file
-val bytes: Array[Byte] = file.loadBytes
-```
-[Fluent Interface](https://en.wikipedia.org/wiki/Fluent_interface):
-```scala
- (root/"tmp"/"diary.txt")
- .createIfNotExists()
- .appendLine()
- .appendLines("My name is", "Inigo Montoya")
- .moveToDirectory(home/"Documents")
- .renameTo("princess_diary.txt")
- .changeExtensionTo(".md")
- .lines
-```
-
-### Streams
-Various ways to slurp a file without loading the contents into memory:
- ```scala
-val bytes : Iterator[Byte] = file.bytes
-val chars : Iterator[Char] = file.chars
-val lines : Iterator[String] = file.lineIterator //file.lines loads all lines in memory
-```
-Note: The above APIs can be traversed at most once e.g. `file.bytes` is a `Iterator[Byte]` which only allows `TraversableOnce`.
-To traverse it multiple times without creating a new iterator instance, convert it into some other collection e.g. `file.bytes.toStream`
-
-You can write an `Iterator[Byte]` or an `Iterator[String]` back to a file:
-```scala
-file.writeBytes(bytes)
-file.printLines(lines)
-```
-
-### Encodings
-You can supply your own charset too for anything that does a read/write (it assumes `java.nio.charset.Charset.defaultCharset()` if you don't provide one):
-```scala
-val content: String = file.contentAsString // default charset
-
-// custom charset:
-import java.nio.charset.Charset
-file.contentAsString(charset = Charset.forName("US-ASCII"))
-
-//or simply using implicit conversion from Strings
-file.write("hello world")(charset = "US-ASCII")
- ```
-
-Note: By default, `better-files` [correctly handles BOMs while decoding](core/src/main/scala/better/files/UnicodeCharset.scala).
-If you wish to have the [incorrect JDK behaviour](http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4508058),
-you would need to supply Java's UTF-8 charset e.g.:
-```scala
-file.contentAsString(charset = Charset.forName("UTF-8")) // Default incorrect JDK behaviour for UTF-8 (see: JDK-4508058)
-```
-
-If you also wish to write BOMs while encoding, you would need to supply it as:
-```scala
-file.write("hello world")(charset = UnicodeCharset("UTF-8", writeByteOrderMarkers = true))
-```
-
-### Java serialization utils
-Some common utils to serialize/deserialize using Java's serialization util
-```scala
-case class Person(name: String, age: Int)
-val person = new Person("Chris", 24)
-
-// Write
-file.newOutputStream.buffered.asObjectOutputStream.serialize(obj).flush()
-
-// Read
-val person2 = file.newInputStream.buffered.asObjectInputStream.readObject().asInstanceOf[Person]
-assert(person == person2)
-```
-
-The above can be simply written as:
-```scala
-val person2: Person = file.writeSerialized(person).readDeserialized[Person]
-assert(person == person2)
-```
-
-### Java interoperability
-You can always access the Java I/O classes:
-```scala
-val file: File = tmp / "hello.txt"
-val javaFile : java.io.File = file.toJava
-val uri : java.net.URI = file.uri
-val url : java.net.URL = file.url
-val reader : java.io.BufferedReader = file.newBufferedReader
-val outputstream : java.io.OutputStream = file.newOutputStream
-val writer : java.io.BufferedWriter = file.newBufferedWriter
-val inputstream : java.io.InputStream = file.newInputStream
-val path : java.nio.file.Path = file.path
-val fs : java.nio.file.FileSystem = file.fileSystem
-val channel : java.nio.channel.FileChannel = file.newFileChannel
-val ram : java.io.RandomAccessFile = file.newRandomAccess
-val fr : java.io.FileReader = file.newFileReader
-val fw : java.io.FileWriter = file.newFileWriter(append = true)
-val printer : java.io.PrintWriter = file.newPrintWriter
-```
-The library also adds some useful [implicits](http://pathikrit.github.io/better-files/latest/api/better/files/Implicits.html) to above classes e.g.:
-```scala
-file1.reader > file2.writer // pipes a reader to a writer
-System.in > file2.out // pipes an inputstream to an outputstream
-src.pipeTo(sink) // if you don't like symbols
-
-val bytes : Iterator[Byte] = inputstream.bytes
-val bis : BufferedInputStream = inputstream.buffered
-val bos : BufferedOutputStream = outputstream.buffered
-val reader : InputStreamReader = inputstream.reader
-val writer : OutputStreamWriter = outputstream.writer
-val printer : PrintWriter = outputstream.printWriter
-val br : BufferedReader = reader.buffered
-val bw : BufferedWriter = writer.buffered
-val mm : MappedByteBuffer = fileChannel.toMappedByteBuffer
-val str : String = inputstream.asString //Read a string from an InputStream
-```
-`better-files` also supports [certain conversions that are not supported out of the box by the JDK](https://stackoverflow.com/questions/62241/how-to-convert-a-reader-to-inputstream-and-a-writer-to-outputstream)
-
-[`tee`](http://stackoverflow.com/questions/7987395/) multiple outputstreams:
-```scala
-val s3 = s1 tee s2
-s3.printWriter.println(s"Hello world") // gets written to both s1 and s2
-```
-
-### Globbing
-No need to port [this](http://docs.oracle.com/javase/tutorial/essential/io/find.html) to Scala:
-```scala
-val dir = "src"/"test"
-val matches: Iterator[File] = dir.glob("*.{java,scala}")
-// above code is equivalent to:
-dir.listRecursively.filter(f => f.extension == Some(".java") || f.extension == Some(".scala"))
-```
-
-You can even use more advanced regex syntax instead of [glob syntax](http://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob):
-```scala
-val matches = dir.globRegex("^\\w*$".r) //equivalent to dir.glob("^\\w*$")(syntax = File.PathMatcherSyntax.regex)
-```
-
-By default, glob syntax in `better-files` is [different from](https://github.com/pathikrit/better-files/issues/114)
-the default JDK glob behaviour since it always includes path. To use the default behaviour:
-```scala
-dir.glob("**/*.txt", includePath = false) // JDK default
-//OR
-dir.glob("*.txt", includePath = true) // better-files default
-```
-You can also extend the `File.PathMatcherSyntax` to create your own matchers.
-
-For custom cases:
-```scala
-dir.collectChildren(_.isSymbolicLink) // collect all symlinks in a directory
-```
-For simpler cases, you can always use `dir.list` or `dir.walk(maxDepth: Int)`
-
-### File system operations
-Utilities to `ls`, `cp`, `rm`, `mv`, `ln`, `md5`, `touch`, `cat` etc:
-```scala
-file.touch()
-file.delete() // unlike the Java API, also works on directories as expected (deletes children recursively)
-file.clear() // If directory, deletes all children; if file clears contents
-file.renameTo(newName: String)
-file.moveTo(destination)
-file.moveToDirectory(destination)
-file.copyTo(destination) // unlike the default API, also works on directories (copies recursively)
-file.copyToDirectory(destination)
-file.linkTo(destination) // ln destination file
-file.symbolicLinkTo(destination) // ln -s destination file
-file.{checksum, md5, sha1, sha256, sha512, digest} // also works for directories
-file.setOwner(user: String) // chown user file
-file.setGroup(group: String) // chgrp group file
-Seq(file1, file2) `>:` file3 // same as cat file1 file2 > file3 (must import import better.files.Dsl.SymbolicOperations)
-Seq(file1, file2) >>: file3 // same as cat file1 file2 >> file3 (must import import better.files.Dsl.SymbolicOperations)
-file.isReadLocked; file.isWriteLocked; file.isLocked
-File.numberOfOpenFileDescriptors // number of open file descriptors
-```
-You can also load resources from your classpath using `File.resource` or `File.copyResource`.
-
-### Temporary files
-Utils to create temporary files:
-```scala
-File.newTemporaryDirectory()
-File.newTemporaryFile()
-```
-The above APIs allow optional specifications of `prefix`, `suffix` and `parentDir`.
-These files are [not deleted automatically on exit by the JVM](http://stackoverflow.com/questions/16691437/when-are-java-temporary-files-deleted) (you have to set `deleteOnExit` which adds to `shutdownHook`).
-
-A cleaner alternative is to use self-deleting file contexts which deletes the file immediately when done:
-```scala
-for {
- tempFile <- File.temporaryFile()
-} doSomething(tempFile) // tempFile is auto deleted at the end of this block - even if an exception happens
-```
-
-OR equivalently:
-```scala
-File.usingTemporaryFile() {tempFile =>
- //do something
-} // tempFile is auto deleted at the end of this block - even if an exception happens
-```
-
-You can make any files temporary (i.e. delete after use) by doing this:
-```scala
-val foo = File.home / "Downloads" / "foo.txt"
-
-for {
- temp <- foo.toTemporary
-} doSomething(temp) // foo is deleted at the end of this block - even if an exception happens
-```
-
-### UNIX DSL
-All the above can also be expressed using [methods](http://pathikrit.github.io/better-files/latest/api/better/files/Dsl$.html) reminiscent of the command line:
-```scala
-import better.files._
-import better.files.Dsl._ // must import Dsl._ to bring in these utils
-
-pwd / cwd // current dir
-cp(file1, file2)
-mv(file1, file2)
-rm(file) /*or*/ del(file)
-ls(file) /*or*/ dir(file)
-ln(file1, file2) // hard link
-ln_s(file1, file2) // soft link
-cat(file1)
-cat(file1) >>: file
-touch(file)
-mkdir(file)
-mkdirs(file) // mkdir -p
-chown(owner, file)
-chgrp(owner, file)
-chmod_+(permission, files) // add permission
-chmod_-(permission, files) // remove permission
-md5(file); sha1(file); sha256(file); sha512(file)
-unzip(zipFile)(targetDir)
-zip(file*)(targetZipFile)
-```
-
-### File attributes
-Query various file attributes e.g.:
-```scala
-file.name // simpler than java.io.File#getName
-file.extension
-file.contentType
-file.lastModifiedTime // returns JSR-310 time
-file.owner
-file.group
-file.isDirectory; file.isSymbolicLink; file.isRegularFile
-file.isHidden
-file.hide(); file.unhide()
-file.isOwnerExecutable; file.isGroupReadable // etc. see file.permissions
-file.size // for a directory, computes the directory size
-file.posixAttributes; file.dosAttributes // see file.attributes
-file.isEmpty // true if file has no content (or no children if directory) or does not exist
-file.isParentOf; file.isChildOf; file.isSiblingOf; file.siblings
-file("dos:system") = true // set custom meta-data for file (similar to Files.setAttribute)
-```
-All the above APIs let you specify the [`LinkOption`](http://docs.oracle.com/javase/8/docs/api/java/nio/file/LinkOption.html) either directly:
-```scala
-file.isDirectory(LinkOption.NOFOLLOW_LINKS)
-```
-Or using the [`File.LinkOptions`](http://pathikrit.github.io/better-files/latest/api/better/files/File$$LinkOptions$.html) helper:
-```scala
-file.isDirectory(File.LinkOptions.noFollow)
-```
-
-`chmod`:
-```scala
-import java.nio.file.attribute.PosixFilePermission
-file.addPermission(PosixFilePermission.OWNER_EXECUTE) // chmod +X file
-file.removePermission(PosixFilePermission.OWNER_WRITE) // chmod -w file
-assert(file.permissionsAsString == "rw-r--r--")
-
-// The following are all equivalent:
-assert(file.permissions contains PosixFilePermission.OWNER_EXECUTE)
-assert(file.testPermission(PosixFilePermission.OWNER_EXECUTE))
-assert(file.isOwnerExecutable)
-```
-
-### File comparison
-Use `==` to check for path-based equality and `===` for content-based equality:
-```scala
-file1 == file2 // equivalent to `file1.isSamePathAs(file2)`
-file1 === file2 // equivalent to `file1.isSameContentAs(file2)` (works for regular-files and directories)
-file1 != file2 // equivalent to `!file1.isSamePathAs(file2)`
-file1 !== file2 // equivalent to `!file1.isSameContentAs(file2)`
-```
-There are also various [`Ordering[File]` instances](http://pathikrit.github.io/better-files/latest/api/better/files/File$$Order$.html) included, e.g.:
-```scala
-val files = myDir.list.toSeq
-files.sorted(File.Order.byName)
-files.max(File.Order.bySize)
-files.min(File.Order.byDepth)
-files.max(File.Order.byModificationTime)
-files.sorted(File.Order.byDirectoriesFirst)
-```
-
-### Zip APIs
-You don't have to lookup on StackOverflow "[How to zip/unzip in Java/Scala?](http://stackoverflow.com/questions/9324933/)":
-```scala
-// Unzipping:
-val zipFile: File = file"path/to/research.zip"
-val research: File = zipFile.unzipTo(destination = home/"Documents"/"research")
-
-// Zipping:
-val zipFile: File = directory.zipTo(destination = home/"Desktop"/"toEmail.zip")
-
-// Zipping in:
-val zipFile = File("countries.zip").zipIn(file"usa.txt", file"russia.txt")
-
-// Zipping/Unzipping to temporary files/directories:
-val someTempZipFile: File = directory.zip()
-val someTempDir: File = zipFile.unzip()
-assert(directory === someTempDir)
-
-// Gzip handling:
-File("countries.gz").newInputStream.gzipped.lines.take(10).foreach(println)
-```
-
-### Lightweight ARM
-Auto-close Java closeables:
-```scala
-for {
- in <- file1.newInputStream.autoClosed
- out <- file2.newOutputStream.autoClosed
-} in.pipeTo(out)
-// The input and output streams are auto-closed once out of scope
-```
-`better-files` provides convenient managed versions of all the Java closeables e.g. instead of writing:
-```scala
-for {
- reader <- file.newBufferedReader.autoClosed
-} foo(reader)
-```
-You can write:
-```scala
-for {
- reader <- file.bufferedReader // returns ManagedResource[BufferedReader]
-} foo(reader)
-
-// or simply:
-file.bufferedReader.foreach(foo)
-```
-
-You can also define your own custom disposable resources e.g.:
-```scala
-trait Shutdownable {
- def shutdown(): Unit = ()
-}
-
-object Shutdownable {
- implicit val disposable: Disposable[Shutdownable] = Disposable(_.shutdown())
-}
-
-val s: Shutdownable = ....
-
-for {
- instance <- new ManagedResource(s)
-} doSomething(s) // s is disposed after this
-```
-
-### Scanner
-Although [`java.util.Scanner`](http://docs.oracle.com/javase/8/docs/api/java/util/Scanner.html) has a feature-rich API, it only allows parsing primitives.
-It is also [notoriously slow](https://www.cpe.ku.ac.th/~jim/java-io.html) since it uses regexes and does un-Scala things like returns nulls and throws exceptions.
-
-`better-files` provides a [faster](benchmarks#benchmarks), richer, safer, more idiomatic and compossible [Scala replacement](http://pathikrit.github.io/better-files/latest/api/better/files/Scanner.html)
-that [does not use regexes](core/src/main/scala/better/files/Scanner.scala), allows peeking, accessing line numbers, returns `Option`s whenever possible and lets the user mixin custom parsers:
-```scala
-val data = t1 << s"""
- | Hello World
- | 1 true 2 3
-""".stripMargin
-val scanner: Scanner = data.newScanner()
-assert(scanner.next[String] == "Hello")
-assert(scanner.lineNumber == 1)
-assert(scanner.next[String] == "World")
-assert(scanner.next[(Int, Boolean)] == (1, true))
-assert(scanner.tillEndOfLine() == " 2 3")
-assert(!scanner.hasNext)
-```
-If you are simply interested in tokens, you can use `file.tokens()`
-
-Writing your own custom scanners:
-```scala
-sealed trait Animal
-case class Dog(name: String) extends Animal
-case class Cat(name: String) extends Animal
-
-implicit val animalParser: Scannable[Animal] = Scannable {scanner =>
- val name = scanner.next[String]
- if (name == "Garfield") Cat(name) else Dog(name)
-}
-
-val scanner = file.newScanner()
-println(scanner.next[Animal])
-```
-
-The [shapeless-scanner](shapeless/src/main/scala/better/files/ShapelessScanner.scala) module lets you scan [`HList`s](https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/hlists.scala):
-```scala
-val in = Scanner("""
- 12 Bob True
- 13 Mary False
- 26 Rick True
-""")
-
-import shapeless._
-
-type Row = Int :: String :: Boolean :: HNil
-
-val out = Seq.fill(3)(in.next[Row])
-assert(out == Seq(
- 12 :: "Bob" :: true :: HNil,
- 13 :: "Mary" :: false :: HNil,
- 26 :: "Rick" :: true :: HNil
-))
-```
-
-[and case-classes](https://meta.plasm.us/posts/2015/11/08/type-classes-and-generic-derivation/):
-
-```scala
-case class Person(id: Int, name: String, isMale: Boolean)
-val out2 = Seq.fill(3)(in.next[Person])
-```
-
-Simple CSV reader:
-```scala
-val file = """
- 23,foo
- 42,bar
-"""
-val csvScanner = file.newScanner(StringSpliiter.on(','))
-csvScanner.next[Int] //23
-csvScanner.next[String] //foo
-```
-
-### File Monitoring
-Vanilla Java watchers:
-```scala
-import java.nio.file.{StandardWatchEventKinds => EventType}
-val service: java.nio.file.WatchService = myDir.newWatchService
-myDir.register(service, events = Seq(EventType.ENTRY_CREATE, EventType.ENTRY_DELETE))
-```
-The above APIs are [cumbersome to use](https://docs.oracle.com/javase/tutorial/essential/io/notification.html#process) (involves a lot of type-casting and null-checking),
-are based on a blocking [polling-based model](http://docs.oracle.com/javase/8/docs/api/java/nio/file/WatchKey.html),
-does not easily allow [recursive watching of directories](https://docs.oracle.com/javase/tutorial/displayCode.html?code=https://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java)
-and nor does it easily allow [watching regular files](http://stackoverflow.com/questions/16251273/) without writing a lot of Java boilerplate.
-
-`better-files` abstracts all the above ugliness behind a [simple interface](core/src/main/scala/better/files/File.scala#1100):
-```scala
-val watcher = new FileMonitor(myDir, recursive = true) {
- override def onCreate(file: File, count: Int) = println(s"$file got created")
- override def onModify(file: File, count: Int) = println(s"$file got modified $count times")
- override def onDelete(file: File, count: Int) = println(s"$file got deleted")
-}
-watcher.start()
-```
-Sometimes, instead of overwriting each of the 3 methods above, it is more convenient to override the dispatcher itself:
-```scala
-import java.nio.file.{Path, StandardWatchEventKinds => EventType, WatchEvent}
-
-val watcher = new FileMonitor(myDir, recursive = true) {
- override def onEvent(eventType: WatchEvent.Kind[Path], file: File, count: Int) = eventType match {
- case EventType.ENTRY_CREATE => println(s"$file got created")
- case EventType.ENTRY_MODIFY => println(s"$file got modified $count")
- case EventType.ENTRY_DELETE => println(s"$file got deleted")
- }
-}
-```
-
-### Akka File Watcher
-`better-files` also provides a powerful yet concise [reactive file watcher](akka/src/main/scala/better/files/FileWatcher.scala)
-based on [Akka actors](http://doc.akka.io/docs/akka/snapshot/scala/actors.html) that supports dynamic dispatches:
- ```scala
-import akka.actor.{ActorRef, ActorSystem}
-import better.files._, FileWatcher._
-
-implicit val system = ActorSystem("mySystem")
-
-val watcher: ActorRef = (home/"Downloads").newWatcher(recursive = true)
-
-// register partial function for an event
-watcher ! on(EventType.ENTRY_DELETE) {
- case file if file.isDirectory => println(s"$file got deleted")
-}
-
-// watch for multiple events
-watcher ! when(events = EventType.ENTRY_CREATE, EventType.ENTRY_MODIFY) {
- case (EventType.ENTRY_CREATE, file, count) => println(s"$file got created")
- case (EventType.ENTRY_MODIFY, file, count) => println(s"$file got modified $count times")
-}
-```