2009-01-07

ROR ÕÐÆ¸ Î人

ÎÒÃÇÕýÔÚÕÐÆ¸³ÌÐòÔ±£¬µØµãÔÚÎ人¡£Çëµã»÷ÒÔÏÂÁ´½Ó¡£ ÎÒÃÇͬʱҲÌṩÅàѵµÄְλ¸øÓÐÓÃÆäËûÓïÑÔÍøÂ翪·¢¾­ÑéµÄ³ÌÐòÔ±£¬Èç¹ûÄú¸ÐÐËȤÇë·¢¼òÀú¸øÎÒÃÇ¡£ ¹ùÀò

by GuoLi at 2009-01-07 05:44 AM

2009-01-06

Git服务器安装

Git on Ubuntu Server

安装Git-Core:

1
2
3
4
sudo apt-get update # 可选步骤
sudo apt-get dist-upgrade # 可选步骤
 
sudo apt-get install git-core

因为要用到 Gitosis ,所有,需要安装python setuptools

1
sudo apt-get install python-setuptools

安装 Gitosis

1
2
3
4
5
6
mkdir ~/src
cd ~/src
git clone git://eagain.net/gitosis
 
cd gitosis
sudo python setup.py install

增加名为Git的用户

1
sudo adduser --system --shell /bin/sh  --gecos 'git version control' --group --disabled-password --home /home/git git

上传公钥到USER用户的根目录下(如果没有,用 ssh-keygen -t rsa 生成)

1
2
3
scp .ssh/id_rsa.pub USER@YOUR_SERVER:
sudo -H -u git gitosis-init < /home/USER/id_rsa.pub
sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update

到这一步,基本上都安装好了,到本地进行测试:

1
git clone git@YOUR_SERVER:gitosis-admin.git

成功后,在本地将有一个gitosis-admin目录,里面有gitosis.conf,keydir。

为Rails项目配置git
打开gitosis.conf,增加一块内容,members为某个用户的公钥~/.ssh/id_rsa.pub中的名字(在该文件的最后在)

1
2
3
[group myrailsapp]
members = vince@urbanpuddle
writable = myrailsapp

然后,提交修改

1
2
git commit -a -m "created a new repository"
git push

将本地代码提交到git中

1
2
cd myrailsapp
git init

创建 .gitignore 文件,用于忽略某些不需要进行代码管理的内容

