Git commit message书写总结

为什么要有规范

作为团队协作工具,Git的提交message非常必要,如果写的比较规范,可以方便查看代码库是如何演进的。如果写的五花八门,那么对将来有可能发生的版本回溯等会造成很大的干扰。

另外,如果按照固有的规范的话,也有工具能帮助直接生成 changelog。

Read more...

在Rails中使用ElasticSearch进行检索

概要说明

这篇博客介绍自己对ElasticSearch(下面简称ES)的入门使用过程。
ES底层的搜索实现是基于lucene的。

安装ElasticSearch

Mac系统的话,推荐使用HomeBrew来安装各种软件。

brew install elasticsearch
---------------以下为控制台输出结果---------------------------
==> Downloading https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.4.4.tar.gz
######################################################################## 100.0%
==> 
To have launchd start elasticsearch at login:
    ln -sfv /usr/local/opt/elasticsearch/*.plist ~/Library/LaunchAgents
Then to load elasticsearch now:
    launchctl load ~/Library/LaunchAgents/homebrew.mxcl.elasticsearch.plist
Or, if you don't want/need launchctl, you can just run:
    elasticsearch --config=/usr/local/opt/elasticsearch/config/elasticsearch.yml
==> Summary
🍺  /usr/local/Cellar/elasticsearch/1.4.4: 33 files,  29M, built in 46 secondsCaveats
Data:    /usr/local/var/elasticsearch/elasticsearch_moyan/
Logs:    /usr/local/var/log/elasticsearch/elasticsearch_moyan.log
Plugins: /usr/local/var/lib/elasticsearch/plugins/
Config:  /usr/local/etc/elasticsearch/

如果是Linux发行版的话,可以通过apt-get,yum进行安装。 参考官网的下载页面的安装说明

以Ubuntu为例:

# 下载安装public signing key
wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
# 添加Repo到sources.list
echo "deb http://packages.elastic.co/elasticsearch/1.5/debian stable main" | sudo tee -a /etc/apt/sources.list
# 更新repo并且安装ES
sudo apt-get update && sudo apt-get install elasticsearch
# 如果要设置为开机自启动,执行下面命令
sudo update-rc.d elasticsearch defaults 95 10

安装完成的话,访问http://localhost:9200,如果出现一下结果就是OK了。

{
  "status" : 200,
  "name" : "Earth Lord",
  "cluster_name" : "elasticsearch_moyan",
  "version" : {
    "number" : "1.4.4",
    "build_hash" : "c88f77ffc81301dfa9dfd81ca2232f09588bd512",
    "build_timestamp" : "2015-02-19T13:05:36Z",
    "build_snapshot" : false,
    "lucene_version" : "4.10.3"
  },
  "tagline" : "You Know, for Search"
}
Read more...

2014年总结以及2015计划

2014年已经过去一个月了,很早就想总结一下,可惜一直拖延到现在^~^

2014年总结

工作上
  • 4月份辞去了日本的工作,归国奋斗
  • 7月份~ 车辆年检服务网
    从7月份开始一直从零开始做车辆年检服务网的项目,终于在2014/12/18日正式上线, 很欣慰自己坚持了下来,虽然今后还有更多的事情需要维护。
  • 12月份~ IOS学习
    回到了两年前的公司,开始着手学习IOS,虽然开始的比较晚,但是希望自己能够掌握一种移动开发的技术。
  • 个人博客
    迁移到了Jekyll,但是整个2014年总共没有写几篇博客,希望能够2015年多多产出。
生活上
  • 我最心疼可爱的宝贝女儿出生了!!!(从此我也有了自己的小棉袄^-^)
  • 6月份买了车,希望能多带家人出去玩
  • 坚持了8个月的全职丈夫,照顾老婆
    当一切都过去以后,当听到产房传来宝宝第一声啼哭的时候,你会发现,这一切都是那么的值得。 男人一定要好好照顾自己的老婆,因为你无法想像她为这个家付出了多少,又牺牲了多少。

2015年计划

工作上
  • 能够坚持一年至少12篇技术博客(一月一篇的频率)
  • 有一个自己的IOS App产品上线
  • 读至少5本书(3本技术,1本育儿,1本人文)
  • 英语单词记忆,英语听力训练(目标:基本能够听懂英文技术视频)
生活上
  • 带上老婆出去旅游
  • 坚持羽毛球运动,跑步
关注的技术方向

Rails应用中的middleware们

middleware在rack规范中是一个很重要的概念。在rails中,一个app,其实就是各种middleware一层一层嵌套起来工作的。

在rails app中,middleware可以分为三类:

  • Server的middleware
  • 在config.ru中use的middleware
  • 在application.config中use的middleware

他们的嵌套顺序也是按照上面的顺序,即server middleware 包含 config.ru middleware 包含 application middleware

前提说明

本文中涉及到的rails源码针对的版本是:4.1.6

Server中的middleware

在Rack::Server中有以下代码,这里的build_app其实就是为了给后面得到的app包装上server的middleware的。

# rack/lib/rack/server.rb
def wrapped_app
  @wrapped_app ||= build_app app
end

比如Rails::Server中重写父类Rack::Server的middleware方法:

#
def middleware
  middlewares = []
  middlewares << [Rails::Rack::Debugger] if options[:debugger]
  middlewares << [::Rack::ContentLength]

  # FIXME: add Rack::Lock in the case people are using webrick.
  # This is to remain backwards compatible for those who are
  # running webrick in production. We should consider removing this
  # in development.
  if server.name == 'Rack::Handler::WEBrick'
    middlewares << [::Rack::Lock]
  end

  Hash.new(middlewares)
end

config.ru中的middleware

默认Rails生成的新应用的config.ru文件内容如下:

# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment',  __FILE__)
run Rails.application

其实在run Rails.application之前,是可以use一些middleware的。比如:

# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment',  __FILE__)
use Rack::ShowExceptions
use Rack::ETag
use OTHER Middleware
......
run Rails.application

那么这里use的middleware,就被包装在了Rails app的middleware之前。

Application中的middleware

在rails应用中可以通过config的如下方法来编辑application的middleware:
参考: http://guides.rubyonrails.org/configuring.html#configuring-middleware

  • config.middleware.use Magical::Unicorns
  • config.middleware.insert_before ActionDispatch::Head, Magical::Unicorns
  • config.middleware.insert_after ActionDispatch::Head, Magical::Unicorns
  • config.middleware.swap ActionController::Failsafe, Lifo::Failsafe
  • config.middleware.delete “Rack::MethodOverride”

rake middleware命令

在rails应用目录中执行rake middleware命令,会打印app的middlewares。但是特别注意的是,只会打印上面提到的application中的middleware,而server中,以及config.ru中use的middleware是不会被打印出来的。

从以下middleware.rake的源码可以看出这一点:

# rails/railties/lib/rails/tasks/middleware.rake
desc 'Prints out your Rack middleware stack'
task middleware: :environment do
  Rails.configuration.middleware.each do |middleware|
    puts "use #{middleware.inspect}"
  end
  puts "run #{Rails.application.class.name}.routes"
end

Rails Application启动流程

在之前的博文 rails server是如何启动的 中分析了rails server这个命令最终是如何启动的,本篇接着分析一个Rails Application到底是如何被构建成功的。

事前说明

如果要分析Rails的启动流程的话,需要对以下知识有一些了解:

以下是一些小tips,可以事前了解:

  • Applicaiton, Engine, Railtie的继承关系:Rails::Application < Rails::Engine < Rails::Railtie
  • 相对应的Configuration类的继承关系:Rails::Application::Configuration < Rails::Engine::Configuration < Rails::Railtie::Configuration
  • Rails::Railtie::Configuration 中的变量都是类变量
  • Rails::Engine::Configuration 和 Rails::Application::Configuration 中的变量都是实例变量
Read more...

rails server是如何启动的

当我们启动一个rails应用时,比如我们运行rails server命令,到底后台是如何运行的?

首先确认rails命令的路径,在项目目录下执行 which rails 命令,结果如下:

/Users/moyan/.rvm/gems/ruby-2.1.1/bin/rails

该rails命令文件主要内容:

...
gem 'railties', version
load Gem.bin_path('railties', 'rails', version)

Gem.bin_path的执行结果:

/Users/moyan/.rvm/gems/ruby-2.1.1/gems/railties-4.1.6/bin/rails

文件关键内容:

...
require "rails/cli"

rails/cli.rb关键内容:

require 'rails/app_rails_loader'
# If we are inside a Rails application this method performs an exec and thus
# the rest of this script is not run.
Rails::AppRailsLoader.exec_app_rails

# 这里后面还有一些内容,但是如上面的注释所说,如果在一个rails app的目录中,这些后面的脚本就不会被执行了。

这里的exec_app_rails就相当于执行下列命令:
这里的bin/rails就是rails app目录下的可执行文件

exec ruby bin/rails server

RailsDemoApp/bin/rails内容:

#!/usr/bin/env ruby
begin
  load File.expand_path("../spring", __FILE__)
rescue LoadError
end
APP_PATH = File.expand_path('../../config/application',  __FILE__)
require_relative '../config/boot'
require 'rails/commands'

这里主要干了以下事情:

  • 定义了APP_PATH
  • require config/boot文件,这个文件主要是进行bundle/setup,也就是检查Gemfile的内容
  • require ‘rails/commands’

rails/commands.rb中关键代码:

Rails::CommandsTasks.new(ARGV).run_command!(command)

run_command!方法代码:

def run_command!(command)
  command = parse_command(command)
  if COMMAND_WHITELIST.include?(command)
    send(command)
  else
    write_error_message(command)
  end
end

其中调用了send(command),因为我们执行的rails server,就相当于这里又调用了server方法:

def server
  set_application_directory!
  require_command!("server")

  Rails::Server.new.tap do |server|
    # We need to require application after the server sets environment,
    # otherwise the --environment option given to the server won't propagate.
    require APP_PATH
    Dir.chdir(Rails.application.root)
    server.start
  end
end

这里有以下关键的地方:

  • 这里require了APP_PATH,这个PATH就是该应用目录下的config/application.rb
  • 调用了server.start方法,就相当于正式启动了server

结语

这里只是简单的分析了server的启动流程,其实针对一个Rails application,它的启动过程中还做了更多的事情。 有时间的话,再继续写一些application的启动流程相关的内容。

追加信息

[2014-10-18] – 接下来的分析参照: Rails Application启动流程