CilaCila A blogging framework for hackers.

[Code Complete]tips

| Comments |

The Power of Variable Names

  • 以问题为导向(Problem Orientation)
    • 一个好的名字表达的是what而不是how
  • 最适当的名字长度:8-20

Keep Finders on Their Own Model

| Comments |

solution but needs your judgment

class User < ActiveRecord::Base
    has_many :memberships       def find_recent_active_memberships
        memberships.only_active.order_by_activity.limit(5)      end end
class Membership < ActiveRecord::Base       belongs_to :user        scope :only_active, where(:active => true)      scope :order_by_activity, order('last_active_on DESC')  end

Put All Find() Calls Into Finders on the Model

| Comments | BestPractice, Rails

<ul>        <% User.find(:order => "last_name").each do |user| -%>      <li><%= user.last_name %> <%= user.first_name %></li> <% end %> </ul>

===========>

class UsersController < ApplicationController def index     @users = User.order("last_name") end    end

<ul>        <% @users.each do |user| -%>        <li><%= user.last_name %> <%= user.first_name %></li> <% end %> </ul>===========>
class UsersController < ApplicationController       def index           @users = User.ordered       end end

class User < ActiveRecord::Base 
    def self.ordered            order("last_name")      end end

Solution class User < ActiveRecord::Base scope :ordered, order(“last_name”) end

Follow the Law of Demeter

| Comments | BestPractice, Rails

Follow the law of Demeter

class Address < ActiveRecord::Base 
    belongs_to :customer    end
class Customer < ActiveRecord::Base         has_one :address        has_many :invoices  end
class Invoice < ActiveRecord::Base 
    belongs_to :customer    end
# Views

<%= @invoice.customer.name %>   <%= @invoice.customer.address.street %> 
<%= @invoice.customer.address.city %>
<%= @invoice.customer.address.state %>
<%= @invoice.customer.address.zip_code %>

Law of Demeter: lays out the concept that an object can call methods on a related object but that it should not reach through that object to call a method on a third. In Rails, this could be summed up as “use only one dot.”

So we can write a method :

class Customer < ActiveRecord::Base 
    has_one :address        has_many :invoices      def street          address.street      end     def city 
        address.city        end     def state           address.state       end
end

<%= @invoice.customer_name %>
<%= @invoice.customer_street %>

In addition, your public interface on Invoice has been polluted by methods that arguably have nothing to do with the rest of your interface for invoices.

Solution

Fortunately, Ruby on Rails includes a function that addresses the first concern. This method is the class-level delegate method. This method provides a shortcut for indicating that one or more methods that will be created on your object are actually provided by a related object. Using this delegate method, you can rewrite your exam- ple like this:

class Customer < ActiveRecord::Base 
    has_one :address        has_many :invoices              delegate :street, :city, :state, :zip_code, :to => :address
end
class Invoice < ActiveRecord::Base      belongs_to :customer        delegate :name,              :street,                :to => :customer,               :prefix => true
end

Ruby Way

| Comments | Ruby

面试时发现了自己的很多不足,从今天起再次系统的学习一下Ruby

Ruby.new


  • 类是状态和使用这些状态的方法的组合
  • 标准的构造函数成为new
  • 方法是通过向对象发送该消息来唤起调用的,消息包含方法名称以及方法可能需要的参数.(来自smalltalk)
  • 点(“.”)之前的东西称为receiver ,点后边的名字是调用的方法
  • 代码写在一行的话,可以用分号分句
  • 名称的第一个字符表示这个名称如何被使用: 局部变量,方法参数和方法名都以小写字母或者下划线开始,全局变量以美元符号为前缀,实例变量以@开始,类变量则以@@开始,最后类名称,模块名称都必须以大写祖母开始(@后不可直接跟数字).
  • 包含多个单词的实例变量名称在词与词之间用下划线连接,类变量则以很合大小写方式区分

  • nil是一个对象,不表示任何东西
  • nil和false代表false,其余的都是true(包括0)
  • 语句修饰符(satement modifiers)
  • /patten/ 正则表达式也是对象
  • =~ 匹配操作符,用于匹配字符串,他返回的是模式开始的位置,否则返回nil
  • block只是在花括号或者do..end之间的一组代码(花括号的绑定更紧一些),一般来说单行的时候使用花括号,多行使用do/end
  • 把block放在含有方法调用的源码行的结尾处可以实现关联,参数在block之前,方法可以使用yield一次或者多次的调用(incoke)block.
  • 在block中||之间给出的参数名来自yield

