capistrano 多机部署

Posted by wxianfeng Thu, 12 Apr 2012 15:39:00 GMT

核心使用 task 指令 实现多机部署

# encoding:utf-8
# >cap local deploy
# >cap remote deploy

set :application, "entos"
set :deploy_to, "/data/projects/entos"

set :scm, "git"
set :repository,  "git@114.255.155.167:entos.git"
set :branch, "master"
set :use_sudo, false
set :rails_env,"production"

task :remote do
  set :user, "entsea"
  set :deploy_via, :remote_cache
  set :copy_exclude, %w(external)
  server "114.255.155.166", :web, :app, :db, :primary => true
end

task :local do
  set :user, 'zzq'
  set :deploy_via, :remote_cache
  set :copy_exclude, %w(external)
  server '192.168.10.105', :web, :app, :db, :primary => true
end

namespace :deploy do
  task :start do; end
  task :stop do; end

  desc "Creating ln -s , example: database.yml"
  task :create_sync do
    run "ln -s #{shared_path}/config/database.yml #{current_path}/config/database.yml"
  end

  desc "Restarting unicorn"
  task :restart, :roles => :app, :except => { :no_release => true } do
    # run "/bin/sh restart_server.sh"
  end
end

after "deploy:symlink", "deploy:create_sync"

正则 ?: 非捕获组

Posted by wxianfeng Wed, 21 Mar 2012 15:03:00 GMT

今天一个同事 问我 正则 里 ?: 什么意思,记得 以前知道的 , 愣是 忘记了 ,查了下 是非捕获组的意思!

捕获组
()内的是分组,可以用 $1,$2…取值
demo:

ruby-1.9.2-p290 :022 >   "abcabc".match(/(abc)/)
 => #<MatchData "abc" 1:"abc"> 
ruby-1.9.2-p290 :023 > $1
 => "abc" 

非捕获组
(?:) 内的不当作分组
demo:

ruby-1.9.2-p290 :024 > "abcabc".match(/(?:abc)/)
 => #<MatchData "abc"> 
ruby-1.9.2-p290 :025 > $1
 => nil 

ruby string to class

Posted by wxianfeng Thu, 17 Nov 2011 09:53:00 GMT

环境:ruby 1.9.2

有这样一个需求, 给你 任意一个字符串,把它转化为类,网上大多数的 解决办法是 下面三种:

Kernel.const_get(:User) # Object.const_get(:User)
eval(’User’)
‘User’.constantize

但是上面三种方法, 这个 User 事先必须是初始化的,不然会报错,如下:

Object.const_get(:User) # uninitialized constant User (NameError)

所以需要加个判断 这个 Class 有没有初始化,没有的话 再set 一个Class

require "rails/all"

def Kernel.const_missing(name)
  Object.const_set(name,Class.new)
end
#p Kernel.const_get("baoxiaos".to_sym) # wrong constant name baoxiaos (NameError)
p Kernel.const_get("baoxiaos".classify.to_sym) # Baoxiao , const的首字母必须大写
p Kernel.constants # []
p Object.constants.include?(:UBaoxiao) # true

刚开始把这个 const 定义在 Object 里:

require "rails/all"

def Object.const_missing(name)
  Object.const_set(name,Class.new)
end

#p Object.const_get("baoxiaos".to_sym) # wrong constant name baoxiaos (NameError)
p Object.const_get("baoxiaos".classify.to_sym)

发现 用在 rails 中后 , rails 处处报错,可能 怪我重写了 Object.const_missing 导致的 ……..

上面方法的原理是 当找不到 const的时候 执行了

  Object.const_set(name,Class.new)

那么 name 就变成是 Class 的实例了 , 为什么定义在 Kernel 中的 const_missing ,Object 也可以访问到,需要注意 Object,Kernel 之间的关系,Object 是 inluce Kernel 的,如下:

class Object
include Kernel
end

SEE:

http://niczsoft.com/2010/01/string-to-class-in-ruby-on-rails/
http://www.ruby-forum.com/topic/96222


homebrew install imagemagick

Posted by wxianfeng Sat, 10 Sep 2011 14:02:00 GMT

环境:mac os x lion
homebrew是用ruby写的脚本,发现和rvm极其相似

安装 homebrew

>/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"

安装imagemagick

>brew install imagemagick

安装到libtiff 库时 出错

