术语 “样板” 能够追溯到印刷媒体的早期阶段。小型地区性报纸的填充量只有几英寸,但一般缺少编写人员来实现这一目标,所以他们中的许多人转向大型印刷品集团,以得到稳定的内容流,能够逐字添加到他们日报的后页。这些故事一般在预设板上提供,这相似于用于制造锅炉的轧制钢板,所以得名。html
经过转喻的过程,内容自己被称为“样板”,而且该概念被用于包含合同中的标准化公式文本,形式字母,以及与本周关于NSHipster的代码的文章最相关。git
来小编交流群 有技术的来闲聊 没技术的来学习 691040931
并不是全部代码都是迷人的。实际上,许多使一切工做的低级基础设施都是一个模板。github
这是斯威夫特标准库,其中包括像符号整数类型的家庭(真Int8
,Int16
,Int32
,Int64
),其实现仅在相应类型的大小而变化。数据库
复制粘贴代码能够做为一次性解决方案(假设您第一次设法正确),但它不可持续。每当您想要对这些派生实现进行更改时,您均可能会引入轻微的不一致性,致使实现随着时间的推移而发生分歧 - 与负责地球生命变化的随机突变不一样。编程
语言有各类技术来处理这个问题,从C ++模板和Lisp宏到eval
C预处理器语句。json
Swift没有宏系统,而且由于标准库自己是用Swift编写的,因此它没法利用C ++元编程功能。相反,Swift维护者使用一个名为gyb.py的Python脚本,使用一 小组 模板标签生成源代码。swift
<abbr title="生成您的Boilerplate" style="box-sizing: border-box;">GYB</abbr> 是“Generate Your Boilerplate”的首字母缩写,参考 另外一个Python工具, <abbr title="Generate Your Projects" style="box-sizing: border-box;">GYP</abbr> (“生成你的项目”) <abbr title="生成您的项目" style="box-sizing: border-box;"></abbr> <ins style="box-sizing: border-box; background-color: rgba(255, 128, 0, 0.2); text-decoration: none;">Haskell包 <abbr title="报废你的锅炉" style="box-sizing: border-box;">SYB</abbr> (“Scrap Your Boilerplate”) <abbr title="报废你的锅炉" style="box-sizing: border-box;"></abbr></ins>。xcode
GYB如何运做
GYB是一个轻量级模板系统,容许您使用Python代码进行变量替换和流控制:app
- 序列评估一段Python代码
%{ <var class="placeholder" style="box-sizing: border-box; background: rgb(248, 248, 242); display: inline-block; padding: 0px 0.25em; border: 1px solid rgb(40, 42, 54); border-radius: 5px; font-style: normal;">code</var> }
- 序列管理控制流程
% <var class="placeholder" style="box-sizing: border-box; background: rgb(248, 248, 242); display: inline-block; padding: 0px 0.25em; border: 1px solid rgb(40, 42, 54); border-radius: 5px; font-style: normal;">code</var>: ... % end
- 该序列替换表达式的结果
${ <var class="placeholder" style="box-sizing: border-box; background: rgb(248, 248, 242); display: inline-block; padding: 0px 0.25em; border: 1px solid rgb(40, 42, 54); border-radius: 5px; font-style: normal;">code</var> }
全部其余文本都保持不变。dom
能够在Codable.swift.gyb中找到GYB的一个很好的例子。在文件的顶部,基Codable
类型被分配给实例变量:
%{ codable_types = ['Bool', 'String', 'Double', 'Float', 'Int', 'Int8', 'Int16', 'Int32', 'Int64', 'UInt', 'UInt8', 'UInt16', 'UInt32', 'UInt64'] }%
稍后,在实现中,迭代这些类型以生成协议要求的方法声明:Single<wbr style="box-sizing: border-box;">Value<wbr style="box-sizing: border-box;">Encoding<wbr style="box-sizing: border-box;">Container
% for type in codable_types: mutating func encode(_ value: ${type}) throws % end
评估GYB模板会产生如下声明:
mutating func encode(_ value: Bool) throws mutating func encode(_ value: String) throws mutating func encode(_ value: Double) throws mutating func encode(_ value: Float) throws mutating func encode(_ value: Int) throws mutating func encode(_ value: Int8) throws mutating func encode(_ value: Int16) throws mutating func encode(_ value: Int32) throws mutating func encode(_ value: Int64) throws mutating func encode(_ value: UInt) throws mutating func encode(_ value: UInt8) throws mutating func encode(_ value: UInt16) throws mutating func encode(_ value: UInt32) throws mutating func encode(_ value: UInt64) throws
此图案用于在整个文件中,以产生相似的方法相似地公式化的声明 ,和。总的来讲,GYB将样板代码的数量减小了几千个LOC:encode(_:for<wbr style="box-sizing: border-box;">Key:)``decode(_:for<wbr style="box-sizing: border-box;">Key:)``decode<wbr style="box-sizing: border-box;">If<wbr style="box-sizing: border-box;">Present(_:for<wbr style="box-sizing: border-box;">Key:)
$ wc -l Codable.swift.gyb 2183 Codable.swift.gyb $ wc -l Codable.swift 5790 Codable.swift
有效的GYB模板可能没法生成有效的Swift代码。若是派生文件中发生编译错误,则可能难以肯定根本缘由。
安装GYB
GYB不是标准Xcode工具链的一部分,所以您没法找到它xcrun
。相反,您可使用Homebrew下载它:
$ brew install nshipster/formulae/gyb
或者,您能够下载源代码并使用chmod
命令生成gyb
可执行文件(macOS上的默认安装应该可以运行gyb
):
$ wget https://github.com/apple/swift/raw/master/utils/gyb $ wget https://github.com/apple/swift/raw/master/utils/gyb.py $ chmod +x gyb
若是你走这条路线,必定要将它们移动到能够从Xcode项目访问的地方,但要将它们与源文件分开(例如,Vendor
项目根目录下的目录)。
在Xcode中使用GYB
在Xcode中,单击导航器中的蓝色项目文件图标,选择项目中的活动目标,而后导航到“Build Phases”面板。在顶部,您将看到一个+
符号,您能够单击该符号以添加新的构建阶段。选择“添加新运行脚本阶段”,而后在源编辑器中输入如下内容:
find . -name '*.gyb' | \ while read file; do \ ./path/to/gyb --line-directive '' -o "${file%.gyb}" "$file"; \ done
确保在编译源以前订购GYB构建阶段。
如今,当您构建项目时,任何具备.swift.gyb
文件扩展名的文件都由GYB评估,GYB会输出一个.swift
与项目中其他代码一块儿编译的文件。
什么时候使用GYB
与任何工具同样,知道什么时候使用它与了解如何同样重要。如下是一些能够打开工具箱并进入GYB的示例。
生成公式代码
您是否为一组中的元素或序列中的项复制粘贴相同的代码?具备可变替换的for-in循环多是解决方案。
如Codable
前面的from 示例所示,您能够在GYB模板文件的顶部声明一个集合,而后遍历该集合以获取类型,属性或方法声明:
%{ abilities = ['strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma'] }% class Character { var name: String % for ability in abilities: var ${ability}: Int % end }
使用GYB进行评估会生成如下Swift代码:
class Character { var name: String var strength: Int var dexterity: Int var constitution: Int var intelligence: Int var wisdom: Int var charisma: Int }
代码中的大量重复是一种气味,可能代表有更好的方法来完成任务。协议扩展和泛型等内置语言功能能够消除大量的代码重复,所以请注意使用它们而不是使用GYB强制执行。
生成从数据派生的代码
您是在编写基于数据源的代码吗?尝试将GYB归入您的开发中!
GYB文件能够导入Python包同样json
,xml
和csv
,这样你就能够分析几乎任何类型的可能会遇到的文件:
%{ import csv } % with open('path/to/file.csv') as file: % for row in csv.DictReader(file):
若是您但愿看到这一点,请查看 Currencies.swift.gyb ,它为ISO 4217规范定义的每种货币生成Swift枚举 。
经过将数据下载到能够检入源代码管理的文件而不是在GYB文件中进行HTTP请求或数据库查询,可使编译保持快速和肯定性。
代码生成使您的代码与相关标准保持同步变得微不足道。只需更新数据文件并从新运行GYB便可。
斯威夫特已经作了不少与另外的编译器合成的最近削减样板 Encodable
和Decodable
4.0, Equatable
和Hashable
4.1,和 4.2。咱们但愿这种势头可以在将来的语言更新中获得体现。Case<wbr style="box-sizing: border-box;">Iterable
与此同时,对于其余一切,GYB是代码生成的有用工具。
社区中另外一个很棒的工具是 Sourcery,它容许你在Swift(经过Stencil)而不是Python中编写模板。
“不要重复本身”多是编程的一种美德,但有时你必须说几回才能使事情发挥做用。当你这样作时,你会感谢有一个像GYB这样的工具来为你说。