博客图片的快速处理

经常写微信公众号或博客的朋友,总会面临图片处理的效率问题,找图片或截屏,调整大小,上传,复制粘贴图片地址,让人做得很厌烦。

说说怎么提高效率,找图片和截屏就不提了,而后面三件工作在mac下完全可以用workflow来协助我们完成。

调整图片的大小我是参考了MacTalk 的文章(原文我忘了),基本思路就是复制图像文件到统一目录中,调整图像大小,转换为JPG格式,并可以统一签上前缀名称。这样你就可以上传到微信公众平台,而无需担心图像文件过大影响用户浏览消耗过多的流量。

如果是写博客,我采用七牛云作为图床,使用上传脚本,上传后的结果可以直接 生成markdown格式日志 。同样写一个workflow,将图像文件移到七牛云的上传目录,执行shell脚本即可。(先在/tmp下生成一个qiniu.log文件)

最后上传文件的地址只需要查看/tmp/qiniu.log文件即可,已经修改直接采用了markdown格式。所以你最好采用一个支持markdown的编辑器和博客站点。

让ruby cowsay支持中文

cowsay 是一个很有趣的linux命令行工具,尤其是和fortune, lolcat联合在一起用,休闲好去处。可以加到.bash_profile中作为进入console时的调剂。比如:

在Mac中可以使用Ruby 对应的cowsay, fortune, lolcat 的gem包,gem install即可。不过在使用cowsay的时候,有个问题就是对中文的支持,一个中文汉字的长度仍然为1,但显示占的宽度是2,使得格式对不齐。类似于这样:

简单修改cowsay安装目录下lib/cowsay/character/base.rb代码,将第31行代码的


line_length = message_lines.max{ |a,b| a.length <=> b.length }.length
修改成:

line_length = message_lines.max{ |a,b| a.length <=> b.length }.encode('gbk').b.length

41行的代码


output_lines << “| %-#{line_length}s |” % line

修改成:


output_lines << “| %-#{line_length+line.length-line.encode(‘gbk’).b.length}s |” % line

即可以支持中文的输出,结果就成了:

不过注意的是中文的分词没支持,到时句子中需要自己打几个空格来实现换行。

Ruby on Rails的路由

路由就是用户输入URL地址,后端服务器能找到对应的处理程序。在Ruby on Rails中,我理解的路由(Route)主要和两件事情相关,一是将URL和http动作(Verb)映射到后端的控制器(Controller)对应的动作(Action);二是页面返回时,需要将Rails 视图(Views)中常用的帮助方法(Helper)转换成路径(Path)或URL。

路由的映射配置在config/routes.rb,我们可以在命令行输入bin/rake routes查看路由信息,例如:

Prefix Verb URI Pattern Controller#Action
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
about GET /about(.:format) pages#about

这张表格中的四列就包含了之前所说的两层含义,通过URI Pattern和Verb动作就可以对应到后端处理的Controller#Action,比如GET “/posts/new” 就对应于PostController中的new方法,而最前面的前缀new_post则采用的是命名路由方式,表示可以在视图.erb模板文件中使用new_post_path或new_post_url的帮助方法,来生成相应的URL地址,path是相对路径,url则是绝对路径。

在config/routes.rb中设置路由最简单直接的方法就是key/value形式,指定Http Verb和URI Pattern映射到对应的方法,也可以是静态页面,比如:


root "posts#index"
get '/about', to: 'pages#about'

root相当于get ‘/‘就是映射到app/controllers/posts_controller.rb中的PostsController类的index方法,而get ‘/about’则是对应到app/views/pages/about.html.erb页面模板文件。

这个写法虽然直接,但会对一个资源(Resource)的增删改查来说写起来就繁琐了,往往会采用RESTful的形式。一个Resource有一堆的动作,index, show, new, edit, create, update和destroy, 基本的写法就是:


resources :posts

这就生成了前面例子中有关Post的index, show, new, edit, create, update和destroy所有路由信息了。路由使用 HTTP 方法和 URL 匹配请求,把四个 URL结合不同的HTTP方法映射到七个不同的动作上。

REST有主要有两个核心精神,参见RESTful 應用程式

  • 使用Resource来当做识别的资源,也就是使用一个URL网址來代表一个Resource。
  • 同一个Resource则可以有不同的Representations格式变化。