Classes,Objects and Variables

  • initialize 方法把调用new时所使用的参数传入该方法
  • 每个对象都有对实例变量的一份拷贝
  • Ruby中类永远都不是封闭的,可以打开并添加新的feature
  • 用 < 表示继承 , super 回想当前对象的弗雷发送一个消息,要求它调用子类中的同名方法.
  • 当定义一个类而没有指定父类时,Ruby默认以object类作为其父类
  • Ruby可以通过创建一个名字以等号接的方法来达成这一目标,这些方法可以作为赋值操作的目标
  • attr_reader attr_writer
  • 属性就是一个方法,通过方法暴漏出来的外部形态我们称之为属性,其他的动作就是方法.
  • 类变量被所有的对象共享,并且只存在一份拷贝,类变量在使用前必须被初始化(通常就是赋值).
  • 类变量对类及其实例都是似有的,如果你想让他们都能够被外部世界访问,需要通过实例方法或者类方法.
  • 通过在方法名之前防止类名(.)来定义类方法,或者使用self.以及class <<self 来定义类方法
  • 通过private_class_method :mothed_name 来将方法私有化.
  • public 可以被任何人调用,没有访问限制,方法默认是public的,protected方法只能被定义了该方法的类或其子类的对象所调用,整个家族均可访问,private方法不能被明确的接收者调用
  • 访问控制是在程序运行时动态判定的,只有当代码试图执行首先的方法时才会得到一个访问违规.
  • 使用pubilc,protected,private三个函数来为类或者模块定义方法的指定访问级别,也可以将方法名作为参数列表传入访问控制函数来设置他们的访问级别
  • 变量是对象的引用而不是对象,对象大多保存在堆中,并且由变量指向他们
  • 使用dup来避免创建别名

Containers,Blocks and Iterators

[Rails Tutorial]Bundler and Gems

| Comments | Bundler, Gems, RubyonRails

rails 3 中新增加了一个Library管理工具 Bundler,它提供了好的工具来管理rails3项目依赖的gems。我们需要通过Gemfile来管理requires.

下面是Gemfile的一般写法:

每个Gemfile至少要依赖于一个以上的源,通过以下的形式进行声明:

source :rubygems
source "http://rubygems.org"
source :rubyforge
source "http://gems.rubyforge.org"
source :gemcutter
source "http://gemcutter.org"

当然的由于众所周知的墙的问题,使用上边的源可能会出现某些问题…我推荐使用淘宝提供的墙内源:

source 'http://ruby.taobao.org'

通过gem关键字来声明所依赖的Gems

gem "nokogiri"
gem "rails", "3.0.0.beta3"
gem "rack",  ">=1.0"
gem "thin",  "~>1.1"

第一个参数是gem的名字,第二个参数可以指定版本,后边说明符的用法如下

  • 首先是类似于 3.0.0.beta3 这样直接指定版本号
  • >= 1.0 表示大于1.0版本
  • ~> 比较有意思,我们用一个例子来说明 ~> 2.0.3 就相当于 >= 2.0.3 并且 < 2.1. ~> 2.1 表示 >= 2.1 并且 < 3.0. ~> 2.2.beta 将匹配类似与 2.2.beta.12 的版本号。

关于Gems的详细介绍可以参见这里

  • Version 2.1.0 — 基版本
  • Version 2.2.0 — 引入了一些新特性
  • Version 2.2.1 — 修正一些Bugs
  • Version 2.2.2 — 精简了代码
  • Version 2.3.0 — 更多的新特性
  • Version 3.0.0 — 重写了接口. 应用 2.x 的代码可能会出现兼容性问题。

如果 require 的档名不同,可以加上 :require 参数

gem "rspec", :require => "spec"
gem "sqlite3-ruby", "1.2.5", :require => "sqlite3"
gem "gem-release", :require => false
gem "redis", :require => ["redis/connection/hiredis", "redis"]

更神奇的是还可以用 Git 当做来源,甚至可以指定 branch, tag 或 ref,当然了默认的 branch 是 master 啦。

gem "nokogiri", :git => "git://github.com/tenderlove/nokogiri.git", :branch => "1.4" git "git://github.com/wycats/thor.git", :tag => "v0.13.4"
gem "thor"

如果你是一个Gem的开发者,你还可以直接指定本地的gem哦