1
2
3
4
5
.DS_Store
log/*.log
tmp/**/*
config/database.yml
db/*.sqlite3

提交代码

1
2
3
4
git remote add origin git@YOUR_SERVER:myrailsapp.git
git add .
git commit -a -m "initial import"
git push origin master:refs/heads/master

接下来,可以增加成员的公钥到系统中了

1
2
3
4
cd gitosis-admin
cp ~/alice.pub keydir/
cp ~/bob.pub keydir/
git add keydir/alice.pub keydir/bob.pub

修改gitosis.conf

1
2
3
4
[group myteam]
- members = jdoe
+ members = jdoe alice bob
  writable = free_monkey

提交修改

1
2
git commit -a -m "Granted Alice and Bob commit rights to FreeMonkey"
git push

其它成员就可以获取代码了

1
git clone git@YOUR_SERVER:myrailsapp.git

请参考 Hosting Git repositories, The Easy (and Secure) Way

原文请参考 : http://enjoyrails.com/wikis/Git安装

Related posts:

  1. Git详解(一) 我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的: commit  fa6f27b7de063c2f301b0e7148b5bd5e813faa98 tree       5e7a19c158b89fbc52a078771a833ee839727404 parent   76f31606376180ca88efa12be341dbb14fb06fdf 咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:...
  2. Git一分钟教程 流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器 取代码及修改全局设置 设置用户名与邮箱 git...
  3. Git详解(二) Git中级用法: Ignoring files 项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:...

Related posts brought to you by Yet Another Related Posts Plugin.

by devon at 2009-01-06 04:50 AM

2009-01-05

Rails中检测SWF尺寸

安装:

1
2
cd vendor/plugins
svn export http://ruby-imagespec.googlecode.com/svn/trunk/ image_spec

使用:

1
2
3
4
image = ImageSpec::Dimensions.new('/path/to/your/file')
 
image.width
image.height

例子:

1
2
3
4
5
6
>> image = ImageSpec::Dimensions.new("#{RAILS_ROOT}/a.swf")
=> #<ImageSpec::Dimensions:0x2570d94 @height=670, @width=868>
>> image.width
=> 868
>> image.height
=> 670

Related posts:

  1. Rails应用添加配置的方法 方法一: 使用 app_config 插件 script/plugin install http://svn.jarmark.org/rails/app_config Rails::Initializer.run do |config|...

Related posts brought to you by Yet Another Related Posts Plugin.

by devon at 2009-01-05 07:36 AM

2009-01-04

¼±ÎÊÌ⣡£¡£¡

ÎÒÏë°²×°rails±È½ÏµÍµÄ°æ±¾£¬¶ø²»ÏëÓÃgemÔÚÏß°²×°×îа汾£¬Ôõô°ì£¿ Áí£¬ÎÒÏÂÔØÁËInstantRails,µ«mysqlÈ´Æô¶¯²»ÁË£¬Ìáʾ´íÎó£ºUnexpected end of Mysql,Ôõ÷á°ì£¿ лл¸÷λ

by jw1970 at 2009-01-04 02:30 PM

页面调用flash文件之路径问题(IE)

今天发现一个很诡异的问题 :
页面调用一个swf文件(该文件在kecheng.example.net/courses 这个目录下),该swf文件内部as调用其他的swf文件(文件在其他的域名目录下,跟页面调用的那个swf文件不在同目录下),在ie下 第一次可以调用 刷新后无法调用。
(页面地址:http://kecheng.example.net/courses/flash_s/4)

调用代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
function show_flash(swf_url) {
	var so = new SWFObject(swf_url,'aa','710','532','8','#ffffff'); 
	so.addParam('allowscriptaccess','always'); 
	so.addParam('wmode','transparent'); 
	var base_url = swf_url.replace(/\/[^/]*$/, '/')
	so.addParam('base', base_url); 
	so.addParam('allowfullscreen','true'); 
	so.addVariable('width','710'); 
	so.addVariable('height','532'); 
	so.write('flash_viewer'); 
}
 
show_flash('');

查询adobe网站查到 有base这个属性 (官网地址)
base - . or [base directory] or [URL]. Specifies the base directory or URL used to resolve all relative path statements in the Flash Player movie. This attribute is helpful when your Flash Player movies are kept in a different directory from your other files.

这个属性可以指定as调用swf文件的相对路径的路径基准.
例如: a.swf文件处于 www.aa.com/kecheng 下,b1.swf、b2.swf 2个文件处于www.bb.com/kecheng 下其中b1.swf文件as代码调用b2.swf文件 。在www.aa.com/kecheng下的a.swf文件调用b1.swf文件 ,如果不加base这个属性的话 b1.swf是调用不到b2.swf这个文件的(因为b2.swf文件的路径已经变成www.aa.com/kecheng 了) 加上属性 就可以指定其相对路径的基准是www.bb.com/kecheng 这样就可以调用到b2.swf文件了。
但是在IE6.7下刷新页面后b2.swf文件就调用不到了 使用iewatch 发现页面刷新后b2.swf的路径已经变成www.aa.com/kecheng了,base属性在ie下失效了,但是删除ie临时文件又可以了,然后刷新又不可以了。
通过iewatch 观察后,发现可能是ie缓存的问题 ,就在调用地址上加了上一个随机数字

1
show_flash('?'+ Math.random());

问题解决。

此问题非常诡异,虽然解决了,但是更深层次的原因还是没弄明白,望哪位高手解释下!

No related posts.

by wengjian at 2009-01-04 09:16 AM

Git一分钟教程

流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器

取代码及修改全局设置

设置用户名与邮箱

1
2
git config --global user.name "My Name"
git config --global user.email "my@email.com"

从已有的git库中提取代码

1
git clone git@server:app.git myrepo

每次更改代码的操作

更新本地代码到最新版本(需要merge才能合到本地代码中)

1
git fetch

合并更新后的代码到本地

1
git merge

更新代码方式的另一种方法(git pull是git fetch和git merge命令的一个组合)

1
git pull

修改代码后,查看已修改的内容

1
git diff --cached

将新增加文件加入到git中

1
git add file1 file2 file3

从git中删除文件

1
2
git rm file1
git rm -r dir1

提交修改

1
git commit -m 'this is memo'

如果想省掉提交之前的 git add 命令,可以直接用

1
git commit -a -m 'this is memo'

commit和commit -a的区别, commit -a相当于:

  • 第一步:自动地add所有改动的代码,使得所有的开发代码都列于index file中
  • 第二步:自动地删除那些在index file中但不在工作树中的文件
  • 第三步:执行commit命令来提交

提交所有修改到远程服务器,这样,其它团队成员才能更新到这些修改

1
git push

其它常用命令

显示commit日志

1
git log

不仅显示commit日志,而且同时显示每次commit的代码改变。

1
git log -p

回滚代码:

1
git revert HEAD

你也可以revert更早的commit,例如:

1
git revert HEAD^

将branchname分支合并到当前分支中。(如果合并发生冲突,需要自己解决冲突)

1
git merge branchname

解决冲突

当merge命令自身无法解决冲突的时候,它会将工作树置于一种特殊的状态,并且给用户提供冲突信息,以期用户可以自己解决这些问题。当然在这个时候,未发生冲突的代码已经被git merge登记在了index file里了。如果你这个时候使用git diff,显示出来的只是发生冲突的代码信息。

在你解决了冲突之前,发生冲突的文件会一直在index file中被标记出来。这个时候,如果你使用git commit提交的话,git会提示:filename.txt needs merge

在发生冲突的时候,如果你使用git status命令,那么会显示出发生冲突的具体信息。

在你解决了冲突之后,你可以使用如下步骤来提交:

第一步(如果需要增加文件):

1
git add file1

第二步:

1
git commit

Related posts:

  1. Git详解(一) 我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的: commit  fa6f27b7de063c2f301b0e7148b5bd5e813faa98 tree       5e7a19c158b89fbc52a078771a833ee839727404 parent   76f31606376180ca88efa12be341dbb14fb06fdf 咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:...
  2. Git详解(二) Git中级用法: Ignoring files 项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:...
  3. Git服务器安装 Git on Ubuntu Server 安装Git-Core: sudo apt-get update # 可选步骤...

Related posts brought to you by Yet Another Related Posts Plugin.

by devon at 2009-01-04 09:12 AM

2009-01-03

ÉϺ£´ú¿ªÉÌÒµ·¢Æ±´ú¿ª¹ã¸æÒµ×¨Ó÷¢Æ±13313197276

by ÊéÇàd at 2009-01-03 11:59 AM

ɽ¶«Ê¡´ú¿ª·þÎñÒµÒµÓéÀÖÒµÎÄ»¯ÌåÓýҵͨÓ÷¢Æ±13313197276ÁÖС½ã

ÎÒ˾¿ÉÒÔΪÆäËûµ¥Î»£¨¹«Ë¾£©¹©Ó¦£ºÓà¶î·¢/ƱÏêÇéÈçÏ£ºÒòϸڷöÖ²µÄ˰ÊÕÕþ²ß£¬¼ÓÉϽøÏî½Ï¶àÍê³É²»ÁËÿÔ¶¨Ë°¶î¶È,±¾¹«Ë¾ÏÖÓÐÓà¶î·¢.Ʊ£¬±¾¹«Ë¾Óë¶à¼Ò¹«Ë¾£¨ÆóÒµ£©ÓÐÒµÎñÍùÀ´£¬¿É¸ù¾Ý¿Í»§ÔÚ¡°»¥»Ý»¥Àû¡± µÄºÏ×÷»ù´¡ÉÏΪ¿Í»§(´ú¡£¿ª·¢Æ±)£¡ ¹óÆóÒµ(¹«Ë¾)ÈôÓÐÒÔÏÂÇé¿öÇëÀ´µçÁª

by ÊéÇàd at 2009-01-03 11:59 AM

´úÀí³ö¿ÚºËÏúµ¥´úÀí³ö¿ÚÊÕ»ãºËÏúµ¥13313197276ÁÖС½ã

ÉîÛÚ´úÀí±¨¹Ø³ö¿ÚºËÏúµ¥²úµØÖ¤13313197276ÁÖС½ã ,ÉîÛÚÊкãͨóÒ×ÓÐÏÞ¹«Ë¾ ºÏ×÷ÏîÄ¿£º ÌṩºËÏúµ¥µ½È«¹ú¸÷¸Û¿Ú±¨¹Ø ÎÒÃÇÉîÛÚ½ø³ö¿Ú¹«Ë¾¿ÉÒÔÔÚÍâ¹Ü¾ÖÁì³öµÄºËÏúµ¥Ô¶Ô¶³¬³öÁ˳ö¿ÚµÄÓÃÁ¿£¬ÉîÛÚ½øÍâ»ãÓв¹ÌùÏà¶Ô¶øÑԱȽÏÓŻݡ£ÖÁÓÚ¶àÓàºËÏúµ¥£¬ÎÒÃÇÒѾ­È«ÃæÏòÆäËü¸Û¿Ú£¨Ìì½ò¡¢±±¾

by ÊéÇàd at 2009-01-03 11:58 AM

ɽ¶«Ê¡´ú¿ª·þÎñÒµÒµÓéÀÖÒµÎÄ»¯ÌåÓýҵͨÓ÷¢Æ±13313197276ÁÖС½ã

ÎÒ˾¿ÉÒÔΪÆäËûµ¥Î»£¨¹«Ë¾£©¹©Ó¦£ºÓà¶î·¢/ƱÏêÇéÈçÏ£ºÒòϸڷöÖ²µÄ˰ÊÕÕþ²ß£¬¼ÓÉϽøÏî½Ï¶àÍê³É²»ÁËÿÔ¶¨Ë°¶î¶È,±¾¹«Ë¾ÏÖÓÐÓà¶î·¢.Ʊ£¬±¾¹«Ë¾Óë¶à¼Ò¹«Ë¾£¨ÆóÒµ£©ÓÐÒµÎñÍùÀ´£¬¿É¸ù¾Ý¿Í»§ÔÚ¡°»¥»Ý»¥Àû¡± µÄºÏ×÷»ù´¡ÉÏΪ¿Í»§(´ú¡£¿ª·¢Æ±)£¡ ¹óÆóÒµ(¹«Ë¾)ÈôÓÐÒÔÏÂÇé¿öÇëÀ´µçÁª

by ÊéÇàd at 2009-01-03 11:57 AM

API的查询

在开发的时候经常要用得着这东西

相对于google baidu这种解决问题的搜索方法

查API可能更有效一些

rails api
http://api.rubyonrails.org/
http://www.railsbrain.com

ruby api
http://www.ruby-doc.org/core/

2009-01-03 04:54 AM

打造Blog-10:has_many更好一些

has_and_belongs_to_many在其中一表删除数据后
关系表中对应项不会自动删除
这样会遗留很多不可用数据

但是用has_many加:dependent => :destroy
就能解决这一些问题

class Blog < ActiveRecord::Base
  has_many :comments
  has_many :blogs_tagss,:dependent => :destroy # BlogsTags
  has_many :tags,:through => :blogs_tagss
end

class Tag < ActiveRecord::Base
  has_many :blogs_tagss,:dependent => :destroy # BlogsTags
  has_many :blogs,:through => :blogs_tagss
end

class BlogsTags < ActiveRecord::Base
  belongs_to :blog
  belongs_to :tag
end

2009-01-03 04:51 AM

打造Blog-9:多对多关系创建Tags标签2

然后创建控制器tags

class TagsController < ApplicationController
  def show
    @blogs = Tag.find(params[:id]).blogs

    respond_to do |format|
      format.html{render :template =>  "blogs/index",:object => @blogs }
    end
  end
end

然后修改blogs/index.html.erb里的render项 加上"blogs"
把will_paginate项删除 或再对其进行处理下

运行能显示对应Tag的所有blogs项即可

之后请大家自己在对应地方加上Tags的连接

2009-01-03 04:40 AM

打造Blog-8:多对多关系创建Tags标签1

首先生成两个model
Tag name:string
BlogsTags blog_id:integer tag_id:integer

然后在模型
blog.rb加入
has_and_belongs_to_many :tags

tag.rb加入
has_and_belongs_to_many :blogs

然后进入控制台测试

2009-01-03 04:34 AM

央视网首页布局

上 CCAV 网站查看今天 NBA 直播时间,央视网飘出一个友情提示:

首页布局有变化

非常“友好”,就是根本让人闹不明白“恢复初始”和“暂不恢复”是什么意思。符合 CCAV 一贯作风。

by ashchan at 2009-01-03 02:17 AM

2008-12-30

Git详解(一)

我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的:
commit  fa6f27b7de063c2f301b0e7148b5bd5e813faa98
tree       5e7a19c158b89fbc52a078771a833ee839727404
parent   76f31606376180ca88efa12be341dbb14fb06fdf

咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:
Git通过简单比较object name就可以快速的确定这两个对象是否相等。
因为object name在每个repository里都是以相同的方法来计算的,所以在不同的两个repository的同一个内容都会被存储在相同的object name下。
Git可以在读取对象的时候检查错误,检查该对象的名称是否还是它的内容的SHA1 hash。

The Objects
每个对象都由三个东东组成:type,size,content。size当然是content的size了,而content却是依赖于这个对象是个什么type了。而type又有四类:“blob”,”tree”, “commit”, “tag”。
blob - 通常被用来存储文件数据,一般是个文件。
tree  - 基本上像个目录结构,比如x / yyy
commit - 它指向一个单独的tree,它标记了一个时刻的项目的面貌,就像给这个project照了个艳照一样。它包含那个时刻的元信息,例如时间戳,改变本次提交的作者,前一个提交的指向标等等。
tag - 专门用来指定某些特殊行为的commits。

和svn的不同是?
传统的SCM系统,比如svn,CVS, perforce, Mercuial等,它们存储的都是本次和下次提交的differents。 而Git不同,这是关键的一点。Git就像一个狗仔队的记者一样,把你项目的所有文件以及每次提交时候的tree 结构都拍了个照, 把这个照片存储下来而已。这点对于理解Git来说,相当重要!

Blob Object
刚才说了,这是指文件数据。
git show 命令可以帮助你看type,具体用法可以参照(http://www.kernel.org/pub/software/scm/git/docs/git-show.html)例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
git show
commit cf70117f3cc497fba42890171d29ae404061d25f
Author: Alex &lt;blackanger.z@gmail.com&gt;
Date:   Sun Dec 7 05:55:46 2008 +0800
 
 
modify .gitignore
 
diff --git a/.gitignore b/.gitignore
index deb5b7c..77573ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-log/
+/log
.DS_Store

因为blob是由它的数据决定的实体,如果在目录tree里有两个内容相同的blob,那么它们就会共享同一个blob对象。该对象是完全独立于它在目录tree里的位置的,并且你重命名文件的话也不会改变与这个文件相关联的那个blob对象。

Tree Object
这是个简单的对象,它就是指向一堆blob对象和其他的tree目录。它一般表现的是目录和子目录的内容。你用git ls-tree命令可以把tree 对象看的更详细。例如:
git ls-tree cf701
100644 blob 77573ab40c4f010c0e050f1bbff2ad3ab78f1428       .gitignore
100644 blob f8cd794a2d06e6c409737d5bcd39a20abb62db26    README
100644 blob 3bb0e8592a41ae3185ee32266c860714980dbed7    Rakefile
040000 tree ee99c7a2e9842acbab05fcd02ec510ea917218b2    app
040000 tree 0aff84690f37df01a7cac96529657222cbeeebf6               config
040000 tree 92aaeee021e9c7da661bac141ab55c17a3ae79ee    db
040000 tree 0269300738b048a5cc34769d1436d9f228499018    doc
040000 tree 1e384157d8bc3cd7aab5b0b5605e9a78d0612426    features
040000 tree 9f87e761776449b7d43ea112573f8ae27faaf826    lib
040000 tree 4875662d9a7e07a7b95b68958e518fdd65235124    public
040000 tree 11741373949f86364c10af17db764d1af3bc048f               script
040000 tree 20433690c23ae3a299b5a02147f68fdf94820370    spec
040000 tree 646d8b1458d23ba0ec396ef5748205977b023f3f    stories
040000 tree cc48cdef8eba2b5333c6a01d5795bb6efb43182f    test
040000 tree e85767f4716fd20a53d7d6455972c6ec6571c833    vendor

cf701.。。是上一个tree对象,是整个app的tree对象,熟悉Rails的人就可以看得出来这个tree目录。

请注意这些文件到mode为644或755,以保证git执行时候有足够到权限。

Commit Object
你可以用git show或git  log加–pretty=raw参数来检查你的提交,例如:

1
2
3
4
5
6
7
8
git show -s --pretty=raw cf701
commit cf70117f3cc497fba42890171d29ae404061d25f
tree 6ccb7edcdb14205861feb263a7607b8921c75fa3
parent 3e794f3e4dcb8d362bfb11464c849070bd04a35f
author Alex &lt;blackanger.z@gmail.com&gt; 1228600546 +0800
committer Alex <blackanger.z@gmail.com> 1228600546 +0800
 
modify .gitignore

看见没有?
有个parent, 这基本上是每个commit都有的,但是当一个commit没有parent的时候,那么就叫root commit,这是初始化工程第一次提交才有的。每个project必然会有一个root commit,有的有多个root commit,不过很少见(project 套project ?)。

author是这次提交的人。
committer实际创建这次提交的人,它和author有可能不同,例如,我写的代码发email给你,你帮我commit的,但实际author并不是你,对不?
comment是对这次提交的描述。这里没有我不知道为什么 。。。

Tag Object
到这里可以看到如何创建和验证一个object对象。
http://www.kernel.org/pub/software/scm/git/docs/git-tag.html


Git Directory and Working Directory

1. The Git Directory
git directory是存储你工程所有Git历史和元信息的目录。包括所有的对象,所有到不同分支的指向。
每个project仅有一个git directory。这个目录就是你工程根目录下的那个.git。例如:

1
2
3
4
cd .git
~/work/mars/.git&gt;ls
COMMIT_EDITMSG    branches    description    index        logs        refs
HEAD        config        hooks        info        objects

2.The Working Directory
工作目录自然就是你当前检出文件的目录了,大白话就是项目的目录,你要在这里面工作的。。。

The Git Index

如果把你当前修改过的这些文件比作是你从你的部队你精选出来的突击队的话,把commit比作深入敌后的话,那么这个git index就是你这支突击队在深入敌后之前的排练场,你需要在这里点兵,看看有没有怕死的逃兵漏掉。因为你要提交的只是你修改的文件,而不是全部文件,所有你只需要有一个修改文件集合就可以了。
用这个命令来看:

1
2
3
git status
# On branch master
nothing to commit (working directory clean)

我距离上次提交没有改动过任何文件,自然不会出现什么文件列表了。我无耻的抄个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$git status
# On branch master
# Your branch is behind 'origin/master' by 11 commits, and can be fast-forwarded.
#
# Changes to be committed:
#   (use "git reset HEAD &lt;file&gt;..." to unstage)
#
#   modified:   daemon.c
#
# Changed but not updated:
#   (use "git add &lt;file&gt;..." to update what will be committed)
#
#   modified:   grep.c
#   modified:   grep.h
#
# Untracked files:
#   (use "git add &lt;file&gt;..." to include in what will be committed)
#
#   blametree
#   blametree-init
#   git-gui/git-citool

用过svn的人也很容易懂把。

Setup and Initialization

安装就不说了,用mac或linux的人都会安装,用windows的人我只能无耻的抄一句别人的话来骂你:
who fucking need to run a separate software just for using git。

Git Config

1
2
3
4
5
6
7
8
$ git config --global user.name "Alex Zhang"
$ git config --global user.email “blackanger.z@gmail.com"
然后你
vi ~/.gitconfig
就会看到:
[user]
name = Alex Zhang
email = blackanger.z@gmail.com

如果你想为指定的项目用别的git 配置,那么你可以使用git config命令来修改你的信息,不需要加--global参数。

Getting a Git Repository
那么现在我需要一个Git仓库了。怎么办?

两个办法:
克隆一个已经存在的。
初始化一个新的。

如果你要clone的话,你需要知道一个project的git url。git操作跨越多个协议,例如:
git url  :  git clone git://git.kernel.org/pub/scm/git/git.git
或者
http     :  git clone http://www.kernel.org/pub/scm/git/git.git

请记住git:// 协议是更快的。但是当你有防火墙或其他原因的时候,还得用http。

Initializing a New Repository

假如你有个工程叫project,那么:

1
2
3
4
cd project
git init
则会输出:
Initialized empty Git repository in .git/

你可以去这里看git的视频:
http://www.gitcasts.com/

Normal Workflow
一般的工作流程就是:
1.增加一些新的文件
$ git add file1 file2 file3   把新文件加到git index里。
2.  git diff –cached
你可能需要显示你刚add到git index里的那些改变。如果没有--cached,那么就不会显示刚add到index的改变。 你也可以用git status来看。
git commit  你可能需要提交了。
git commit -a 把新近的改变加到index里顺便提交。
为每次commit写message是最佳实践。
svn或其他的版本控制工具也有add方法,它们只是把新加的文件加到index里来跟踪。但是git的add更加强大, git add,不仅仅是增加新文件到index里,还包括最新的修改。

Basic Branching and Merging
一个单一的git仓库就可以提供多个分支给开发者。创建一个新的分支:

1
2
3
4
5
git  branch experimental
<pre lang="bash" line="1">
如果你现在运行:
<pre lang="bash" line="1">
git branch

你就会得到一个所有分支的列表。

1
2
experimental
* master

experimenta是刚刚创建的那个,那个master是默认的分支。星号标识的是你当前所处的分支。

1
git checkout experimental

来选择那个experimental的分支内容。如果修改了一个文件,commit这个改变,并且选择回到master 分支:
(edit file)

1
2
$ git commit -a
git branch

输出

1
2
* experimental
master
1
2
$ git checkout master
git branch

输出:

1
2
experimental
master

然后你这master分支里做了一个不同的改变,然后提交。 那么现在master和experimental这两分支里都有了不同的修改,那么我们来合并这些不同:
git merge experimental
注意,你现在是这master里,把其他分支的不同合并到master里来。
如果没有冲突还好,那么有冲突怎么办?
git diff 呀

查看不同,然后解决冲突,再提交一次。

命令行里输入:
gitk
会出来一个x-windows工具,很挫的,截图给大家看,太难看,github上有个好看的工具介绍,我忘了名字了。

来看看如何解决冲突:

1
2
3
4
5
$ git merge next
100% (4/4) done
Auto-merged file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the result.

merge的时候有冲突,会有警告信息,这可真墨迹。

git status来看冲突的地方:
<<<<<<< HEAD:file.txt
Hello world
=======
Goodbye
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
那么你需要编辑文件来解决冲突,然后:

1
2
$ git add file.txt
$ git commit

具体可以看gitcasts的视频六:GitCast #6: Branching and Merging

查看历史:

git log 版本号

加各种参数可以让log格式化输入便于阅读。

以上都是简单的情况。 大体命令都去查文档吧。

Distributed Workflows
麻烦的情况怎么处理呢?
Alice有个新的工程,存储这一个git仓库:/home/alice/project, 但是Bob,在同一台机器上也有一个home目录。

Bob:

1
$ git clone /home/alice/project myrepo

创建了一个新的project,叫myrepo。
Bob修改了一些文件,然后提交它们:
(edit files)

1
2
$ git commit -a
(repeat as necessary)

当他准备好以后,他告诉Alice去更新这些改变从他的项目里:/home/bob/myrepo

那么Alice她是这么做的:

1
2
$ cd /home/alice/project
$ git pull /home/bob/myrepo master (此命令,master参数不是必须的)

这个操作把bob的master分支合并到了Alice的当前的master分支里。但是如果此时Alice有自己的改变,有可能会出现冲突。因此pull命令是两个操作:
从远程分支取一些改变。
merge到本地当前分支。

为了避免这种麻烦,我们可以这么做:

1
$ git remote add bob /home/bob/myrepo

然后先取回来bob的修改,但是并不去merge

1
$ git fetch bob

然后看看日志:

1
$ git log -p master..bob/master

然后就会显示bob的所有改变,再检查完这些改变以后,Alice就可以合并这些改变到她的分支里了:

1
$ git merge bob/master

这一步也可以这么做:

1
$ git pull . remotes/bob/master

之后, Bob更新Alice最新的改变就可以用:

1
$ git pull

没有alice的路径是因为,是bob clone的alice的代码。你可以用这个命令查看:

1
2
$ git config --get remote.origin.url
/home/alice/project

Git也可以做一份Alice master分支的原始拷贝在“origin/master”下:

1
$ git branch -r

输出
origin/master

Public git repositories
使用一个公共的仓库,这是通用的做法,这样可以把一些私有的工作过程清晰的和版本库清晰的分离出来。你只需要在你私人的仓库里完成你的工作,然后把你做的改变提交到你的那个公共仓库里,别的开发者可以从你的公共仓库里更新代码。同样,别的开发者push他的改变到他的公共仓库,你从他的公共仓库获取更新。

you push
your personal repo ——————> your public repo
^                                     |
|                                     |
| you pull                            | they pull
|                                     |
|                                     |
|               they push      V
their public repo <——————- their repo

Pushing changes to a public repository

1
2
3
$ git push ssh://yourserver.com/~you/proj.git master:master
或者是
$ git push ssh://yourserver.com/~you/proj.git master

当然你可以设置.git/config:
$ cat >>.git/config <<EOF
[remote "public-repo"]
url = ssh://yourserver.com/~you/proj.git
EOF

这样你就可以使用命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ git push public-repo master
</pr>
 
以GitHub为例子, 保存在github上的一个项目, 我查看它的config:
[remote "origin"]
url = git@github.com:blackanger/mars.git
fetch = +refs/heads/*:refs/remotes/origin/*
 
这样,我每次往github push代码就是用命令:
git push origin master
 
详细的可以去看 www.gitcasts.com
 
<em><strong>Git Tag</strong></em>
 
1.Lightweight Tags
~/work/mars&gt;git tag stable-1 cf701
~/work/mars&gt;git show stable-1
commit cf70117f3cc497fba42890171d29ae404061d25f
Author: Alex &lt;blackanger.z@gmail.com&gt;
Date:   Sun Dec 7 05:55:46 2008 +0800
 
modify .gitignore
。。。
使用tag和一个object关联起来。这是创建一个轻量级的tag。
 
Tag Objects
如果加上-a,-s或-u &lt;key-id&gt;参数,则是创建一个tag对象。
<pre lang="bash" line="1">
$ git tag -a stable-1 1b2e1d63ff

Related posts:

  1. Git服务器安装 Git on Ubuntu Server 安装Git-Core: sudo apt-get update # 可选步骤...
  2. Git详解(二) Git中级用法: Ignoring files 项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:...
  3. Git一分钟教程 流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器 取代码及修改全局设置 设置用户名与邮箱 git...

Related posts brought to you by Yet Another Related Posts Plugin.

by blackanger at 2008-12-30 01:43 AM

Git详解(二)

Git中级用法:

Ignoring files
项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ vi .gitignore
 
 
# Lines starting with '#' are considered comments.
# Ignore any file named foo.txt.
foo.txt
# Ignore (generated) html files,
*.html
# except foo.html which is maintained by hand.
!foo.html
# Ignore objects and archives.
*.[oa]
# Ignore log direction and .DS_Store files
/log
.DS_Store

你可以到http://www.kernel.org/pub/software/scm/git/docs/gitignore.html看gitignore的详细解释。你也可以把.ignore文件当到你工作目录里的任意tree目录里,然后你只需要把这个.ignore文件加到你的git 控制下,使用git add命令。

Rebasing
假设你在远程的分支origin上创建了一个分支mywork。

1
$ git checkout -b mywork origin

创建一个新分支并选中它。
然后你做了一些改变:

1
2
3
4
$ vi file.txt
$ git commit
$ vi otherfile.txt
$ git commit

与此同时,另外一些人在origin branch 上也做了一些工作,创建了两个提交。这就意味着origin和mywork会有冲突。在这一点上,你可以用pull来merge你的改变,结果是创建了一个新的merge commit。 但是你只想在mywork分支上保留你的commit历史,而不需要任何merge,那么你可以选择使用git rebase:

1
2
$ git checkout mywork
$ git rebase origin

这个命令会把你每次从mywork的提交都会以补丁的形式暂时保存在一个叫.git/rebase的目录下,当更新到origin的最新版本的时候,就会把这个补丁给新的mywork打回去,这样,就不会有任何merge commit在历史记录里。

一旦你的‘mywork’引用指向的是新被创建的那个commit对象,那么老的commit对象会被遗弃,如果你运行垃圾回收器(git gc),它们很可能会被移除。

如果rebase的过程发现冲突,那么在你解决冲突以后,使用git add命令把它们再次更新到git index里,然后你要使用:

1
$ git rebase --continue

接着中断前的rebase来,但是如果你想返回到你rebase前的状态,那只能让这个过程流产了:

1
$ git rebase --abort

Interactive Rebasing
你可以使用互动的rebase,使用这个模式,你可以在把它们提交到某地之前重写你自己的commit对象。 它可以让你容易分离merge和re-order commit, 你也可以清除已经pull到本地的commits。

你可以在git rebase后面加参数 -i,和 --interactive来给commit应用interactive模式。$ git rebase -i origin/master

一旦你执行了git rebase  -i,你就会被扔到编辑模式,我本地的代码库已经乱了,所以偷个例子吧,呵呵:
pick fc62e55 added file_size
pick 9824bf4 fixed little thing
pick 21d80a5 added number to log
pick 76b9da6 added the apply command
pick c264051 Revert “added file_size” - not implemented correctly

# Rebase f408319..b04dc3d onto f408319
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

这是说,你有5个提交。每个提交遵循下面的格式:
(action) (partial-sha) (short commit message)

现在你可以改变那个action(默认是pick),可以改成,edit或squash,或者只是保留pick。你也可以reorder commit,移除你不想要的那行就行了。当你退出编辑模式,git就会尝试应用新的commit。

Interactive Adding
这是个好方法,你可以用它来微操你的每次git add 文件到git index。 启动这个模式的命令就是:

1
git add -i

然后输出:

1
2
3
4
5
6
7
8
9
10
11
12
$>git add -i
staged     unstaged path
1:    unchanged        +4/-0 assets/stylesheets/style.css
2:    unchanged      +23/-11 layout/book_index_template.html
3:    unchanged        +7/-7 layout/chapter_template.html
4:    unchanged        +3/-3 script/pdf.rb
5:    unchanged      +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown
 
*** Commands ***
1: status   2: update   3: revert   4: add untracked
5: patch    6: diff     7: quit     8: help
What now>

看到那些命令了吧。你可以选择,如果不懂,可以输入8,然后回车,就会输出帮助:

1
2
3
4
5
6
7
8
9
10
status        - show paths with changes
update        - add working tree state to the staged set of changes
revert        - revert staged set of changes back to the HEAD version
patch         - pick hunks and update selectively
diff          - view diff between HEAD and index
add untracked - add contents of untracked files to the staged set of changes
*** Commands ***
1: [s]tatus      2: [u]pdate      3: [r]evert      4: [a]dd untracked
5: [p]atch      6: [d]iff      7: [q]uit      8: [h]elp
What now>

当然你不输入数字,直接输入help也是一样的效果。

这种模式下,你有多种选择。当你选择完毕以后,那么输入7或q退出,然后git commit你的改变,记住这里不要用git commit -a,否则你前面都做无用功了。

Stashing
当你在工作中发现一个不相关的但是却显而易见微不足道的bug的时候,你可能想在继续你的工作之前修复它。你可以用git stash来保存当前的工作状态,在修复完那个bug之后,再回来继续。

1
$ git stash "work in progress for foo feature"

这个命令会把你当前的改变保存到stash,并且会重新设置你的工作tree和匹配index到你修改bug的状态,这样在你提交修改bug代码的时候,就不会和你之前做的工作相冲突了:
… edit and test …

1
$ git commit -a -m "fix:bugs"

然后,你可以回到你之前的工作状态:

1
$ git stash apply

很好很强大。 svn好像没这功能吧?

Stash Queue

你可以stashing了多个状态(老是修bug)

这可以看到这个stash list:

1
2
3
$>git stash list
stash@{0}: WIP on book: 51bea1d... fixed images
stash@{1}: WIP on master: 9705ae6... changed the browse code to the official repo

你可以使用命令来回到你想去的那个stash:

1
git stash apply stash@{1}

清除stash可以用命令:

1
git stash clear

Git Treeishes

除了吃力的写出那40位的sha乱码来引用一个commit对象或是tree对象之外,还有很多方法。在Git里这些被称为 treeish。

Partial Sha

如果你的commit sha是980e3ccdaac54a0d4de358f3fe5d718027d96aae,git可以通过下列标识来识别它:
980e3ccdaac54a0d4de358f3fe5d718027d96aae
980e3ccdaac54a0d4
980e3cc

我自己试了试前5位,ms也能识别。

Branch, Remote or Tag Name
你也可以用branch,remote,tag name代替一个sha。
如果你的master 分支是在980e3 commit上,而且你也把它push到了origin,并且它也有一个tag name叫v1.0,那么下面这些是等价的:
980e3ccdaac54a0d4de358f3fe5d718027d96aae
origin/master
refs/remotes/origin/master
master
refs/heads/master
v1.0
refs/tags/v1.0
都代表同一个commit object

1
2
3
$ git log master
 
$ git log refs/tags/v1.0

输出是一样的。

Date Spec

1
2
git log master@{yesterday}
git log master@{1 month ago}

注意这种格式的,得到的sha会是不同的。

Ordinal Spec
git log master@{5}, 同上。

Carrot Parent
这会给你一个特别commit的第n次父类。这个格式仅对merge commits有用 - commit对象有大于一个的父类。
master^2

Tilde Spec
给你第n次commit对象的外祖父类。上上级。
master~2
这会返回这个master指向的commit对象的第一个parent的第一个parent。等价于:
master^^
你也可以这么做:
master^^^^^^
master~3^~2
master~6

Tree Pointer
master^{tree}

Blob Spec
master:/path/to/file

Range
你可能指定一个commit的范围,那么:
7b593b5..51bea1
它会包含从7b593b5开始的每次提交:
7b593b5..

Tracking Branches
一个tracking branche是指链接到远程分支的一个本地分支。当你往这个分支push和pull的时候,会自动的的push或pull到远程的那个分支。

git clone命令会自动的设置一个master分支,它是origin/master的tracking branch。
你也可以通过–track参数手动创建一个tracking branch:

1
git branch --track experimental origin/experimental

然后,当你运行:
$ git pull experimental
它会自动的从origin取代码,并且merge origin/experimental到你本地的experimental分支。
同样,当你push到origin,它会push你experimental分支到origin的experimental。

Finding with Git Grep
使用git grep(http://www.kernel.org/pub/software/scm/git/docs/git-grep.html)可以很方便的查找文件。这和通常的unix命令grep功能类似。
例如,我想查看在git版本库里用到def的每个地方,我可以运行:

1
2
3
4
5
6
7
8
9
10
11
$ git grep def
config/boot.rb:RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
config/boot.rb:    def boot!
config/boot.rb:    def booted?
config/boot.rb:      defined? Rails::Initializer
config/boot.rb:    def pick_boot
config/boot.rb:    def vendor_rails?
config/boot.rb:    def preinitialize
config/boot.rb:    def preinitializer_path
config/boot.rb:    def run
...

如果我想看行数,我也可以加-n参数:

1
2
3
4
5
6
7
8
9
10
11
$ git grep -n def
config/boot.rb:4:RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
config/boot.rb:8:    def boot!
config/boot.rb:15:    def booted?
config/boot.rb:16:      defined? Rails::Initializer
config/boot.rb:19:    def pick_boot
config/boot.rb:23:    def vendor_rails?
config/boot.rb:27:    def preinitialize
config/boot.rb:31:    def preinitializer_path
config/boot.rb:37:    def run
...

如果是仅仅感兴趣它在哪个文件,我们可以用–name-only参数:

1
2
3
4
5
6
7
$ git grep --name-only def
config/boot.rb
config/environment.rb
config/initializers/inflections.rb
config/initializers/new_rails_defaults.rb
config/routes.rb
...

我们也可以看有多少行匹配def:

1
2
3
4
5
6
$ git grep -c def
config/boot.rb:18
config/environment.rb:9
config/initializers/inflections.rb:1
config/initializers/new_rails_defaults.rb:2
config/routes.rb:2

更多可以看git grep的文档。

Undoing in Git - Reset, Checkout and Revert

Fixing un-committed mistakes
如果你已经混乱了你的working tree,但是还没有提交,那么可以使用这个命令来恢复到最近提交时候的状态:

1
$ git reset --hard HEAD

这个命令会扔掉你所有的改变,包括已经加到git index里的改变。

如果你只是想restore一个文件,那么使用checkout:

1
2
$ git checkout -- hello.rb
$ git checkout HEAD hello.rb

Fixing committed mistakes
对于已经提交的错误,有两个方法:
你可以创建一个新的commit,去undo你旧的提交做的那些事情。这是个正确的做法。

你也可以返回来修改旧的commit。一般不要这样做。

Fixing a mistake with a new commit
使用git revert命令:

1
$ git revert HEAD

你也可以revert更早的commit,例如:

1
$ git revert HEAD^

Fixing a mistake by modifying a commit

可以使用git rebase -i 修改你的commit,或用–amend参数。

Maintaining Git
Ensuring good performance
对于一个大的git仓库,可能会有一些历史信息占用了太多的空间或内存。那么可以用命令:

1
2
3
4
5
6
7
8
9
10
git gc
输出:
git gc
Counting objects: 810, done.
Compressing objects: 100% (723/723), done.
Writing objects: 100% (810/810), done.
Total 810 (delta 95), reused 0 (delta 0)
Removing duplicate objects: 100% (256/256), done.
 
Ensuring reliability

git fsck命令会在代码仓里执行一些检查并返回一些问题报告,最常见的警告是关于dangling对象:

1
2
git fsck
dangling blob 1b2b2a5e3f9518e2aa243337683391451b281d7c

Setting Up A Public Repository
假设你的私人repos是在~/.proj下面。我们首先要创建一个repos的新的clone,并且告诉git-daemon 它是public的:

1
2
$ git clone --bare ~/proj proj.git
$ touch proj.git/git-daemon-export-ok

这个结果是导出一个‘赤裸的’git repos。

下一步copy proj.git到你计划作为一个public repos的服务器。你可以用scp,rsync,或者其他。

Exporting a git repository via the git protocol
这是首选的方法。
可以启动git daemon服务,详细的看:http://www.kernel.org/pub/software/scm/git/docs/git-daemon.html

Exporting a git repository via http

1
2
3
4
$ mv proj.git /home/you/public_html/proj.git
$ cd proj.git
$ git --bare update-server-info
$ chmod a+x hooks/post-update

最后两行代码可以参看:
http://www.kernel.org/pub/software/scm/git/docs/git-update-server-info.html
http://www.kernel.org/pub/software/scm/git/docs/githooks.html
这样就可以了:

1
$ git clone http://yourserver.com/~you/proj.git


Setting Up a Private Repository

Repo Access over SSH

最简单的方式是通过ssh来使用git。

1
2
$ git clone --bare /home/user/myrepo/.git /tmp/myrepo.git
$ scp -r /tmp/myrepo.git myserver.com:/opt/git/myrepo.git

Multiple User Access using Gitosis
如果不想为每个用户都开一个单独的帐号,你需要用一个叫gitosis的工具。
http://www.urbanpuddle.com/articles/2008/07/11/installing-git-on-a-server-ubuntu-or-debian

Related posts:

  1. Git一分钟教程 流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器 取代码及修改全局设置 设置用户名与邮箱 git...
  2. Git服务器安装 Git on Ubuntu Server 安装Git-Core: sudo apt-get update # 可选步骤...
  3. Git详解(一) 我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的: commit  fa6f27b7de063c2f301b0e7148b5bd5e813faa98 tree       5e7a19c158b89fbc52a078771a833ee839727404 parent   76f31606376180ca88efa12be341dbb14fb06fdf 咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:...

Related posts brought to you by Yet Another Related Posts Plugin.

by blackanger at 2008-12-30 01:36 AM

2008-12-29

ruby中10进制和16进制的转换

16进制到10进制:
>> "B0A0".hex
=> 45216

>> "B0A0".to_i(16)
=> 45216
10进制到16进制:
>> 45216.to_s(16)
=> "b0a0"

by Captain Zhan at 2008-12-29 03:27 PM

2008-12-28

ÓиöеÄRUBYרҵÉçÇø´ó¼Ò¿´¿´

¶àÁ˸ö¿ÉÒÔ½»Á÷µÄµØ·½£¬,²»¹ýÄÚÈÝ»¹±È½ÏÉÙ

by lancky at 2008-12-28 07:25 AM

为所有HTML标签添加Hover效果

在制作网页时经常会用到onmouseover和onmouseout效果来改善用户体验,最常见的就是在指定Element中添加如下的代码来实现背景色的切换。
onmouseover='this.style.background=#666;' onmouseout="this.style.background=#fff;"
其实到达这个效果有两种方式:Javascript和CSS,上面提到是用JS来完成的,我个人更喜欢用CSS来解决类似问题。
用CSS的hover来解决这个问题,不仅简单高效,关键是低侵入性,页面上不会写太多东西。例如在li上添加这个效果:
li {background:#fff;}
li:hover {background:#666;}

这样的代码看起来简洁且方便日后维护,但也有一个问题就是在IE6下并不是所有HTML标签都支持hover这个属性,还好已经有人为IE做了这个Pacth,只需要添加一下就好了。点击下载csshover

by Raecoo at 2008-12-28 02:53 AM

2008-12-27

深入理解Blocks,Procs和lambdas

Blocks, Procs和lambdas是Ruby里最重要的方面,同时也是难点之一。这是因为Ruby处理闭包(closures)的方式比较特别。更复杂的是,Ruby有4种使用闭包的方式,它们之间还稍有不同。

First Up, Blocks

大多数情况下,使用闭包最Ruby的方式就是用Block了。

array = [1,2,3,4]
#[1, 2, 3, 4]
array.collect! do |n|
  n ** 2 (求平方)
end
#[1, 4, 9, 16]
puts array.inspect
# [1, 4, 9, 16]

so ,what’s going on here?

我们发送了‘collect!’方法给一个block代码的数组

在collect!方法内部给每个变量作平方(此处为n)

我们现在来实现自己的collect!方法,我们先建立一个iterate!方法:

class Array
  def iterate!
    self.each_with_index do |n,i|
      self[i] = yield(n)
    end
  end
end
array = [1,2,3,4]
#[1, 2, 3, 4]
array.iterate! do |n|
n ** 2
end
#[1, 4, 9, 16]

和属性不一样,你并不需要在你的方法内部指定block名字,你只需要使用yield关键字就ok了。请注意上例是如何给yield传参数n的。整个过程可以解释为:

给Array对象发送iterate!方法

当yield被调用的时候,把n(第一次1,第二次4,以此类推)传给被给的block里

block里有了可用的值,也就是n,那么就平方它。

yield输出block里返回的值,并且重写了array里面的值。

使用yield只是使用block代码的一个方法而已,这里还有另外一个,那就是作为一个Proc来调用它。看看:

class Array
  def iterate!(&amp;code)
    self.each_with_index do |n,i|
      self[i] = code.call(n)
    end
  end
end
arr = [1,2,3,4]
arr.iterate! do |n|
  n ** 2
end
 
#[1, 4, 9, 16]

和上一个例子非常相似。然而有两点不同。第一个就是iterate!的参数形式。第二点就是call方法。 输出结果是相似的,但是为什么语法不同呢?

def what_am_i(&amp;block)
  block.class
end
puts what_am_i{}
#Proc
这是一个Proc对象。block是一个Proc<pre lang="RUBY">def what_am_i
  yield.class
end
puts what_am_i{ puts "x"}&gt; x
NilClass
puts what_am_i{ "x"}
# String

这说明,使用yield直接返回的是block表达式里的值。

那么什么是Proc了?

Procedures, AKA, Procs

我们经常需要使用一个块在多个地方,这样我们就需要不断的重复我们的block,那么为了解决这个问题,做到代码复用,我们就可以使用Proc, 其实block和Proc的唯一区别就是, block是个一次性的Proc。

class Array
  def iterate!(code)
    self.each_with_index do |n, i|
      self[i] = code.call(n)
    end
  end
end
arr1 = [1,2,3,4]
arr2 = [2,3,4,5]
square = Proc.new do |n|
  n ** 2
end
 
arr1.iterate!(square)
#[1, 4, 9, 16]
arr2.iterate!(square)
#[4, 9, 16, 25]

你可能会说,用block不就完了吗?整个Proc不是多此一举。 那么请问,如果我们想给一个方法传多个closures怎么办?使用block会很不灵活。 但是用Proc就好多了:

def callbacks(procs)
  procs[:starting].call
  puts "Still going"
  procs[:finishing].call
end
callbacks(:starting #Proc.new{puts "Starting"},:finishing #Proc.new{puts "Finishing"})
 
#
Starting
Still going
Finishing

那么什么时候用block,什么时候用Proc呢?
Block: 当你的方法是被分成多个小片段,而你想让你的用户与这些片段做一些交互。
Block: 当你需要运行多个原子性表达式的时候,比如数据库迁移(migration)
Proc : 当你需要重用一个block的时候。
Proc : 当你的方法有一个或多个callbacks的时候。
Lambdas
匿名函数,在其他语言里也有。Ruby里也可用:

class Array
  def iterate(code)
    self.each_with_index do |n,i|
      self[i] = code.call(n)
    end
  end
end
arr = [1,2,3,4]
arr.iterate(lambda{|n| n**2 })
#[1, 4, 9, 16]

咋看上去,lambda和Proc执行的好像是一样。但是这里有两个细微的不同点。第一个不同就是lambda检查参数的个数。

def arguments(code)
  one, two = 1, 2
  code.call(one,two)
end
arguments(Proc.new { |a, b, c| puts "Give me a #{a} and a #{b} and a #{c.class}" })
#Give me a 1 and a 2 and a NilClass
arguments(lambda { |a, b, c| puts "Give me a #{a} and a #{b} and a #{c.class}" })
#ArgumentError: wrong number of arguments (2 for 3)

第二个不同就是,lambda有一个‘微小’的返回,什么意思呢?Proc返回会阻止一个方法的执行,并返回这个值。lambda返回它们的值,但是方法还会继续执行。看看例子:

def proc_return
  Proc.new { return "Proc.new"}.call
  return "proc_return method finished"
end
def lambda_return
  lambda{ return "lambda"}.call
  return "lambda_return method finished"
end
puts proc_return   #Proc.new
puts lambda_return  #lambda_return method finished

为什么会不同?答案就是procedures(过程)和methods(方法)的概念不同。Procs在Ruby里是代码片段,不是方法。因为这个,Proc return的就是proc_return这个方法的return,因为Proc那段就是那个方法里的代码片段。而lambdas的行为像一个方法,它检查参数的个数,而且不会覆盖调用方法的return。由于这个原因,你最好把lambdas理解为写一个方法的另类方式,只不过是匿名的而已。那么什么时候该用lamda代替Proc呢?看例子:

def generic_return(code)
  code.call
  return "generic_return method finished"
end
puts generic_return(Proc.new{return "Proc.new"})
#LocalJumpError: unexpected return
puts generic_return(lambda{return "lambda"})
# =&gt; generic_return method finished

Ruby语法里,参数部分不能带return,然而lambda行为像方法,所以它可以有个内部return。

def generic_return(code)
  one, two    = 1, 2
  three, four = code.call(one, two)
end
puts generic_return(lambda { |x, y| return x + 2, y + 2 })
puts generic_return(Proc.new { |x, y| return x + 2, y + 2 })
puts generic_return(Proc.new { |x, y| x + 2; y + 2 })
puts generic_return(Proc.new { |x, y| [x + 2, y + 2] })
# Give me a 3 and a 4
#*.rb:11: unexpected return (LocalJumpError)
#Give me a 4 and a
#  Give me a 3 and a 4

这个generic_return方法返回的是两个值,使用lambda,一切都很easy,而使用Proc,我们还不得不用数组指定x,y。

a,b =  generic_return(lambda { |x, y| return x + 2, y + 2 })
#[3, 4]
a
#3
 b
#4
 
c,d = generic_return(Proc.new { |x, y| x + 2; y + 2 })
#[4]
c
#4
 d
#nil
 e,f = generic_return(Proc.new { |x, y| [x + 2, y + 2] })
#[3, 4]
e
#3
f
#4

Method Objects
如果你有一个工作完好的方法,你想把它传到另一个方法里,作为闭包,也为了使你的代码DRY,那么你可以使用这个method方法:

class Array
  def iterate!(code)
    self.each_with_index do |n,i|
      self[i] = code.call(n)
    end
  end
end
def square(n)
  n ** 2
end
arr = [1,2,3,4]
arr.iterate!(method(:square))
#[1, 4, 9, 16]
puts method(:square).class
#  Method

这个方法对象的行为像是lambda,那么到底。。。:

puts lambda {}.class
#  Proc

呵呵,它是个Proc。
现在明白Ruby 的这四种闭包方式了吧。
block,Proc的行为更像一个代码片段,lambdas和method方法的行为更像方法。
block,Proc, lambdas都是Proc对象,而method,是Method对象。

原文请看这里

No related posts.

by blackanger at 2008-12-27 05:38 PM

custom exceptions in merb

在开发应用过程中难免需要根据实际情况自定义一些异常处理机制,这方面Merb已经将底部的架子为我们准备好了,我们只需要简单的在此基础上进行扩展就可以搞的很舒服。
Merb默认生成的Application会提供一个Exception的Controller,并包含了两个样版异常NotFound和NotAcceptable。现在我们添加一个自定义的异常在这里,假定名称为NotExists,并为其创建对应的View。
在Action中调用
def show
product = Product.find(params[:id])
raise NotExists unless product
[...]
end

这时会报错,称并不存在NotExists常量,Google了一下并没有找到合理的解释,直接看了Merb的源代码才发现,自定义异常不是这样的用法。

在Merb里如果要自定义异常,需要将自定义异常继承自一个Merb自身已存的异常,比如这样
class NotExists < Merb::ControllerExceptions::NotFound ; end
并且需要在使用该异常的Controller里进行声明(放在Application里自然会是一个不错的选择),再跑一下上面报错的程序应该就可以得到正确的结果啦~ BTW:为了这个我可查了好一会资料 :)

以下是Merb对标准Http异常的封装
class Informational < Merb::ControllerExceptions::Base; end
class Continue < Merb::ControllerExceptions::Informational; self.status = 100; end
class SwitchingProtocols < Merb::ControllerExceptions::Informational; self.status = 101; end
class Successful < Merb::ControllerExceptions::Base; end
class OK < Merb::ControllerExceptions::Successful; self.status = 200; end
class Created < Merb::ControllerExceptions::Successful; self.status = 201; end
class Accepted < Merb::ControllerExceptions::Successful; self.status = 202; end
class NonAuthoritativeInformation < Merb::ControllerExceptions::Successful; self.status = 203; end
class NoContent < Merb::ControllerExceptions::Successful; self.status = 204; end
class ResetContent < Merb::ControllerExceptions::Successful; self.status = 205; end
class PartialContent < Merb::ControllerExceptions::Successful; self.status = 206; end
class Redirection < Merb::ControllerExceptions::Base; end
class MultipleChoices < Merb::ControllerExceptions::Redirection; self.status = 300; end
class MovedPermanently < Merb::ControllerExceptions::Redirection; self.status = 301; end
class MovedTemporarily < Merb::ControllerExceptions::Redirection; self.status = 302; end
class SeeOther < Merb::ControllerExceptions::Redirection; self.status = 303; end
class NotModified < Merb::ControllerExceptions::Redirection; self.status = 304; end
class UseProxy < Merb::ControllerExceptions::Redirection; self.status = 305; end
class TemporaryRedirect < Merb::ControllerExceptions::Redirection; self.status = 307; end
class ClientError < Merb::ControllerExceptions::Base; end
class BadRequest < Merb::ControllerExceptions::ClientError; self.status = 400; end
class MultiPartParseError < Merb::ControllerExceptions::BadRequest; end
class Unauthorized < Merb::ControllerExceptions::ClientError; self.status = 401; end
class PaymentRequired < Merb::ControllerExceptions::ClientError; self.status = 402; end
class Forbidden < Merb::ControllerExceptions::ClientError; self.status = 403; end
class NotFound < Merb::ControllerExceptions::ClientError; self.status = 404; end
class ActionNotFound < Merb::ControllerExceptions::NotFound; end
class TemplateNotFound < Merb::ControllerExceptions::NotFound; end
class LayoutNotFound < Merb::ControllerExceptions::NotFound; end
class MethodNotAllowed < Merb::ControllerExceptions::ClientError; self.status = 405; end
class NotAcceptable < Merb::ControllerExceptions::ClientError; self.status = 406; end
class ProxyAuthenticationRequired < Merb::ControllerExceptions::ClientError; self.status = 407; end
class RequestTimeout < Merb::ControllerExceptions::ClientError; self.status = 408; end
class Conflict < Merb::ControllerExceptions::ClientError; self.status = 409; end
class Gone < Merb::ControllerExceptions::ClientError; self.status = 410; end
class LengthRequired < Merb::ControllerExceptions::ClientError; self.status = 411; end
class PreconditionFailed < Merb::ControllerExceptions::ClientError; self.status = 412; end
class RequestEntityTooLarge < Merb::ControllerExceptions::ClientError; self.status = 413; end
class RequestURITooLarge < Merb::ControllerExceptions::ClientError; self.status = 414; end
class UnsupportedMediaType < Merb::ControllerExceptions::ClientError; self.status = 415; end
class RequestRangeNotSatisfiable < Merb::ControllerExceptions::ClientError; self.status = 416; end
class ExpectationFailed < Merb::ControllerExceptions::ClientError; self.status = 417; end
class ServerError < Merb::ControllerExceptions::Base; end
class InternalServerError < Merb::ControllerExceptions::ServerError; self.status = 500; end
class NotImplemented < Merb::ControllerExceptions::ServerError; self.status = 501; end
class BadGateway < Merb::ControllerExceptions::ServerError; self.status = 502; end
class ServiceUnavailable < Merb::ControllerExceptions::ServerError; self.status = 503; end
class GatewayTimeout < Merb::ControllerExceptions::ServerError; self.status = 504; end
class HTTPVersionNotSupported < Merb::ControllerExceptions::ServerError; self.status = 505; end

by Raecoo at 2008-12-27 02:51 PM

2008-12-26

hack truncate in ruby 1.8.7 compability issue

add follows code into rails app environment.rb and restart the service
# http://rails.lighthouseapp.com/projects/8994/tickets/867-undefined-method-length-for-enumerable

class String
def chars
ActiveSupport::Multibyte::Chars.new(self)
end
alias_method :mb_chars, :chars
end
##
module ActionView
module Helpers
module TextHelper
def truncate(text, length = 30, truncate_string = "...")
if text.nil? then return end
l = length - truncate_string.chars.to_a.size
(text.chars.to_a.size > length ? text.chars.to_a[0...l].join + truncate_string : text).to_s
end
end
end
end

by Raecoo at 2008-12-26 03:42 AM

2008-12-25

process base64 encode in ruby

在Ruby世界中,语言本身就支持标准的Base64编码实现,而且还有不止一种实现,一个是类库base64中提供的实现(使用时需要require),一个是Ruby基础数据类型Array提供的,可直接使用.具体使用方法如下:

使用Array的实现
str = "imabase64encode"
base64_str = [str].pack(”m”)
original = base64_str.unpack(”m”)

使用Base64的实现
require "base64"
enc = Base64.encode64('Send reinforcements')
plain = Base64.decode64(enc)

请注意方法pack(’m')、unpack(’m')以及encode64和decode64的用法

建议使用Array方式的实现,在Ruby1.9中将会去除Base64这个类库 :)

by Raecoo at 2008-12-25 09:32 AM

http authentication

some information about http authentication :

As for authentication, the HTTP protocol includes the basic access authentication and the digest access authentication protocols, which allow access to a Web page only when the user has provided the correct username and password. If the server requires such credential for granting access to a Web page, the browser requests them to the user; once obtained, the browser stores and uses them also for accessing subsequent pages, without requiring the user to provide them again. From the point of view of the user, the effect is the same as if cookies were used: username and password are only requested once, and from that point on the user is given access to the site. In the basic access authentication protocol, a combination of username and password is sent to the server in every browser request. This means that someone listening in on this traffic can simply read this information and store for later use. This problem is overcome in the digest access authentication protocol, in which the username and password are encrypted using a random nonce created by the server.

see more http://en.wikipedia.org/wiki/Basic_access_authentication

by Raecoo at 2008-12-25 09:20 AM

2008-12-24

´ú¿ª¼Ó¹¤Î¬ÐÞ·¢Æ±´ú¿ª½¨Öþ·¢Æ±13313197276

±¾¹«Ë¾ºÍÈ«¹ú¸÷µØÖڶ๫˾ÓÐÒµÎñÍùÀ´£¬¿ÉÒÔÌṩ˰Îñ»ú¹Ø´ú¿ª·¢Æ±×Éѯ¡£×Éѯ·¶Î§£ºÉÌÆ·ÆÕͨÏúÊÛ·¢Æ±¡¢¹ã¸æ·¢Æ± ¡¢½¨Öþ°²×°·¢Æ±£¬·þÎñÒµ·¢Æ±£¬×âÁÞ·¢Æ±£¬·¿Îݳö×ⷢƱ£¬Ó°ÊÓÖÆ×÷·¢Æ±£¬Åàѵ×Éѯ·¢Æ±£¬ÍøÂç·þÎñ·¢Æ±£¬·­Ò뷢Ʊ£¬Ó¡Ë¢·¢Æ±£¬»áÎñ»áÒ鷢Ʊ£¬²ÍÒûסËÞ·¢Æ±£¬ÎÄ»¯ÓéÀÖ

by ÊéÇàd at 2008-12-24 06:22 AM

ɽ¶«Ê¡ÇൺÊдú¿ª·þÎñҵͳһ·¢Æ±ÑéÖ¤ºó¸¶¿î13313197276

ÎÒ¹«Ë¾±¾×ÅΪ¹óµ¥Î»ºÏÀíºÏ·¨,½ÚÊ¡¾­Óª³É±¾ºÍ¿ªÖ§, ÔÚ³ÏÐű£ÃܵĻù´¡ÉÏ,Ìṩ·¢Æ±×Éѯ¹ÜÀí·þÎñ¡£·þÎñ·¶Î§£ºÉÌÆó·¢Æ±¡¢·þÎñ·¢Æ±¡¢¹ã¸æ·¢Æ±¡¢ÔËÊ䷢Ʊ¡¢¹«Â·ÄÚºÓ·¢Æ±¡¢µÀ·½»Í¨·¢Æ±¡¢ÔËÊäװж·¢Æ±·¿ÎÝ×âÁÞ·¢Æ±¡¢×âÁÞ·¢Æ±¡¢½¨Öþ·¢Æ±¡¢²ÍÒû·¢Æ±¡¢Ò½ÁÆ·¢Æ±¡¢»ú¶¯³µÏúÊÛ·¢Æ±µÈ¡£Ëù¿ª·

by ÊéÇàd at 2008-12-24 06:21 AM

¹ã¶«Ê¡¹ãÖÝÊж«Ý¸Êдú¿ªÉÌÆ·ÏúÊÛͳһ·¢Æ±13313197276

ÎÒ˾¿ÉÒÔΪÆäËûµ¥Î»£¨¹«Ë¾£©¹©Ó¦£ºÓà¶î·¢/ƱÏêÇéÈçÏ£ºÒòϸڷöÖ²µÄ˰ÊÕÕþ²ß£¬¼ÓÉϽøÏî½Ï¶àÍê³É²»ÁËÿÔ¶¨Ë°¶î¶È,±¾¹«Ë¾ÏÖÓÐÓà¶î·¢.Ʊ£¬±¾¹«Ë¾Óë¶à¼Ò¹«Ë¾£¨ÆóÒµ£©ÓÐÒµÎñÍùÀ´£¬¿É¸ù¾Ý¿Í»§ÔÚ¡°»¥»Ý»¥Àû¡± µÄºÏ×÷»ù´¡ÉÏΪ¿Í»§(´ú¡£¿ª·¢Æ±)£¡ ¹óÆóÒµ(¹«Ë¾)ÈôÓÐÒÔÏÂÇé¿öÇëÀ´µçÁª

by ÊéÇàd at 2008-12-24 06:21 AM

ruby on rails招聘 北京十六方数字科技有限公司12月24日

Ruby网站主站开发工程师
工作年限:1-2年 招聘人数:若干人
语言能力:不限
工作地点:北京
学历:不限
职位描述/要求:
在十六方您加入的是一个创业型团队,十六方提供的是创新前沿的工作,您的工作可能对整个化工行业的发展产生实质性的影响。我们并不看重应聘者的学历和专业以及毕业学校,我们只关心素质能力和经验。热爱程序, 热爱设计, 热爱编写美丽的代码。
热爱学习跟踪最新的软件项目,热爱open source项目。
熟悉Ruby on Rails, 此外至少掌握诸如Python/PHP/Perl/C/Java/Actio