scala中基于包的自动修复目录结构

Posted

技术标签:

【中文标题】scala中基于包的自动修复目录结构【英文标题】:Autofix directory structure based on package in scala 【发布时间】:2020-08-24 20:35:09 【问题描述】:

我有一个文件src/main/scala/foo.scala,它需要在包bar 中。理想情况下,该文件应位于 src/main/scala/bar/foo.scala 内。

// src/main/scala/foo.scala


package bar

// ... 

如何在整个项目中自动修复此问题,以使文件夹结构与包结构匹配?

是否有任何 SBT 插件等可以帮助我解决此问题?

【问题讨论】:

【参考方案1】:

据我所知,没有这样的工具,尽管 AFAIR IntelliJ 可以警告包目录不匹配。

如果是自定义 scalafix (https://scalacenter.github.io/scalafix/) 规则,我认为最好 - scalafix/scalameta 将用于检查文件的实际包,将其转换为预期目录,如果它们不同,则移动文件。

我建议使用 scalafix/scalameta,因为有一些极端情况,例如:

你可以这样写你的包:

package a
package b
package c

几乎package a.b.c 一样,只是它会自动从 ab 导入所有内容

你可以在你的文件中包含package object,如果你有的话

package a.b

package object c

这个文件应该在a/b/c目录下

所以我更愿意检查文件是否不属于任何使用现有工具的文件。

如果您确定自己没有这种情况(我不会不检查),您可以:

用正则表达式匹配第一行 (^package (.*)) 将a.b.c 翻译成a/b/c (matched.split('.').map(_.trim).mkString(File.separator)) 将生成的位置与实际位置进行比较(我建议解析绝对文件位置) 必要时移动文件

如果可能有比这更复杂的情况,我可以通过查询 scalafix/scalameta 实用程序来替换第一步。

【讨论】:

我可以在多项目设置中将自定义规则作为项目实施吗? 如果您不想部署它但在其他模块上使用它,那么可能在projects/ 中实现它,因为 sbt 任务使用的 Scala 代码会更容易。【参考方案2】:

这是一个提供packageStructureToDirectoryStructure任务的sbt插件,它从源文件中读取包语句,创建相应的目录,然后将文件移动到它们

import sbt._
import sbt.Keys._
import better.files._

object PackagesToDirectories extends AutoPlugin 
  object autoImport 
    val packageStructureToDirectoryStructure = taskKey[Unit]("Make directory structure match package structure")
  

  import autoImport._

  override def trigger = allRequirements

  override lazy val projectSettings = Seq(
    packageStructureToDirectoryStructure := 
      val log = streams.value.log
      log.info(s"Refactoring directory structure to match package structure...")
      val sourceFiles = (Compile / sources).value
      val sourceBase = (Compile / scalaSource).value

      def packageStructure(lines: Traversable[String]): String = 
        val packageObjectRegex = """package object\s(.+)\s\""".r
        val packageNestingRegex = """package\s(.+)\s\""".r
        val packageRegex = """package\s(.+)""".r
        lines
          .collect 
            case packageObjectRegex(name) => name
            case packageNestingRegex(name) => name
            case packageRegex(name) => name
          
          .flatMap(_.split('.'))
          .mkString("/")
      

      sourceFiles.foreach  sourceFile =>
        val packagePath = packageStructure(sourceFile.toScala.lines)
        val destination = file"$sourceBase/$packagePath"
        destination.createDirectoryIfNotExists(createParents = true)
        val result = sourceFile.toScala.moveToDirectory(destination)
        log.info(s"$sourceFile moved to $result")
      
    
  )


警告:确保在运行之前备份项目。

【讨论】:

@tusharmath 如果您想尝试一下,我已经发布了sbt-packages-to-directories sbt 插件。确保在运行之前备份项目以防万一。

以上是关于scala中基于包的自动修复目录结构的主要内容,如果未能解决你的问题,请参考以下文章

使用scalatest,sbt目录结构时出错

maven,算不算是一个框架?

gulp配置实现修改jscsshtml自动刷新

带你认识spark安装包的目录结构

Composer 的结构详解

就是个控制结构,Scala能有什么新花样呢?