再解释一下bin/rake routes输出信息中的格式,:id是传入参数,可以通过params[:id]获得;(.format)则说明可以让路由接受.json、.xml等有扩展名的网址,并且转成params[:format]参数传入Controller里,搭配respond_to而回传不同的格式。

基本的就是这样,具体路由为了简化书写,还有resource的嵌套,as别名,module/namespace/member/collection/scope多种组合形态,还可以用except/only做七个预设资源路由的限制,这个慢慢用到时再了解。

参考文档:

理解Ruby Symbol

过年了还在单位,在看看ROR。简单翻译一下Knowing The Difference Between [:symbol] and [symbol:] in Rails,自己也搞搞明白。


对于Rails新手来说,看到一个冒号一会在前一会在后经常容易迷惑。那么:symbol和symbol: 的区别是什么呢?

符号前的冒号

一个前面带有冒号的符号就是一个Symbol (有点像变量)我们需要使用=>对Symbol赋值。

举个例子,如果我们想复制”Ruby on Rails”赋值给:book符号,我们就写:


:book => "Ruby on Rails"

符号后的冒号

冒号后的符号实际上和之前的是同一回事。区别在于用法,如果:symbol 使用=>赋值,而symbol: 则不需要。

我们看第一个例子,重新用符号后的冒号写一些:


book: "Ruby on Rails"

它和之前的例子相同,都是把”Ruby on Rails”赋值给:book符号。

把一个符号赋值给另一个符号

有时我们会碰到下面的例子:


book: :available

这段代码就是i讲一个变量符号赋值给另一个符号。不过千万小心类似这样的写法Book::Name,这个完全不同,Book::Name表示Name是一个模块名,Book是一个类名。


上面的文章似乎简单化了,Symbol的含义不只此。:symbol是Symbol ,看文档的说明:

Symbol对象用于表示Ruby解释器中的名字和一些字符串,他们可以采用:name和:”string”的语法格式,也可以使用to_sym方法。对于指定的名称和字符串在程序运行期间会创建相同的symbol对象。也就是说无论Fred是一个上下文中的常量、另一个中的方法,或是第三个中的类,:Fred符号在所有三个上下文中都是相同的对象。

而symbol: 则是hash中key/value的一种替换语法格式。


> x = {foo: 1, bar: 2}
=> {:foo=>1, :bar=>2}
> x[:foo]
=> 1

IBM developerWorks这篇理解 Ruby Symbol,第 1 部分 说的更细些,尤其提到使用技巧,在ruby中使用Symbol处理名字可以降低Ruby内存消耗。

典型的使用是在hash中,symbol可以作为key值,效率比使用字符串要更好,因为Ruby对每一次字符串引用都会生成一个String对象。

还有可以做hash参数,普通调用函数的时候往往需要确保参数个数、顺序匹配,而使用hash参数就没有这个问题。Ruby on Rails大量地运用了这种方式,比如:


link_to 'Show', :action => 'show', :id => product

add_column :products, :price, :decimal, 
:precision => 8, :scale => 2, :default => 0

使用hash参数,可以如下定义,前半部分为固定参数,后面是可变参数,或者全部采用hash参数。

理解 Ruby Symbol ,第 2 部分: Symbol 内幕 提到使用:Symbol的方式会创建Symbol对象,保存在符号表中,这是一个全局数据结构,存放了所有Symbol的(数字ID、名字)对,Ruby不会做删除。

文中最后有一句话:Symbol 的特点决定了它的简洁和高效。 Ruby 把它的符号表敞开了给你,在 Symbol 可以更好地发挥作用时,不要吝啬使用 Symbol 。

hexo genereate CSS文件没有更新

刚写了一篇文章发布后,引用部分的内容(blockquote)字体很难看,字又大,还居中,实在无法忍受。

搜了一下,一开始以为是一直以为是hexojs/hexo-renderer-stylus#5 渲染的问题,尝试了不对;后来想是不是还是landscape-plus theme的问题,还特意去开了个issue问问。

其实还是自己的问题,style.css并不是修改后就会自动生成的,手工删除后public/css/style.css,重新hexo generate即可。之前是嫌博客文章太多,每次编译耗时久而懒得折腾。简单地建个目录,搞个测试看到hexo generate生成的文件清单就很容易排除了。