gem "nokogiri", :path => "~/sw/gems/nokogiri"

最后还要介绍一个比较重要的关键字 Group,可以指定某些Gem在特定的环境下被加载:

gem "wirble", :group => :development
gem "ruby-debug", :group => [:development, :test]
group :test do
  gem "rspec"
end

没有指定 Group 的Gems是属于 Default Group 的。 通过 Group 我们可以更方便的执行 Bundle ,比如

$ bundle install --without test development

Group的功能还是很强大的,大多数特性咱也不太会用的说,这里有老外写的某文章,可以看看啦。

直接执行$ bundle可以列出常用的命令,比如

bundle check        # 检查目前缺少哪些Gems
bundle init         # 在当前目录生成Gemfile
bundle install      # 根据Gemfile安装环境到当前的系统

关于 RubyGems 我觉得没理由不看官方文档的吧,各个方面都特别详细,有时间好好看看.

[Rails Tutorial] 自动化测试环境

| Comments | Rspec, RubyonRails, Tests

今天的这篇主要参考的Ruby-China的这篇帖子,基本是照搬…Orz

1、 新建项目(不启用Test::Unit,不执行Bundle)

$ rails new appname --skip-test-unit --skip-bundle

2、 修改 Gemfile ,并 bundle install

OS X 要安装 growl-notify ,是这里还是这里,就看你了。 liveload的浏览器扩展

(Gemfile) download
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
require 'rbconfig'
HOST_OS = RbConfig::CONFIG['host_os']
source 'http://rubygems.org'

gem 'rails', '3.2.3'

# Gems used only for assets and not required
# in production environments by default.
group :assets do
  gem 'sass-rails',   '~> 3.2.3'
  gem 'coffee-rails', '~> 3.2.1'
  gem 'uglifier', '>= 1.0.3'
end

gem 'jquery-rails'
gem 'rspec-rails' ,:group => [:development,:test]

# jquery-ui
# gem 'jquery-ui-rails'

# bootstrap
# gem 'anjlab-bootstrap-rails', :require => 'bootstrap-rails',:git => 'git://github.com/anjlab/bootstrap-rails.git'

if HOST_OS =~ /linux/i
  gem 'therubyracer', '>= 0.8.2'
end
case HOST_OS
  when /darwin/i
    gem 'rb-fsevent', :group => :development
    gem 'growl', :group => :development
    gem 'guard-pow', :group => :development
  when /linux/i
    gem 'libnotify', :group => :development
    gem 'rb-inotify', :group => :development
  when /mswin|windows/i
    gem 'rb-fchange', :group => :development
    gem 'win32console', :group => :development
    gem 'rb-notifu', :group => :development
end


# Use unicorn as the web server
# gem 'unicorn'

# Deploy with Capistrano
# gem 'capistrano'

# To use debugger
# gem 'ruby-debug19', :require => 'ruby-debug'

group :test do
  # Pretty printed test output
  gem 'turn', :require => false
  gem 'factory_girl_rails' , "~> 1.1.0" ,:require => false
  gem 'database_cleaner', ">= 0.6.7"
  # gem 'mongoid-rspec', ">= 1.4.4"
  gem "capybara",">= 1.1.1"
  gem "launchy", ">= 2.0.5"
  gem 'guard-spork'
  gem 'spork', '~> 0.9.0'
  gem "guard-rspec"
  gem 'guard-livereload'
  gem 'guard-bundler'
end

3、 初始化 Rspec,Guard, Spork

$ rails g rspec:install
$ guard init

$ bin/guard init rspec && bin/guard init spork

修改 Guardfile

(Guardfile) download
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
guard 'livereload' do
  watch(%r{app/.+\.(erb|haml)})
  watch(%r{app/helpers/.+\.rb})
  watch(%r{(public/|app/assets).+\.(css|js|html)})
  watch(%r{(app/assets/.+\.css)\.s[ac]ss}) { |m| m[1] }
  watch(%r{(app/assets/.+\.js)\.coffee}) { |m| m[1] }
  watch(%r{config/locales/.+\.yml})
end

guard 'pow' do
  watch('.powrc')
  watch('.powenv')
  watch('.rvmrc')
  watch('Gemfile')
  watch('Gemfile.lock')
  watch('config/application.rb')
  watch('config/environment.rb')
  watch(%r{^config/environments/.*\.rb$})
  watch(%r{^config/initializers/.*\.rb$})
  watch(%r{^config/settings(\.local)?\.yml$})
