元编程
编程本来是一种致力于减少重复的工作,但不幸的是,我们却越来越听到「每天上班就是重复的 CURD」的这种抱怨。仔细想想过去一周你写过的代码,里边有多少是重复的呢?
当然,好的程序员总是有办法完成 DRY(Don't Repeat Yourself)的,「元编程」就是其中一种。
定义上,「元编程」是指通过代码来生成代码,从而减少重复的编码工作。具体而言,编译器、代码生成器都属于这个范畴。
其核心理念是,程序员的核心任务是描述「核心数据」和「核心逻辑」,剩下的事情,应该由工具链和机器来完成。在这种理念基础上,我们发展出了很多不错的框架。在其框架能管理的范围内,我们实现了大规模的代码重用。
以 API 为例,我们已经构建起来了以 OpenAPI 规范为中心的工具链。一旦你设计好 API,就可以自动化的生成服务部分的 Server 脚手架、以及调用部分的 SDK 。数十种语言,瞬间生成,用起来很感人。
MetaPage
MetaPage 不打算做那么大规模的事情,它着眼于日常的小代码甚至文字片段。一般我们遇到一个小时以上的重复劳动时,会想着做个工具把它自动化了。但如果我们遇到十多分钟的重复劳动,往往就忍了。因为搞这个工具本身可能就要花上十多二十分钟。
那么能不能提供一个通用的小工具来处理这些小需求呢?这就是 MetaPage 所做的尝试。它提供一个网页,这个网页分成三栏,分别是「元数据」、「模板」和「最终输出」。
「元数据」用 JSON 描述,模板用 ejs 引擎,点「生成」按钮生成「最终输出」。这里的输出甚至不一定是代码,文章也可以。
我们来看下界面,没有数据的时候,它会默认显示一个例子。
元数据是一个 JSON。
{
"author":"Easy",
"contacts":
[
{"HP":"https://ftqq.com"},
{"weibo":"https://weibo.com"},
{"twitter":"https://twitter.com/easychen"}
]
}
这个 JSON 中的数据,在模板中可以直接使用:
// MetaPage 由 开发,方糖气球?出品。
这时候,我们点击「生成」按钮,或者 cmd + s 就可以得到最终输出。
// MetaPage 由 Easy 开发,方糖气球?出品。
非常简单的模板替换逻辑。这里我们采用了 ejs 语法。这是一个简单但强大的引擎。
首先它用
和
%>
来嵌入语法块,不会产生输出。在其中,可以直接使用js
来做条件和循环。会直接输出变量内容。
会去掉标签之前的全部空白格,可以用来做代码的格式控制。
输出未转义的内容。
ejs
可以用 js
的原生语法来赋值、条件判断和循环,非常方便。
users.forEach(function(user){ %>
更多的内容可以参考ejs的文档,这里就不展开了。
逻辑重用
对于简单需求,上边的逻辑基本就够了。不过有时候,我们希望引入一些公用的逻辑,比如获取数组第一个元素的某个属性。
我们当然可以直接写成
contacts[0].nickname
但如果这个值在模板中被反复的使用,就又会造成大量的重复。于是我们引入了一个公用对象 —— this。
在这个区域我们可以给这个对象添加各种方法,而在模板中,就可以通过 this.method
来调用。
这样我们就可以实现部分逻辑的重用。
存储及其他
在 MetaPage 编写的代码会实时保存,但这些内容只保存在你浏览器的本地存储中,不会传到服务器上去。当你换台电脑,这些数据就消失了。所以我们提供到导出和导入功能。
对于相对复杂的使用场景,你可能同时需要多个 MetaPage 。你可以通过构造 URL 来区分不同的项目用的 MetaPage。比如:
meta.ftqq.com/php
meta.ftqq.com/project1
还记得大明湖畔的 MetaToy 吗?
记性好的同学可能还得我之前发布过一个叫做的 MetaToy
的工具,也是用来解决元编程的问题的。
MetaToy
把 MySQL 元信息获取和代码生成两个过程给绑定了,更为强大,想要一步到位。但在实际使用中却发现,这样反而导致一些来源不是 MySQL 的元数据进入不了这个体系。
所以这次我做了更轻量级的 MetaPage
。
它不关心元数据来源,只处理生成过程。
它只是一个网页,不用安装。
数据完全存放在客户端,没有泄密风险。
编辑器是 VSCode 背后的 Monaco,支持 cmd+d 多选、鼠标中键列选择和选中内容同步编辑。
符合我对一个小工具的各种喜好,因为本来就是做给我自己用的。有类似需求的同学可以用用,觉得好用的话,可以推荐给其他人。