顺便搞搞清楚npm和nvm,npm是针对javascipt的安装包管理器(Node Package Manager),而nvm则用来安装和管理多个node.js的版本,其本身由npm安装。

attempt to write a readonly database

使用Adminer,一个PHP文件的数据库管理工具管理SQLite时,简单地删除一张表,报错:attempt to write a readonly database。

原因在于Adminer是在Apache中运行,在mac中使用的用户身份是_www用户,就没有写的权限了。所以要修改目录权限让apache可写


$ sudo chown -R _www:staff db
$ sudo chmod -R 775 db

权限如果改成755的话,个人用户就又没有写权限了。当然更好的方式是保留原有权限,只给_www用户新增所需权限:sudo chmod -R +a ‘_www allow read,write,delete,add_file,add_subdirectory,file_inherit,directory_inherit’ #dir#,就打起来复杂点。

为Mac OS设置国内外地址不同的访问路由

环境越来越恶化,这两天到处都是Gmail彻底被墙的消息。我等屁民只有迎难而上,把vpn,ssh给用好。

原先一直都是在用Chrome+SwitchySharp+ssh的方式,但这个方式不爽的是只支持http/https,很多时候git或brew更新时都会出问题,到时就只有祭起VPN大棋,但VPN的问题呢又在于走的是全局路由,包括国内的站点也都走了VPN,既慢又费流量。以前偶尔用用,一直懒得折腾,今天研究了一下,可以根据国内外地址设置不同的访问路由。这真是一个折腾的时代。

在mac下需要的几个工具:修改路由的chnroutes和开源的OpenVPN客户端Tunnelblick,原理就是:

利用来自APNIC的数据生成路由命令脚本,让VPN客户端在连接时自动执行。通过这些路由脚本,可以让用户在使用VPN作为默认网关时,不使用VPN访问中国国内IP,从而减轻VPN负担,并提高访问国内网站的速度。

如果你VPN服务使用PPTP,mac下很简单,参照chnroutes说明即可,可惜我的VPN提供商PPTP,L2TP,Cisco IPSecVPN几种连接方式相继被GFW干扰,目前只有采用OpenVPN的连接方式,参见Mac OS X通过Viscosity连接OpenVPN,不过Viscosity不是免费的,我就找个开源的Tunnelblick替代。

说明一下过程和注意事项:

  • 下载chnroutes
  • 在目录下执行python chnroutes.py -p mac ,生成 ip-up 与 ip-down 两个文件。
  • Tunnelblick中导入你的vpn服务提供商提供的配置文件。
  • 修改Tunnelblick的连接配置文件,增加

up {your directory}/ip-up
down {your directory}/ip-down
networksetup -setdnsservers "Ethernet" 8.8.8.8 8.8.4.4
networksetup -setdnsservers "Wi-Fi" 8.8.8.8 8.8.4.4
  • Tunnelblick中的设置里Set DNS/WINS为“Do not setnameserver”,由前面的配置文件来指定。
  • Tunnelblick连接VPN,连接成功后,可以访问ip138.comip.cn,前者为访问国内站点的ip地址,后者为访问国外站点的地址,两者应该不同。

– 12月30日更新:
发现连上VPN后,公司内网无法访问,参考如何在连接国外 VPN 翻墙的同时,访问公司内网服务 - Alsotang’s blog在ip-up/ip-down中增加公司的域名以及内网地址即可。对于Chrome来说可能需要清除缓存,否则总指向到该死的189so。

参考的文章有:

为七牛云图床的上传生成markdown格式日志

博客迁移到hexo后,使用七牛云作为图床,日常就用它的命令行工具qrsync上传图像,上传成功后会显示日志。有点不爽的是日志中只是显示上传到服务器上的相对路径的文件名称,在写markdown 格式时,还需要自己去补充类似“![]”,然后再补充完整url信息。

于是就在日志信息后加一个sed的脚本做替换,帮自动生成markdown格式,书写自然就方便了。

1
/Users/yangbin/bin/qrsync /Users/yangbin/bin/qiniu-conf.json 2>&1 |sed -e 's/\(=> xbin999:\)\(.*\)/=> ![](http:\/\/xbin999.qiniudb.com\/\2\)/'

