diff --git a/.gitignore b/.gitignore index 9c07d4a..349cac9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,18 @@ *.class *.log + +# sbt specific +.cache/ +.history/ +.lib/ +dist/* +target/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ + +# Scala-IDE specific +.scala_dependencies +.worksheet +.idea \ No newline at end of file diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..f7730b7 --- /dev/null +++ b/build.sbt @@ -0,0 +1,9 @@ +name := "ScalaLabs" + +version := "0.1" + +scalaVersion := "2.12.11" + +libraryDependencies += "org.typelevel" %% "cats-core" % "2.0.0" + +libraryDependencies += "org.scalatest" %% "scalatest" % "3.1.1" % "test" diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..f37b0aa --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.3.10 \ No newline at end of file diff --git a/src/main/scala/main.scala b/src/main/scala/main.scala new file mode 100644 index 0000000..2b5e14e --- /dev/null +++ b/src/main/scala/main.scala @@ -0,0 +1,104 @@ +import java.nio.file.{Files, Path, Paths, StandardCopyOption} + +import cats.data.{IndexedStateT, StateT} +import cats.{Applicative, Functor, Id, Monad} +import cats.syntax.all._ +import cats.instances.list._ + +import scala.language.higherKinds + +import scala.collection.JavaConverters._ + +trait MkDir[F[_], Dir] { + def mkDir(dir: Dir, name: String): F[Dir] +} + +trait MkFile[F[_], Dir, File] { + def mkFile(dir: Dir, name: String): F[File] +} + +trait Printer[F[_], File] { + def printName(file: File): F[Unit] +} + +trait GetFiles[F[_], Dir, File] { + def getFiles(dir: Dir): F[List[File]] +} + +trait GetFileName[F[_], File]{ + def getFileName(file: File): F[String] +} + +trait MoveFile[F[_], Dir, File] { + def moveFile(file: File, dest: Dir): F[File] +} + +class Program[F[_], Dir, File](implicit + F: Monad[F], + mkDir: MkDir[F, Dir], + mkFile: MkFile[F, Dir, File], + printer: Printer[F, File], + getFiles: GetFiles[F, Dir, File], + getFileName: GetFileName[F, File], + moveFile: MoveFile[F, Dir, File]) { + def run(dir: Dir, dirName: String, fileNames: List[String]): F[Unit] = for { + newDir <- mkDir.mkDir(dir, dirName) + _ <- fileNames.traverse(name => mkFile.mkFile(newDir, name)) + files <- getFiles.getFiles(newDir) + _ <- files.traverse(file => printer.printName(file)) + names <- files.traverse(file => getFileName.getFileName(file)) + letters = names.map(_.head) + dirs <- letters.traverse(letter => mkDir.mkDir(newDir, letter.toString)) + _ <- files.zip(dirs).traverse(p => moveFile.moveFile(p._1, p._2)) + } yield () +} + +class RealFileSystem[F[_] : Applicative] extends MkDir[F, Path] with MkFile[F, Path, Path] + with GetFiles [F, Path, Path] with GetFileName[F, Path] with MoveFile [F, Path, Path] { + + override def moveFile(file: Path, dest: Path): F[Path] = { + Files.move(file, dest.resolve(file.getFileName), StandardCopyOption.REPLACE_EXISTING).pure[F] + } + + override def getFileName(file: Path): F[String] = { + file.getFileName.toString.pure[F] + } + + override def getFiles(dir: Path): F[List[Path]] = { + Files.list(dir).filter(Files.isRegularFile(_)).iterator().asScala.toList.pure[F] + } + + override def mkDir(dir: Path, name: String): F[Path] = { + if (Files.exists(dir.resolve(name))) { + dir.resolve(name).pure[F] + } else { + Files.createDirectories(dir.resolve(name)).pure[F] + } + } + + override def mkFile(dir: Path, name: String): F[Path] = { + if (Files.exists(dir.resolve(name))) { + dir.resolve(name).pure[F] + } else { + Files.createFile(dir.resolve(name)).pure[F] + } + } +} + + class ConsoleRealPrinter[F[_] : Applicative] extends Printer[F, Path] { + override def printName(file: Path): F[Unit] = println(file.getFileName).pure[F] + } + +object TypeClasses { + def main(args: Array[String]): Unit = { + + implicit val fs: RealFileSystem[Id] = new RealFileSystem[Id] + implicit val printer: ConsoleRealPrinter[Id] = new ConsoleRealPrinter[Id] + val program = new Program[Id, Path, Path] + + program.run(Paths.get("."), "test_dir", List("foo", "bar", "baz")) + } +} + + + diff --git a/src/test/scala/test.scala b/src/test/scala/test.scala new file mode 100644 index 0000000..3db1f6d --- /dev/null +++ b/src/test/scala/test.scala @@ -0,0 +1,44 @@ +import java.nio.file.{Files, Path, Paths} +import java.util.Comparator + +import cats.Id +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + + +class test extends AnyFlatSpec with Matchers { + val root: Path = Paths.get("./tmp") + Files.createDirectory(root) + + implicit val fs: RealFileSystem[Id] = new RealFileSystem[Id] + implicit val printer: ConsoleRealPrinter[Id] = new ConsoleRealPrinter[Id] + val program = new Program[Id, Path, Path] + + program.run(root, "test_dir", List("foo", "bar", "baz")) + + var dir: Path = root.resolve("test_dir") + + Files.exists(dir) shouldBe true + + var fDir: Path = dir.resolve("f") + var bDir: Path = dir.resolve("b") + + Files.exists(fDir) shouldBe true + Files.isDirectory(fDir) shouldBe true + Files.exists(bDir) shouldBe true + Files.isDirectory(bDir) shouldBe true + + val foo: Path = fDir.resolve("foo") + val bar: Path = bDir.resolve("bar") + val baz: Path = bDir.resolve("baz") + + Files.exists(foo) shouldBe true + Files.isRegularFile(foo) shouldBe true + Files.exists(bar) shouldBe true + Files.isRegularFile(bar) shouldBe true + Files.exists(baz) shouldBe true + Files.isRegularFile(baz) shouldBe true + + Files.walk(root).sorted(Comparator.reverseOrder()) + .forEach(file => Files.deleteIfExists(file)) +} \ No newline at end of file