curl: (7) couldn't connect to host
Error: Failure while executing: /usr/bin/curl -f#LA Homebrew\ 0.8\ (Ruby\ 1.8.7-249;\ Mac\ OS\ X\ 10.7.1) ftp://ftp.remotesensing.org/pub/libtiff/tiff-3.9.5.zip -o /Users/wangxianfeng/Library/Caches/Homebrew/libtiff-3.9.5.zip

fixed :

>/usr/bin/curl http://download2.osgeo.org/libtiff/tiff-3.9.5.zip -o ~/Library/Caches/Homebrew/libtiff-3.9.5.zip

再次安装:

>brew install imagemagick

最后测试安装成功:

wxianfeng:inono wangxianfeng$ convert --version
Version: ImageMagick 6.7.1-1 2011-09-10 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2011 ImageMagick Studio LLC
Features: OpenMP

可以查看出brew安装了下面的库:

wxianfeng:inono wangxianfeng$ brew list
imagemagick jasper jpeg libtiff little-cms

see:
https://github.com/mxcl/homebrew/wiki/installation
https://github.com/mxcl/homebrew/pull/5168


北京 798 Ruby/Rails 活动

Posted by wxianfeng Sat, 30 Jul 2011 06:36:00 GMT

时间: 2011-07-24
收获:
发现北京ROR的公司不是一般的多,签到单上看到N多公司,技术上没有太大收获,都是介绍性的,没有实战性的,内容主要涉及: mirah , Mongodb,Erlang,Grape

进程:http://www.surveymonkey.com/s/MSY2L7T

PS : 798 很好玩,很有艺术特色

现场:

093

798 入口

059

Ruby活动地方

054

Rails rumble 创始人

049

现场job board

067

现场

061

清一色老外,清一色Mac

056

介绍Mirah

045

798

083

798

043

798

MORE


ruby yaml 表示数组

Posted by wxianfeng Tue, 01 Mar 2011 13:24:00 GMT

yaml 的语法真是变态 , 表示个数组这么麻烦, 更复杂的数据结构 那不是更麻烦 !!!

yaml 文件:

# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html

one:
  name: MyString
  orgunit_id: 1
  inheritable: false
 # codes 是yaml数组表示方法
 # 缩进只能是两个空格为一级,不能是其他字符
  codes: 
    - 1
    - a
    - 2
    - b
    - 3
    - c

ruby 解析yaml:

ruby-1.9.2-p0 >   file =  "#{Rails.root}/test/fixtures/enumerations.yml"
 => "/usr/local/system/projects/entos/ent_os/test/fixtures/enumerations.yml" 
ruby-1.9.2-p0 > YAML.load File.read(file) 
 => {"one"=>{"name"=>"MyString", "orgunit_id"=>1, "inheritable"=>false, "codes"=>[1, "a", 2, "b", 3, "c"]}} 

不知道怎么写的可以 使用 to_yaml 方法 看一下:

irb(main):001:0> 
=> {"one"=>{"name"=>"MyString", "inheritable"=>false, "orgunit_id"=>1, "codes"=>[1, "a", 2, "b", 3, "c"]}}
irb(main):002:0> require "yaml"
=> true
irb(main):003:0> hsh.to_yaml
=> "--- \none: \n  name: MyString\n  inheritable: false\n  orgunit_id: 1\n  codes: \n  - 1\n  - a\n  - 2\n  - b\n  - 3\n  - c\n"

可读性 更好的 使用 y 方法

ruby-1.9.2-p0 > y hsh
--- 
one: 
  name: MyString
  orgunit_id: 1
  inheritable: false
  codes: 
  - 1
  - a
  - 2
  - b
  - 3
  - c
 => nil 

项目寻人

Posted by wxianfeng Mon, 14 Feb 2011 03:19:00 GMT

公司项目寻人,美工 + Ruby + Java + Flex + Javascript 工程师

招聘帖:

http://chinaonrails.com/topic/view/4746.html

http://www.oschina.net/bbs/thread/15953


ruby rake tips

Posted by wxianfeng Wed, 26 Jan 2011 06:59:00 GMT

环境:ruby 1.9.2 + rake 0.8.7 + rails 3.0.3

今天在写 rake 文件 , 提示我没找到 model Class,问题在于我没加 => :environment , 那为什么加上 => :environment 就可以了 , 研究了下rake:

task :test => :environment do 
end

