发布你的静态页面 - Github Pages

Github的主页服务 Github提供了Github Pages的服务来帮助你为自己的项目提供主页。目前,这种主页服务分为两种:用户主页和项目主页。其中用户主页已经称为广大开发者的标配,有很多的开发者已经将自己的博客迁移到了Github上,其中所用到的核心机制就是Github Pages。 这篇文章主要介绍如何使用项目主页。项目主页,顾名思义,就是你项目的主页,本来设计的初衷是为你的项目编写介绍文档,不过Github只提供对静态内容的托管。如果需要添加评论,可以使用disqus的服务,而和微博,flickr等集成都有现成的JavaScript片段,这里也不做详细讨论。 你现在正在看的我的博客正是托管在Github上,不过我对域名进行了自定义而已,如何做到这一点可以查看此处的文档。 我之前发布的一个我去过的地方就使用了项目主页的服务,该项目的地址在此,最终的页面在这里。 Web设计样板工程 我在Github上创建了一个设计样板工程,你可以使用这个工程快速的搭建一个完整的样板工程,其中包含了: 一个基本的HTML5的文档 SCSS环境 Guard环境,可以与LiveReload集成 具体的操作可以参看文档。 发布你的Web设计 Github提供的项目主页服务可以帮助你快速将设计发布,你所需要做的就是为项目创建一个名叫gh-pages的分支,然后将HTML/CSS/JS放在这个分支上即可。 假设你在github上的用户名为wumai(一时间想不到好名字,看看窗外,就叫雾霾吧),那么根据惯例,你的Github地址为https://github.com/wumai。这时候,假设你的项目(repo)的名称为design-1,则你的项目主页地址为https://wumai.github.io/design-1。 知道了你的项目主页地址,你就需要为这个页面添加内容了: $ git clone git@github.com:abruzzi/design-boilerplate.git design-1 克隆了design-boilerplate之后, $ cd design-1 $ git remote -v 你可以看到当前的项目是和git@github.com:abruzzi/design-boilerplate.git关联的, origin git@github.com:abruzzi/design-boilerplate.git (fetch) origin git@github.com:abruzzi/design-boilerplate.git (push) 你需要先和这个样板工程解除绑定: $ git remote remove origin 然后你需要在Github上创建一个新的Repo,假设命名为design-1,这时候,将这个新创建的Repo作为你本地的remote: $ git remote add -u origin git@github.com:wumai/design-1.git 与远程连接之后,我们可以开始实际的设计了,不过在这之前,需要先创建一个gh-pages分支: $ git checkout -b gh-pages 这条命令会创建gh-pages分支,并切换到该分支,这样后续的修改都会在该分支进行,这也正是我们想要的。开发调试之后,就可以将这个分支push到Github: $ git push -u origin gh-pages 好了,现在打开地址http://wumai.github.io/design-1,应该就可以看到你自己的设计了。

November 21, 2014 1 min

测试驱动开发实例