另一种只显示结果文件格式的可以参见gist

自动布局是如何工作的

一直没搞明白iOS是如何设计界面的,看到有两篇不错的教程,Beginning Auto Layout Tutorial in iOS 7: Part 1 Part 2,针对Auto Layout做了很好的示例,把其中的一小节翻译了一下,算是加深印象。

As you’ve seen in the test drive above, the basic tool in Auto Layout is the constraint. A constraint describes a geometric relationship between two views. For example, you might have a constraint that says:
就像你在上面的例子中所看到的,自动布局(Auto Layout)的基本工具是约束。一个约束描述了两个视图间的几何关系。比如你可以这样描述一个约束:

“The right edge of label A is connected to the left edge of button B with 20 points of empty space between them.”
“标签A的右侧和按钮B的左侧相连,两者间距20个点。”

Auto Layout takes all of these constraints and does some mathematics to calculate the ideal positions and sizes of all your views. You no longer have to set the frames of your views yourself – Auto Layout does that for you, entirely based on the constraints you have set on those views.
自动布局获取所有的约束,然后计算得到所有视图的大小和理想位置。你不在需要自己设置视图的框架,自动布局基于你在视图上设置的约束为你实现了。

Before Auto Layout, you always had to hard-code the frames of your views, either by placing them at specific coordinates in Interface Builder, by passing a rectangle into initWithFrame:, or by setting the view’s frame, bounds or center properties.
在自动布局前,你始终不得不硬编码视图的框架,要么在Interface Builder中指定绝对坐标,要么传递一个矩形到initWithFrame中,要么设置视图的框架、边距和中心等属性。

For the app that you just made, you specifically set the frames to:
对于你刚设计的应用,你明确地设置框架:

You also set autosizing masks on each of these views:
你也会设置对这些视图自动改变大小的修饰:

That is no longer how you should think of your screen designs. With Auto Layout, all you need to do is this:
而使用自动布局,你需要做的是这样的:

The sizes and positions of the views are no longer important; only the constraints matter. Of course, when you drag a new button or label on to the canvas it will have a certain size and you will drop it at a certain position, but that is only a design aid that you use to tell Interface Builder where to put the constraints.
视图的大小和位置不再重要,只需要关注约束。当然当你把一个按钮或标签拖动到画布中,它会有一定的大小,你也会把它放置在一定的位置,但是要注意这只是一个设计上的辅助功能,用来帮助你告诉Interface Builder在哪里放置约束。

Designing like you mean it
The big advantage of using constraints is that you no longer have to fiddle with coordinates to get your views to appear in the proper places. Instead, you can describe to Auto Layout how the views are related to each other and Auto Layout will do all the hard work for you. This is called designing by intent.
使用约束的最大优点是你不再需要和坐标打交道来让视图出现在正确的位置上,取而代之的是使用自动布局描述视图间的关系,自动布局会为你完成硬编码工作。这被称为基于目的设计(designing by intent)。

When you design by intent, you’re expressing what you want to accomplish but not necessarily how it should be accomplished. Instead of saying: “the button’s top-left corner is at coordinates (20, 230)”, you now say:
当你基于目的设计,你表达的是你想要实现什么,而不是它应该如何被实现。你不会说“这个按钮的左上角坐标是(20,230)”,你会说:

“The button is centered vertically in its superview, and it is placed at a fixed distance from the left edge of the superview.”
“这个按钮在它的父视图中垂直居中,并且被放在父视图的左侧固定的位置。”

Using this description, Auto Layout can automatically calculate where your button should appear, no matter how big or small that superview is.
使用这样的描述,自动布局能自动计算你的按钮出现的位置,而无需考虑父视图的大小。

Other examples of designing with intent (and Auto Layout can handle all of these instructions):
其他基于目的设计的例子(自动布局能处理这些指令):

“These two text fields should always be the same size.”
“These two buttons should always move together.”
“These four labels should always be right-aligned.”
“这两个文本框大小相同。”
“这两个按钮同时移动。”
“这四个标签保持右对齐。”

This makes the design of your user interfaces much more descriptive. You simply define the constraints, and the system calculates the frames for you automatically.
这让你的用户界面设计更有描述性。你只需要简单定义约束,系统会为你自动计算框架。