end

guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' } do
  watch('config/application.rb')
  watch('config/environment.rb')
  watch(%r{^config/environments/.+\.rb$})
  watch(%r{^config/initializers/.+\.rb$})
  watch('spec/spec_helper.rb')
end

guard 'rspec', :version => 2 ,:cli => "--drb",:notification => true do
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch('spec/spec_helper.rb')  { "spec/" }

  # Rails example
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^lib/(.+)\.rb$})                           { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  watch(%r{^spec/support/(.+)\.rb$})                  { "spec/" }
  watch('spec/spec_helper.rb')                        { "spec/" }
  watch('config/routes.rb')                           { "spec/routing" }
  watch('app/controllers/application_controller.rb')  { "spec/controllers" }
  # Capybara request specs
  watch(%r{^app/views/(.+)/.*\.(erb|haml)$})          { |m| "spec/requests/#{m[1]}_spec.rb" }
end

4、 修改 spechelper

如果你没有使用activerecorder 一定要按注释修改文件.

(spec_helper.rb) download
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
require 'rubygems'
require 'spork'

Spork.prefork do
  # Loading more in this block will cause your tests to run faster. However, 
  # if you change any configuration or code from libraries loaded here, you'll
  # need to restart spork for it take effect.
  # This file is copied to spec/ when you run 'rails generate rspec:install'
  ENV["RAILS_ENV"] ||= 'test'
  require File.expand_path("../../config/environment", __FILE__)
  require 'rspec/rails'
  require 'rspec/autorun'

  # Requires supporting ruby files with custom matchers and macros, etc,
  # in spec/support/ and its subdirectories.
  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

  RSpec.configure do |config|
    # == Mock Framework
    #
    # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
    #
    # config.mock_with :mocha
    # config.mock_with :flexmock
    # config.mock_with :rr
    config.mock_with :rspec

    # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
    config.fixture_path = "#{::Rails.root}/spec/fixtures"

    # If you're not using ActiveRecord, or you'd prefer not to run each of your
    # examples within a transaction, remove the following line or assign false
    # instead of true.
    config.use_transactional_fixtures = true

    # If true, the base class of anonymous controllers will be inferred
    # automatically. This will be the default behavior in future versions of
    # rspec-rails.
    config.infer_base_class_for_anonymous_controllers = false
  end
end

Spork.each_run do
  # This code will be run each time you run your specs.

end

5、执行 $ bundle exec spork --bootstrap

6、以后只要运行 $ guard 就可以了

[Rails Tutorial] 从零开始搭建 Ruby on Rails 开发环境

| Comments | Git, RubyonRails

去年8月份开始接触RoR,之后虽然做过几个小的App但是并没有对Rails进行一个系统的学习,翻看之前的代码,简直惨不忍睹,并且带有浓重的C# Style,今天捧起“Ruby on Rails 3 Tutorial”开始从头学起,从今以后将作为一个Rubyist开始新的生活。


搭建开发环境

1、安装Git

通过git-osx-installer进行安装,异常的简单,简单的使用教程可以看这里

2、安装Xcode

之后要下载并安装Xcode,当然了主要是Command Line Tools for Xcode。

3、安装Homebrew

这里先推荐的一个东西homebrew,Mac OS X 下新的软件包管理工具,比较方便的,之后就可以使用类似$ brew install unrar的命令管理包了,安装方法:

/usr/bin/ruby -e "$(/usr/bin/curl -fsSL https://raw.github.com/mxcl/homebrew/master/Library/Contributions/install_homebrew.rb)"

也可以按照这篇文章中的做法进行安装:

首先,Homebrew 的原则是“No sudo”,也就是说,既然 Mac OS X (client 版本) 绝大部分情况下都是归你这个有管理员权限的用户,为什么在自己的 /usr/local 下安装程序还需要 sudo 呢?所以,首先:

$ sudo chown -R \`whoami` /usr/local

然后可以正式开始安装,我推荐的安装方式是先用 git-osx-installer 装上 git,然后用 git 安装:

$ cd /usr/local
$ git init
$ git remote add origin git://github.com/mxcl/
$ homebrew.git
$ git pull origin master

这么做的实际作用是把你的 /usr/local 目录变成了一个本地 git 仓库,只不过这个仓库只跟踪跟 Homebrew 相关的更新,并不影响任何其他软件的安装。

这样安装会在 /usr/local 下创建 Library 这个目录,然后在 /usr/local/bin 中加入 brew 这个 ruby 脚本。

4、安装 RVM

$ bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)  

