我在努力学习科特林。我来自Java的一些背景。作为一个学习练习,我编写了这个简单的程序来总结作者电子邮件在git存储库列表中出现的字符串。
我很好奇我是否在用一种习惯的Kotlin方式来对待事物。扩展函数是很棒的,但我怀疑这是我不应该过度使用的东西。
我计划让它成为一个命令行应用程序,并可能使用递归从源目录获取git存储库,而不显式地提供它们。不过,在我走得太远之前,我想看看如何改进我所拥有的一切。
任何反馈都是非常感谢的!
import java.io.File
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import kotlin.concurrent.thread
data class CommitSummary(
var author: String,
var regexString: String,
var count: Int)
data class Commit(
var commit: String = "",
var author: String = "",
var date: OffsetDateTime? = null,
var message: String = "")
fun main(args: Array<String>) {
val cmd = "git log --all --branches=* --remotes=*"
val matchStr = "d'{0,1}oh" //case-insensitive
val gitDir = "C:\\dev\\git\\"
arrayListOf("repo-1", "repo-2")
.forEach { repo ->
thread {
val log = cmd.run(File(gitDir + repo), createTempFile())
val commits = log.parseGitLog()
val summaries = commits.summarizeGitMessages(matchStr)
summaries.forEach { author, summary ->
println(String.format("repo: %s, author: %s, %s count: %s", repo, author, summary.regexString, summary.count))
}
}
}
}
fun File.parseGitLog(): ArrayList<Commit> {
return this.readLines().fold(arrayListOf()) { accumulated, current ->
val startingWord = current.split("\\s".toRegex())[0]
when (startingWord) {
"commit" -> accumulated.add(Commit(current.split("\\s".toRegex())[1]))
"Author:" -> accumulated.last().author = current.substring(current.indexOf("<") + 1, current.indexOf(">"))
"Date:" -> accumulated.last().date = current.split("Date:")[1].trim().parseGitDateString()
else -> accumulated.last().message += current.trim()
}
return@fold accumulated
}
}
fun ArrayList<Commit>.summarizeGitMessages(regexString: String): MutableMap<String, CommitSummary> {
val pattern = Pattern.compile(regexString, Pattern.MULTILINE or Pattern.CASE_INSENSITIVE)
return this.fold(mutableMapOf()) { acc, commit ->
val summary: CommitSummary = acc.getOrPut(commit.author) { CommitSummary(commit.author, regexString, 0) }
val match = pattern.matcher(commit.message)
while (match.find()) {
summary.count = summary.count.plus(1)
}
return@fold acc
}
}
// string extensions
fun String.run(workingDir: File, targetFile: File = File("C:\\dev\\tmpFile")): File {
if (targetFile.exists()) {
targetFile.delete()
}
ProcessBuilder(*split(" ").toTypedArray())
.directory(workingDir)
.redirectOutput(ProcessBuilder.Redirect.appendTo(targetFile))
.redirectError(ProcessBuilder.Redirect.INHERIT)
.start()
.waitFor(60, TimeUnit.MINUTES)
return targetFile
}
fun String.parseGitDateString(format: DateTimeFormatter = DateTimeFormatter.ofPattern("EEE MMM d HH:mm:ss yyyy Z")): OffsetDateTime {
return OffsetDateTime.parse(this, format)
}发布于 2018-07-17 06:56:12
我从来没有使用过Kotlin,所以我不能给出一个全面的回顾或评论,特别是具体的成语。
我对这一行有点困扰,因为null对象看起来非常像Kotlin范式通常试图避免的Java习惯。
var date: OffsetDateTime? = null,在我看来,Commit是一种在构造时应该知道其值的东西,所以请考虑使用数据类构造函数。
我对这句话也有点紧张:
val gitDir = "C:\\dev\\git\\"
File(gitDir + repo)我知道您将参数化您想要使用的存储库列表。当你这么做的时候,它是值得思考的事情,如跨平台的可用性。我不能给出具体的建议,但通常最好是使用某种文件系统库,而不是将这样的字符串拼接在一起。
// string extensions
fun String.run(workingDir: File, targetFile: File = File("C:\\dev\\tmpFile")): File 类扩展是一种非常酷的功能,但它也让人觉得使用这种能力是一种危险的做法。根据经验,您将不会有一个对该类的任何实例运行都没有意义和合法的类方法,同样,在添加对类的大多数版本没有意义的扩展时也要小心。因为matchStr.run(...)没有任何意义,所以我怀疑会像这样扩展String。我想说的是,要么为可运行的字符串拥有一个特定的类,要么只有一个函数将该字符串作为参数运行。
https://codereview.stackexchange.com/questions/199638
复制相似问题