其中后面的 :environment 也是 一个 task , 也就是说在执行 test 这个 task 之前 会执行 :environment 这个 task,有点像rails controller 中的 before_filter ,那么 :environment 这个task 定义在什么地方,rails project中也没有啊 。。。,定义在 rails 源码中了 ,你在 你的project下执行 rake environment 不会报错的

wxianfeng@ubuntu:/usr/local/system/projects/entos/ent_os$ rake environment --trace 
(in /usr/local/system/projects/entos/ent_os)
** Invoke environment (first_time)
** Execute environment

不过 也看不到 输出什么信息,因为只是加载了 运行环境而已 ,那么从哪里执行的,定义在 project 下 Rakefile 中了

# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require File.expand_path('../config/application', __FILE__)
require 'rake'

EntOs::Application.load_tasks

继续跟踪 load_tasks:

最后 找到了 task environment

   def initialize_tasks
require "rails/tasks"
task :environment do
$rails_rake_task = true
require_environment!
end
end

全部文件 here

所以加载了 environment 也就可以 找到 model Class 了

总结:

1,rake 命名格式

rakefile, Rakefile, rakefile.rb, Rakefile.rb 都可以 ,常用 Rakefile

另外 rails 中使用的话,还可以 使用 .rake 后缀的文件

2,设置命名空间

namespace :test do
end

3,设置默认task

task :default => ["test"]

可以指定多个 task,执行 rake 后 ,默认调用的是 default task

4,指定task执行顺序

task :test => [:hello,:world]

5,查看rake 任务

rake -T  
rake --tasks
rake -T db: # 查看db打头的task

6,跟踪task

rake test --trace 

更多 options

wxianfeng@ubuntu:/usr/local/system/projects/entos/ent_os$ rake -h
rake [-f rakefile] {options} targets...

Options are ...
    -C, --classic-namespace          Put Task and FileTask in the top level namespace
    -D, --describe [PATTERN]         Describe the tasks (matching optional PATTERN), then exit.
    -n, --dry-run                    Do a dry run without executing actions.
    -e, --execute CODE               Execute some Ruby code and exit.
    -p, --execute-print CODE         Execute some Ruby code, print the result, then exit.
    -E, --execute-continue CODE      Execute some Ruby code, then continue with normal task processing.
    -I, --libdir LIBDIR              Include LIBDIR in the search path for required modules.
    -P, --prereqs                    Display the tasks and dependencies, then exit.
    -q, --quiet                      Do not log messages to standard output.
    -f, --rakefile [FILE]            Use FILE as the rakefile.
    -R, --rakelibdir RAKELIBDIR,     Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')
        --rakelib
    -r, --require MODULE             Require MODULE before executing rakefile.
        --rules                      Trace the rules resolution.
    -N, --no-search, --nosearch      Do not search parent directories for the Rakefile.
    -s, --silent                     Like --quiet, but also suppresses the 'in directory' announcement.
    -g, --system                     Using system wide (global) rakefiles (usually '~/.rake/*.rake').
    -G, --no-system, --nosystem      Use standard project Rakefile search paths, ignore system wide rakefiles.
    -T, --tasks [PATTERN]            Display the tasks (matching optional PATTERN) with descriptions, then exit.
    -t, --trace                      Turn on invoke/execute tracing, enable full backtrace.
    -v, --verbose                    Log message to standard output.
    -V, --version                    Display the program version.
    -h, -H, --help                   Display this help message.

DEMO:

wxianfeng@ubuntu:~/test/rake$ cat Rakefile 
desc "Default: test"
task :default => ["r:test"]

namespace :r do 
desc "test" 
task :test  do
        puts "test"
end

desc "test1"
task :test1 => :test do
        puts "test1" 
end

desc "test3"
task :test3 => :test4 do
        puts "test3" 
end 
end

SEE:

http://hi.baidu.com/%D0%C7203/blog/item/ebda2dd09f1d698ea1ec9c7a.html
http://guides.rubyonrails.org/command_line.html
http://ericzouthoughts.wordpress.com/2009/06/20/execute-shell-command-in-ruby-rake-task/


ruby Object#tap and Object#returning

Posted by wxianfeng Wed, 19 Jan 2011 16:29:00 GMT

今天在rails中使用 returning 的时候 log 打出warning:

Object#returning has been deprecated in favor of Object#tap

环境是 ruby 1.9.2 + rails 3.0.3

从warn上看是returning不建议使用,建议使用tap方法,那么tap方法和returning方法有什么不同

