SPM开发的一个命令行工具——ModelMaker

在开发项目的过程中,必不可少地要创建Model,大部分时候都是对照着服务器返回的json来创建。一个property,一个property去写实在枯燥乏味,尤其是当字段量很大的时候,敲的都要怀疑人生了…。ModelMaker是用Swift Package Manager开发的一个命令行工具,只要指定好Json的文件路径,以及生成Model后要放置的目录,即可自动创建Model了,目前支持创建ObjC和Swift的Model。本文将介绍一下该脚本的实现思路,记录一下用SPM制作命令行工具的步骤。如果你感兴趣,可以在此基础上继续修改生成的Model的样子。

实现思路

Json这样的结构实际上是一棵多叉树,我们可以用递归把这棵树构造起来。每个节点是Model的一个Property,如果是叶子节点,该Property就是基本类型,如果节点下面还有节点,则该Property又是一个Model类型。通过遍历这棵树,拿到其下所有子节点大于0的节点,我们就知道了这个Json要生成多少个Model。画了一张对应图:

在构造这棵树的过程中,就可以得到每个Property的具体类型了,我这里定义的Node如下:

1
2
3
4
5
6
7
8
class Node: NSObject {
var name: String = "" //属性的名称
var type: String = "" //属性的类型
var childs: [Node] = []
var level: Int = 0

func createChildNodes(withDict data: [String: Any]) {}
}

node.type我这里可能是NSArray<ProductsModel *> *或者CustomerModel *,所以从node.type里拿到要创建的Model名称会绕一点。

接下就是生成model文件到指定的磁盘位置了,我这里定义了一个全局的字典来保存一些文件模板,这样我们在拼接要生成的文件中的内容时,替换其中的变量就行了。

源码地址:https://github.com/shinancao/ModelMaker

使用

1
2
3
> git clone https://github.com/shinancao/ModelMaker.git
> cd ModelMaker
> ./install.sh

执行后,该脚本将被放在/usr/local/bin中,以后使用时:

1
> modelmaker --json /Users/Shinancao/Desktop/test.json -d /Users/Shinancao/Desktop/modelFiles -t o

把上面的参数换成你自己的哦~

脚本中的参数说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
> modelmaker -h
-h, --help:
Print this help message.
--json:
Path of json file.
-d, --dir:
Directory to the output model files.
-t, --model-type:
model type operation - o for Objective-C, s for Swift. Default is Swift.
-p, --prefix:
Set prefix for generated models. Default is nothing.
-s, --suffix:
Set suffix for generated models. Default is "Model".

SPM制作CommandLine Script

  • 创建项目文件夹(我这里创建的是TestSPM,所以下面出现该名称的地方,都将会是你自己的文件夹名),在该目录下执行:swift package init --type executable,执行完会生成以下文件:
1
2
3
4
5
6
7
8
> swift package init --type executable
Creating executable package: TestSPM
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/TestSPM/main.swift
Creating Tests/

Package.swiftmain.swift是需要我们重点关注的两个文件,Package.swift中的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import PackageDescription

let package = Package(
name: "TestSPM",
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "TestSPM",
dependencies: []),
]
)

在这里可以配置项目依赖的第三方库,还有项目中的target。

main.swift是可执行文件的入口,若在这里执行print("Hello, world!"),在运行脚本后就会在终端中打印出来。

  • 指定依赖的第三方库,比如这里我指定一个对命令行输入参数进行解析的库CommandLine,则在Package.swift中修改如下:
1
2
3
4
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/jatoben/CommandLine", from: "3.0.0-pre1"),
],

(swift的版本不同,这里的写法也会稍有不同,开发时注意一下就好)

  • 指定项目中的target,在Sources下的文件夹经编译后,如果其中有main.swift就会被当做可行文件,没有则会作为Framework。我们再Sources再添加一个文件夹TestSPMKit,同时在Package.swift中修改如下:
1
2
3
4
5
6
7
8
9
10
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "TestSPMKit",
dependencies: []),
.target(
name: "TestSPM",
dependencies: ["TestSPMKit"])
]
  • 编译、运行脚本:
1
2
3
> swift build
> .build/debug/TestSPM
Hello, world!
  • 生成xcodeproj:swift package generate-xcodeproj
1
2
> swift package generate-xcodeproj
generated: ./TestSPM.xcodeproj
  • 一个终端命令,通常需要一些参数,我们可以使用CommandLineKit这个第三库来处理,具体的使用可见CommandLineKit。如果要等待用户进行输入,可以使用readLine()函数。

  • 调用终端命令,可以通过Swift提供的Process来处理:

1
2
3
4
5
6
public static func openFile(_ filePath: String) {
let process = Process()
process.launchPath = "/usr/bin/env"
process.arguments = ["open", filePath]
process.launch()
}

这里注意一下,arguments的第一个对象是命名名称,后面是需要的参数。

–End–

转载请注明出处:

作者:意林

原文链接:https://shinancao.cn/2018/04/29/Script-ModelMaker/