示例的需求描述 今天我们需要完成的需求是这样的: 对于一个给定的字符串,如果其中元音字母数目在整个字符串中的比例超过了30%,则将该元音字母替换成字符串mommy,额外的,在替换时,如果有连续的元音出现,则仅替换一次。 如果用实例化需求(Specification by Example)的方式来描述的话,需求可以转换成这样几条实例: hmm经过处理之后,应该保持原状 she经过处理之后,应该被替换为shmommy hear经过处理之后,应该被替换为hmommyr 当然,也可以加入一些边界值的检测,比如包含数字,大小写混杂的场景来验证,不过我们暂时可以将这些场景抛开,而仅仅关注与TDD本身。 为什么选择这个奇怪的例子 我记得在学校的时候,最害怕看到的就是书上举的各种离生活很远的例子,比如国外的书籍经常举汽车的例子,有引擎,有面板,但是作为一个只是能看到街上跑的车的穷学生,实际无法理解其中的关联关系。 其实,另外一种令人不那么舒服的例子是那种纯粹为了示例而编写的例子,现实世界中可能永远都不可能见到这样的代码,比如我们今天用到的例子。 当然,这种纯粹的例子也有其存在的价值:在脱离开复杂的细节之后,尽量的让读者专注于某个方面,从而达到对某方面练习的目的。因为跟现实完全相关的例子往往会变得复杂,很容易让读者转而去考虑复杂性本身,而忽略了对实践/练习的思考。 TDD步骤 通常的描述中,TDD有三个步骤: 先编写一个测试,由于此时没有任何实现,因此测试会失败 编写实现,以最快,最简单的方式,此时测试会通过 查看实现/测试,有没有改进的余地,如果有的话就用重构的方式来优化,并在重构之后保证测试通过 它的好处显而易见: 时时关注于实现功能,这样不会跑偏 每个功能都有测试覆盖,一旦改错,就会有测试失败 重构时更有信心,不用怕破坏掉已有的功能 测试即文档,而且是不会过期的文档,因为一旦实现变化,相关测试就会失败 使用TDD,一个重要的实践是测试先行。其实在编写任何测试之前,更重要的一个步骤是任务分解(Tasking)。只有当任务分解到恰当的粒度,整个过程才可能变得比较顺畅。 回到我们的例子,我们在知道整个需求的前提下,如何进行任务分解呢?作为实现优先的程序员,很可能会考虑诸如空字符串,元音比例是否到达30%等功能。这当然没有孰是孰非的问题,不过当需求本身就很复杂的情况下,这种直接面向实现的方式可能会导致越走越偏,考虑的越来越复杂,而耗费了几个小时的设计之后发现没有任何的实际进度。 如果是采用TDD的方式,下面的方式是一种可能的任务分解: 输入一个非元音字符,并预期返回字符本身 输入一个元音,并预期返回mommy 输入一个元音超过30%的字符串,并预期元音被替换 输入一个元音超过30%,并且存在连续元音的字符串,并预期只被替换一次 当然,这个任务分解可能并不是最好的,但是是一个比较清晰的分解。 实践 第一个任务 在本文中,我们将使用JavaScript来完成该功能的编写,测试框架采用了Jasmine,这里有一个模板项目,使用它你可以快速的启动,并跟着本教程一起实践。 根据任务分解,我们编写的第一个测试是: describe("mommify", function() { it("should return h when given h", function() { var expected = "h"; var result = mommify("h"); expect(result).toEqual(expected); }); }); 这个测试中有三行代码,这也是一般测试的标准写法,简称3A: 组织数据(Arrange) 执行需要被测的函数(Action) 验证结果(Assertion) 运行这个测试,此时由于还没有实现代码,因此Jasmine会报告失败。接下来我们用最快速的方法来编写实现,就目前来看,最简单的方式就是:...

November 9, 2014 3 min

ImageMagick - 命令行里的PhotoShop