Object#tap 方法是 ruby1.8.7 以后加入的,Object#returning 方法是 rails添加的

rails 3.0.3 returning 源码:here

rails 2.3.5 returning源码:

class Object
  # Returns +value+ after yielding +value+ to the block. This simplifies the
  # process of constructing an object, performing work on the object, and then
  # returning the object from a method. It is a Ruby-ized realization of the K
  # combinator, courtesy of Mikael Brockman.
  #
  # ==== Examples
  #
  #  # Without returning
  #  def foo
  #    values = []
  #    values << "bar"
  #    values << "baz"
  #    return values
  #  end
  #
  #  foo # => ['bar', 'baz']
  #
  #  # returning with a local variable
  #  def foo
  #    returning values = [] do
  #      values << 'bar'
  #      values << 'baz'
  #    end
  #  end
  #
  #  foo # => ['bar', 'baz']
  #  
  #  # returning with a block argument
  #  def foo
  #    returning [] do |values|
  #      values << 'bar'
  #      values << 'baz'
  #    end
  #  end
  #  
  #  foo # => ['bar', 'baz']
  def returning(value)
    yield(value)
    value
  end

  # Yields <code>x</code> to the block, and then returns <code>x</code>.
  # The primary purpose of this method is to "tap into" a method chain,
  # in order to perform operations on intermediate results within the chain.
  #
  #   (1..10).tap { |x| puts "original: #{x.inspect}" }.to_a.
  #     tap    { |x| puts "array: #{x.inspect}" }.
  #     select { |x| x%2 == 0 }.
  #     tap    { |x| puts "evens: #{x.inspect}" }.
  #     map    { |x| x*x }.
  #     tap    { |x| puts "squares: #{x.inspect}" }
  def tap
    yield self
    self
  end unless Object.respond_to?(:tap)

  # An elegant way to factor duplication out of options passed to a series of
  # method calls. Each method called in the block, with the block variable as
  # the receiver, will have its options merged with the default +options+ hash
  # provided. Each method called on the block variable must take an options
  # hash as its final argument.
  # 
  #   with_options :order => 'created_at', :class_name => 'Comment' do |post|
  #     post.has_many :comments, :conditions => ['approved = ?', true], :dependent => :delete_all
  #     post.has_many :unapproved_comments, :conditions => ['approved = ?', false]
  #     post.has_many :all_comments
  #   end
  #
  # Can also be used with an explicit receiver:
  #
  #   map.with_options :controller => "people" do |people|
  #     people.connect "/people",     :action => "index"
  #     people.connect "/people/:id", :action => "show"
  #   end
  #
  def with_options(options)
    yield ActiveSupport::OptionMerger.new(self, options)
  end
  
  # A duck-type assistant method. For example, Active Support extends Date
  # to define an acts_like_date? method, and extends Time to define
  # acts_like_time?. As a result, we can do "x.acts_like?(:time)" and
  # "x.acts_like?(:date)" to do duck-type-safe comparisons, since classes that
  # we want to act like Time simply need to define an acts_like_time? method.
  def acts_like?(duck)
    respond_to? "acts_like_#{duck}?"
  end

end

可以看到 tap 方法也封装了,为了防止 ruby版本过低 没有tap方法就 添加Object#tap 方法,tap 和 returning本质是一样的,函数体都是调用block闭包,只不过returning需要传递一个参数给闭包,最后返回的就是这个参数,而 tap直接操作self指针,最后返回的也就是self

另外最新rails源码(>rails3.0.3)已经没有 returning方法了,所以以后最好都用tap方法

DEMO1:

require "rubygems"
require "active_support"
# Object#tap 是>ruby1.8.7 有的
# Object#returning 是Rails 封装的方法, rails3.X 已经不建议使用

# Object#tap 可以支持链式(chain)操作
(1..10).tap {
  |x| puts "original: #{x.inspect}"
}.to_a.tap {
  |x| puts "array: #{x.inspect}"
}.select {|x| x%2==0}.tap {
  |x| puts "evens: #{x.inspect}"
}.map {|x| x*x}.tap {
  |x| puts "squares: #{x.inspect}"
}

def object_tap
  {}.tap do |h| # => Hash.new.tap
    h[:a] = 1
    h[:b] =2
  end
end

p object_tap # {:b=>2, :a=>1}

def object_returning
  returning Hash.new do |h| # 注意这里不能用 {}  , 放在 returning 方法后面 当作成 block闭包了
    h[:a] = 1
    h[:b] = 2
  end  
