Skip to content

Commit 865fb6f

Browse files
committed
MkDir command implementation
1 parent 7131e15 commit 865fb6f

File tree

5 files changed

+132
-5
lines changed

5 files changed

+132
-5
lines changed

filesystem/src/main/scala/com/codingmaniacs/scala/exercises/fs/State.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ package com.codingmaniacs.scala.exercises.fs
2424
import com.codingmaniacs.scala.exercises.fs.directories.Directory
2525

2626
class State(val root: Directory, val workingDir: Directory, val output: String) {
27-
def show(): Unit = print(State.SHELL_PROMPT)
27+
28+
def show(): Unit =
29+
println(output)
30+
print(State.SHELL_PROMPT)
2831

2932
def setMessage(message: String): State = State(root, workingDir, message)
3033
}

filesystem/src/main/scala/com/codingmaniacs/scala/exercises/fs/commands/Command.scala

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,29 @@ trait Command {
2929

3030
object Command {
3131

32+
val MKDIR = "mkdir"
33+
34+
def emptyCommand: Command = new Command {
35+
override def apply(state: State): State = state
36+
}
37+
38+
def incompleteCommand(name: String): Command = new Command {
39+
override def apply(state: State): State =
40+
state.setMessage(s"$name is an incomplete command")
41+
}
42+
3243
def from(input: String): Command = {
33-
print(input)
34-
new UnknownCommand
44+
val tokens = input.split(" ")
45+
if (input.isEmpty || tokens.isEmpty) {
46+
emptyCommand
47+
} else if (MKDIR.equals(tokens(0))) {
48+
if (tokens.length < 2) {
49+
incompleteCommand(MKDIR)
50+
} else {
51+
new MkDir(tokens(1))
52+
}
53+
} else {
54+
new UnknownCommand
55+
}
3556
}
3657
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2019 Geektimus
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
5+
* this software and associated documentation files (the "Software"), to deal in
6+
* the Software without restriction, including without limitation the rights to
7+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8+
* the Software, and to permit persons to whom the Software is furnished to do so,
9+
* subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
package com.codingmaniacs.scala.exercises.fs.commands
23+
24+
import com.codingmaniacs.scala.exercises.fs.State
25+
import com.codingmaniacs.scala.exercises.fs.directories.{ DirEntry, Directory }
26+
27+
class MkDir(name: String) extends Command {
28+
29+
def updateStructure(currentDir: Directory, paths: List[String], newEntry: DirEntry): Directory =
30+
if (paths.isEmpty) {
31+
currentDir.addEntry(newEntry)
32+
} else {
33+
val oldEntry = currentDir.findEntry(paths.head).asDirectory
34+
currentDir.replaceEntry(oldEntry.name, updateStructure(oldEntry, paths.tail, newEntry))
35+
}
36+
37+
override def apply(state: State): State = {
38+
val wd = state.workingDir
39+
if (wd.hasEntry(name)) {
40+
state.setMessage(s"$name already exists")
41+
} else if (name.contains(Directory.SEPARATOR)) {
42+
state.setMessage(s"$name must not contain separators")
43+
} else if (checkIllegal(name)) {
44+
state.setMessage(s"$name: illegal entry name!")
45+
} else {
46+
performMkDir(state, name)
47+
}
48+
}
49+
50+
def checkIllegal(name: String): Boolean =
51+
name.contains(".")
52+
53+
def performMkDir(state: State, name: String): State = {
54+
val wd = state.workingDir
55+
56+
val filesInFolder = wd.getAllFoldersInPath
57+
58+
val newDir = Directory.empty(wd.path, name)
59+
60+
val newRoot = updateStructure(state.root, filesInFolder, newDir)
61+
62+
val newWD = newRoot.findDescendant(filesInFolder)
63+
64+
State(newRoot, newWD)
65+
66+
}
67+
}

filesystem/src/main/scala/com/codingmaniacs/scala/exercises/fs/directories/DirEntry.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@
2121

2222
package com.codingmaniacs.scala.exercises.fs.directories
2323

24-
abstract class DirEntry(val parentPath: String, val name: String)
24+
abstract class DirEntry(val parentPath: String, val name: String) {
25+
def path: String = s"$parentPath${Directory.SEPARATOR}$name"
26+
27+
def asDirectory: Directory
28+
}

filesystem/src/main/scala/com/codingmaniacs/scala/exercises/fs/directories/Directory.scala

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,43 @@
2121

2222
package com.codingmaniacs.scala.exercises.fs.directories
2323

24+
import scala.annotation.tailrec
25+
2426
class Directory(
2527
override val parentPath: String,
2628
override val name: String,
2729
val contents: List[DirEntry]
28-
) extends DirEntry(parentPath, name)
30+
) extends DirEntry(parentPath, name) {
31+
32+
def hasEntry(name: String): Boolean = findEntry(name) != null
33+
34+
def getAllFoldersInPath: List[String] =
35+
path.substring(1).split(Directory.SEPARATOR).toList.filter(p => !p.isEmpty)
36+
37+
def findDescendant(paths: List[String]): Directory =
38+
if (paths.isEmpty) this
39+
else findEntry(paths.head).asDirectory.findDescendant(paths.tail)
40+
41+
def addEntry(newEntry: DirEntry): Directory =
42+
new Directory(parentPath, name, contents :+ newEntry)
43+
44+
def findEntry(entryName: String): DirEntry = {
45+
46+
@tailrec
47+
def findEntryHelper(name: String, contentsList: List[DirEntry]): DirEntry =
48+
if (contentsList.isEmpty) {
49+
null
50+
} else if (contentsList.head.name.equals(name)) {
51+
contentsList.headOption.get
52+
} else findEntryHelper(name, contentsList.tail)
53+
findEntryHelper(entryName, contents)
54+
}
55+
56+
def replaceEntry(entryName: String, newEntry: Directory): Directory =
57+
new Directory(parentPath, name, contents.filter(p => !p.name.equals(entryName)) :+ newEntry)
58+
59+
override def asDirectory: Directory = this
60+
}
2961

3062
object Directory {
3163
val SEPARATOR = "/"

0 commit comments

Comments
 (0)