黑白+单色照片 有很多摄影师通过后期制作出了非常独特的黑白+单色照片,并由此来强调被拍摄主题,绿叶中的红花,紫色花朵的黄色花蕊等;的另一方面,这种照片可以强调背景的灰色,比如雾霾中的交通灯。 比如原图是这样的: 经过处理之后,最终的效果是这样的: 网络上已经有很多的教程来做到这一点,不过都需要使用photoshop来完成颜色的抽取,反色,灰化等。当然,作为程序员,特别是命令行控,自然会想到的是使用图片编辑神器ImageMagick来处理。 基本原理 我们都知道,彩色图片都是由3个通道(红,绿,蓝三个)叠加在一起的(如果图片带有透明通道的话,会有4个通道,我们这里略过)形成的。每个通道都是一张灰度图,并且会根据图片实际的色彩,在不同程度上有明暗差异。 比如上图的花朵,如果我们将jpg本身的RGB分离开,就会得到3张不同的灰度图: 红色通道灰度图: 绿色通道灰度图: 蓝色通道灰度图: 由于原图绿色和紫红色为主要色彩,所以在红色通道中,花朵比较偏向白色,蓝色通道中花朵也会偏向白色,因为紫红色包含红色和蓝色的亮度都比较高,而在绿色通道中,叶子的颜色则更偏向白色一些。 图片的加减 有了灰度图,我们就可以通过不同通道的加减来加强某些色彩,比如蓝色通道和红色通道相减之后,绿色就会被过滤掉,因为绿色在红色和蓝色通道中都表现为灰色: 这时候,我们已经有了花瓣的轮廓,但是还是有些模糊,我们还需要将其二值化。这样做出来的图片被称为mask,这个mask和最终的图片叠加之后,才会将我们关注的部位凸现出来。 实现 ImageMagick提供的命令行工具convert非常强大,我们这里只是用其中很简单的几个: 1. 图片通道的分离 2. 图片相加减 3. 叠加多个图片为一个 要分离一张RGB的图片,只需要指定: $ convert flower.jpg -separate flower_rgb_%d.jpg 这条命令会把图片flower.jpg分离成三张图片,命令中的%d占位符会自动被展开为1,2,3这样的数字,这样这条命令会生成3章图片:flower_rgb_0.jpg,flower_rgb_1.jpg,flower_rgb_2.jpg。 图片的相减也很方便,使用命令: $ convert flower_rgb_2.jpg flower_rgb_0.jpg -compose minus \ -composite flower_minus.jpg 来完成。得到差值文件之后(已经具备了基本轮廓,如果不理想,可以换一个通道试试),就可以进一步二值化了。 命令 $ convert flower_minus.jpg -level 10%,30% flower_mask.jpg 用来生成mask文件,其中10%表示亮度低于10%的点会被认为是黑色,而30%则表示亮度高于30%的点会被认为是白色,这样的出来的图片就是只有黑白两种颜色了。 最后,我们需要将不同的图片合并在一起,形成最终的结果: $ convert flower_rgb_2.jpg flower.jpg flower_mask.jpg -composite flower_final.jpg 注意这里的次序,先是蓝色通道,然后是原图,最后是mask。这样composite的结果就是我们最开始看到的了: 再来看另外一张用同样方式生成的图片:

November 8, 2014 1 min

Node Webkit 101