end

p object_returning # {:b=>2, :a=>1}

DEMO2:

require "rubygems"
require "active_support"

class Hash  
  def shift_value_tap_self
    self.tap do |h|
      h.each { |k,v| v.shift if v.is_a?(Array) }
    end
  end
  def shift_value_tap
    {}.tap do |h|
      self.each { |k,v|  v.is_a?(Array) ? h[k] = v.shift : h[k] = v } 
    end
  end

  def shift_value_returning
    returning Hash.new do |h|
      self.each { |k,v|  v.is_a?(Array) ? h[k] = v.shift : h[k] = v } 
    end
  end
  def shift_value_returning_self
    returning self do |h|
      h.each { |k,v| v.shift if v.is_a?(Array) }
    end
  end
end

hsh = {"a"=>[1,2,3],"b"=>["g","f","w"],"c"=>"fuck_china"}
hsh1 = {"a"=>[1,2,3],"b"=>["g","f","w"],"c"=>"fuck_china"}
hsh2 = {"a"=>[1,2,3],"b"=>["g","f","w"],"c"=>"fuck_china"}
hsh3 = {"a"=>[1,2,3],"b"=>["g","f","w"],"c"=>"fuck_china"}
p hsh.shift_value_tap # {"a"=>1, "b"=>"g", "c"=>"fuck_china"}
p hsh1.shift_value_returning # {"a"=>1, "b"=>"g", "c"=>"fuck_china"}
p hsh2.shift_value_tap_self # {"a"=>[2, 3], "b"=>["f", "w"], "c"=>"fuck_china"}
p hsh3.shift_value_returning_self # {"a"=>[2, 3], "b"=>["f", "w"], "c"=>"fuck_china"}

SEE:
http://blog.rubybestpractices.com/posts/gregory/011-tap-that-hash.html
http://www.simonecarletti.com/blog/2010/09/rails-3-beware-the-tap-pattern/
http://fuliang.javaeye.com/blog/857163


ruby instance_variables

Posted by wxianfeng Tue, 11 Jan 2011 05:52:00 GMT

环境:ruby 1.9.2 + ubuntu 10.10

instance_variables 得到当前 对象已经开辟内存空间的实例变量,疑惑在这里

class Foo

  attr_accessor :sex,:birthday  

end

p Foo.new.instance_variables # => []

刚开始不理解,怎么是 空……..

后来想了想,因为 ruby 是 动态的解释型的语言,如果没有 给实例变量赋值 的话,是不会开辟内存空间的,所以 instance_variables 只能得到已经开辟内存空间的 实例变量,
但是如果是 编译型的静态语言 则不然,例如java ,实例变量 声明了 就会开辟内存空间了

DEMO1:

# ruby version : 1.9.2

class Foo

  attr_accessor :sex,:birthday # attr_accessor ruby里封装的method  

end

p Foo.new.instance_variables # => []

f = Foo.new
p f.sex #=> nil
f.sex = 'M' 
p f.instance_variables #=>  [:@sex]
p f.inspect # => "#<Foo:0x85ead8c @sex=\"M\">"

b = Foo.new
b.birthday = nil # 注意赋值为nil,也开辟了内存空间
p b.instance_variables # => [:@birthday]
p b.inspect # => "#<Foo:0x9dca358 @birthday=nil>"

DEMO2:

class Foo
  
  def initialize
    @name = 'wxianfeng'
  end

  def bar # => as getter method
    @name
  end

end

f = Foo.new
p f.instance_variables #=> [:@name]
p f.inspect #=> "#<Foo:0x8aa7c08 @name=\"wxianfeng\">"
p f.name # =>  undefined method `name' for #<Foo:0x99adf7c @name="wxianfeng">
p f.bar # => "wxianfeng"

ruby 源码:

    # obj.instance_variables    => array
    #
    #
    # Returns an array of instance variable names for the receiver. Note
    # that simply defining an accessor does not create the corresponding
    # instance variable.
    #
    #    class Fred
    #      attr_accessor :a1
    #      def initialize
    #        @iv = 3
    #      end
    #    end
    #    Fred.new.instance_variables   #=> ["@iv"]
    #
    #
    def instance_variables
      # This is just a stub for a builtin Ruby method.
      # See the top of this file for more info.
    end

SEE:
http://www.megasolutions.net/ruby/instance_variables-doesnt-return-unassigned-variables-68358.aspx