等待rvm安装好之后,配置环境变量,在当前用户目录下输入

sudo vim .bash_profile 

在其中加入

[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"

source一下即可。

安装Ruby,并设置默认版本(当前最新的是1.9.3)

$ rvm install ruby --head 
$ rvm use 1.9.3 --default

更换源

$ [sudo] gem update --system  
$ [sudo] gem uninstall rubygems-update  
$ [sudo] gem sources -r http://rubygems.org/  
$ [sudo] gem sources -a http://ruby.taobao.org  

5、安装rails

$ gem install rails -V

至此,rails的应该已经可以使用了。

6、选定编辑器

Mac下边就Textmate或者Macvim,我选的是后起之秀Sublime Text 2

详细的介绍和使用推荐Ruby-China的一篇帖子

一些常用的快捷键

  • 快如闪电查找文件:Ctrl + P
  • 方法查找或行定位(用在Ctrl + P后):@ / # /
  • 快捷命令板:Ctrl + Shift + P
  • 控制台:Ctrl + \
  • 包控制:Package Control
  • 快速代码书写:Zen Coding
  • 对齐(Ctrl + Alt + A):Alignment
  • 无干扰编辑:Shift + F11

使用 Git 进行版本控制

1、全局设置

首先是设置用户名和邮箱

$ git config --global user.name "Your Name" $ git config --global user.email youremail@example.com

$ git config --global color.diff auto
$ git config --global color.status auto
$ git config --global color.branch auto
$ git config --global color.interactive auto
$ git config --global color.ui auto

当然了也可以直接编辑~/.gitconfig,查看配置$ git config --list

为了方便起见,做一些快捷设置(别名而已)

$ git config --global alias.co checkout

然后就是设置Git的默认编辑器,我用的是Sublime Text 2

$ git config --global core.editor "subl -w"

如果使用 textmate 就把subl -w换成mate -w,同理gvim对应 “gvim -f”,MacVim对应”mvim -f”,而gedit则对应”gedit -s”。

然后初始化一下下

$ git init

.gitignore是忽略列表,Rails会自动生成一个的。

2、Adding and Committing

添加文件并且commit, -m 添加了一个消息,如果不写-m的话,会弹出编辑器让你添加的。

$ git add .
$ git commit -m "Initial commit"

使用 $ git status可以查看当前版本的状态,$ git log 查看日志,$ git checkout -f来恢复到上一个版本。

嘛,更多的命令在这里,详细的介绍要参考Wiki

3、Github

其实最好的教程还是官方的文档啦,简单全面,我在这里再稍微啰嗦几句。

首先要申请一个Github的账号,并且建立一个新的Repository,然后执行下面的命令

$ git remote add origin git@github.com:<username>/<Repositoryname>.git
$ git push origin master

这里其实是给Repository的地址起了一个别名而已,之后可以在项目文件夹下的.git/config中修改和删除。

通过 -b 签出一个新的分支,不加-b的话就是切换分支,通过$ git branch可以查看分支

$ git checkout -b new_branch

通过$ git merge <branch>来合并分支,-d是删除,-D强制删除。

另一个比较常用的命令就是$ git push了,当然了要想push到github上需要先生成密钥对

#ssh-keygen -t rsa -C "xxx@mail.com"。

把生成的密钥粘贴在Github的设置中。

补充一本书 Git Magic

4、部署在Heroku

安装并添加密钥对:

$ [sudo] gem install heroku
$ heroku keys:add

申请Heroku账号,并创建一个App

$ heroku create

Push过去就可以了

$ git push heroku master

尾声

折腾了半天,环境总算是弄好了,准备开发了。

Hello Github

| Comments |

这是一篇测试的文章。

首先来测试一下Markdows的语法

这里是一段引用。

最近想要学习的东西

  • Ruby on Rails
  • Rspec
  • 日语
  • 英语 XD

嘛 当然要测试一下代码的排版了

This is a code block.

class CleanRoom
    def a_useful_method(x);x*2;end
end 

Use the a_useful_method() function.

唉?居然是这样的么,语法还是很不熟悉啊,关于代码应该还会有更好的解决方案吧,明天再弄吧。