Web前端的现状 目前的Web前端的现状较之5-6年前,简直不能同日而语:从所使用的技术、工具、框架到开发一个产品所需要付出的工作量,从前端开发从业人员的数量到Web应用的数量,从企业对于Web前端的重要程度的认识到Web实际上为企业带来的回报,一切都有了翻天覆地的变化。 借助HTML5+CSS3的普及,加上一些开箱即用的CSS框架(如bootstrap,foundation等)支持,人们已经可以非常容易的从零开始搭建一个Web应用的前端。一个在UI方面非常业余的程序员也可以很快的做出一个像模像样的用户界面。而另一方面,基于操作系统原生API,要想设计并实现一个桌面应用,需要的付出则远远超过超过同水平的Web界面。 webkit浏览器内核 Webkit作为最受欢迎的浏览器内核,自然有非常多的port。比如GTK+对它的port – WebkitGTK,以及构建在WebkitGTK之上的Python的bind。使用WebkitGTK的Python版本,开发人员可以用HTML+CSS来开发应用,然后写一点Python脚本,最后将其运行在桌面上。 这里有个早期的例子来教你如何写一个所见即所得的编辑器。桌面应用开发中,对于用户界面的复杂性一直是一个难题,而这种方式可以减轻很多的用户界面开发的复杂性,将界面开发交给另外更加灵活,更加容易编写和调试方式:HTML+CSS。 这种模式下基本的开发流程是编写一个HTML页面(作为程序入口),然后在这个页面上引入额外的CSS(界面风格)和JavaScript(动作),然后将这些资源交给工业级浏览器内核Webkit来渲染 – 这个过程和在浏览器中访问该文件并无二致,但是有两个额外的好处: 页面运行在一个“桌面应用程序”中 没有地址栏,状态栏,菜单栏等,看起来更像是一个桌面应用 用户界面开发的复杂性被“外包”给一个更简单的环境 这就是传说中的混合(hybrid)开发模式,比如现在移动开发中的cordova就是采用这种模式,使得本来被视为天堑的原生的用户界面开发变为坦途。 node-webkit node-webkit是一个基于chromium和node.js的应用程序开发工具。它不但支持你使用传统的HTML5+CSS3+JS方式来开发你的应用程序,还支持无缝的与Node.js集成,也就是说,所有的Node支持的与操作系统交互的功能,如网络连接,文件系统,操作系统资源访问等,以及Node之上的第三方库都可以在node-webkit中进行使用。 更好的是,node-webkit是一个跨平台的工具,你可以使用它构建出运行在Mac OS,Linux以及Windows下的应用程序。应用程序通过Node.js来进行与系统相关的访问,而用HTML5+CSS3进行用户界面部分的设计。 node-webkit未必是未来桌面应用的唯一方式,但是却是一个非常好的选择,特别对于已经熟知Web前端开发技术栈的众多开发者来说,无需学习一门新的语言,一切都被很大程度的简化了。 第一个node-webkit应用程序 开发node-webkit应用程序非常简单。在这里下载系统对应的版本。并确保对应的二进制文件(nwnw.exe)在系统的PATH之中。 创建一个新的目录,然后在该目录中创建一个package.json文件和一个index.html文件: $ mkdir -p hello-node-webkit $ cd hello-node-webkit $ touch package.json index.html package.json文件的内容如下: { "name": "hello-node-webkit", "version": "0.1.0", "main": "index.html" } index.html文件的内容如下: <html> <head> <title>Hello node-webkit</title> </head> <body> <div> <h1>Hello node-webkit</h1> </div> </body> </html> 然后将这两个文件打在一个zip格式压缩包中: $ zip -r hello-node-webkit.zip * 然后将这个文件重命名为hello-node-webkit.nw,最后使用node-webkit来启动这个应用程序。 $ ~/Tools/node-webkit.app/Contents/MacOS/node-webkit hello-node-webkit.nw 添加外部JS/CSS 接下来我们为这个页面添加一些外部的引用:CSS/JavaScript文件。首先创建两个目录style和script,然后分别创建文件如下:...

September 21, 2014 1 min

中午吃啥 - 一个简单的脚本

千古谜题 — 中午吃啥? 如果要列出一些日常最频繁的会问/被问的问题的一个列表,吃啥?绝对会排在前三位,对于程序员来说,一样频繁的还有诸如这是谁写的?,***这尼玛啥意思啊?***之类。 吃啥作为一个每天都会面对的问题,我们自然而言会想很多办法,比如随大流,其他人去哪儿我们跟着就行,但是这种方法最大的问题是:大部分人其实都没有很好的想法,大家都很迷茫。作为程序员,一个非常直观的想法就是找出一个列表,然后随机/伪随机的从这个列表中拿出一条来作为推荐。 基本思路 一个基本的思路是这样的,或者说,要开发的软件应该满足这几个基本的需求 维护一个饭店/饭菜的列表 随机的从这个列表中取出一项 每天定时的触发,比如11:30准时提醒 这个工具最终要以弹出窗口等方式来提醒 饭店/饭菜的列表比较容易,比如一个静态的JSON文件: [ { "name": "关中客大碗面" }, { "name": "王华峰肉夹馍" }, { "name": "傻得帽冒菜" }, { "name": "蒸饺" }, { "name": "樊家肉夹馍" }, { "name": "马奴哈羊肉泡馍" }, { "name": "子午路张记肉夹馍" }, { "name": "东滩水盆" } ] 然后我们需要一个小程序来读取这段JSON,并已随机/伪随机的方式返回一个推荐: # encoding: UTF-8 require 'json' def first JSON.parse(File.open("food.json").read).shuffle[0]["name"] end puts "今天去吃#{first}吧?" 测试一下,将上边这个ruby程序运行几次,可以得到一下结果: $ ruby lunch.rb 今天去吃东滩水盆吧? $ ruby lunch.rb 今天去吃子午路张记肉夹馍吧? $ ruby lunch....

September 18, 2014 1 min