You saw in the first section that even a layout with just a few views needs quite a bit of work to layout properly in both orientations. With Auto Layout you can skip all that effort. If you set up your constraints properly, then the layout should work without any changes in both portrait and landscape.
在第一节中你已经看到即使一个只有少数视图的布局也需要大量的工作以保证设备在不同方向下布局正确。使用自动布局,你可以忽略这些工作。如果你正确地设置好约束,那么布局会在肖像模式和风景模式都运行正常。

Another important benefit of using Auto Layout is internationalization. Text in German, for example, is infamous for being very long and getting it to fit into your labels can be a headache. Again, Auto Layout takes all this work out of your hands, because it can automatically resize your labels based on the content they need to display – and have everything else adapt with constraints.
另一点使用自动布局的好处是国际化。举个例子,德语中的文字是臭名昭著的长,很难和你的标签保持合适。而自动布局能很好地解决问题,因为它可以基于要显示的内容,根据要适应的约束,自动调整标签大小,。

Adding support for German, French, or any other language is now simply a matter of setting up your constraints, translating the text, and… that’s it!
增加对德语、法语或其他语言的支持,只需要设置约束,翻译文字…就可以了!

The best way to get the hang of Auto Layout is to play with it, so that’s exactly what you will do in the rest of this tutorial.
要熟悉自动布局最好的方法就是使用它,这也是你在接下来的教程中会学到的。

升级Yosemite

总是挡不住升级的诱惑,即使总会有这样或那样的问题。在看了MacTalk的文章“OSX Yosemite,焕然一新”后,觉得也差不多,就开始升级了。

备份,下载Yosemite,安装,一切顺利,周五晚上就成功升级到Yosemite了。想想太顺利了,开始折腾应用,然后悲剧就发生了。

升级后,提示有四个应用不兼容Yosemite:

  • Glims
  • SogouIM
  • Trim Enabler
  • Kindle

没当回事,前两个我都不记得是什么了,到时删掉得了。Trim Enabler是为了提升SSD硬盘的读写性能的,针对非苹果原装的SSD,我上次给机器在光驱位装了个SSD之后用了这个软件,于是鬼使神差就把原来老的Trim Enabler应用运行,再Enable一下,提示需要重启生效,然后就悲剧了。机器重启登录后一个大大的停止图标。

再之后查问题,发现这个问题搞起来还是有点复杂,折腾良久无果,最后我还是恢复到了原先的10.9,再重新做了一次升级。等搞明白或者有稳定的解决方案再说。

升级后处理的问题简单整理一下:

  • QQ拼音打字在从候选字列表中选自时经常出错,比如是打“一堆”,暂时用原生的输入法。
  • Homebrew更新后安装MacVim,提示“checking uint32_t is 32 bits… configure: error: WRONG! uint32_t not defined correctly.”错误,参见macvim install failed in 10.10 #33357,需要把XCode升级到6.1。升级后安装成功,再brew linkapps安装到/Applications 即可。

最迫切的就是Google Chrome和Trim Enabler了,暂时先不折腾了。

升级后的体验还得慢慢来,但升级后最想用的iOS协作却发现我的MacBook Pro太老了,都无法支持,呜呜。简单说一下:Yosemite和iOS协作最大的提升就是AirDrop在Mac和iOS设备间的共享、HandOff功能实现应用的无缝切换,不过不幸的是这两个功能都需要蓝牙4.0的支持,而我的MacBook Pro是2011年的,不支持蓝牙4.0。当然也有牛人替换了老设备的蓝牙,实现了黑、白苹果开Handoff教程 - ME294GM3亲测可用

想要知道自己的设备是否支持蓝牙4.0,可以在”About This Mac”点”System report”,查看“Bluetooth”即可。 如果知道自己的设备年限,大致可参考OS X Yosemite 的 Handoff 功能可能不支持所有 Mac,其中说到:

由于Continuity 的 Handoff 功能需要蓝牙4.0才能正常工作,这意味着并不是所有安装 OS X Yosemite 的 Mac 电脑都能用上 Handoff。2011年中期之后的 MacBook Air、2012年中期之后的 MacBook Pro、2012年末的 iMac、2011年中期的 Mac mini 和2013年末的 Mac Pro 才支持蓝牙4.0。