A.1 拟态方法

puts “hello,world”

这里的 puts 实际上是个方法,完整写法 

puts(“hello,world”)

如果加上上下文,就是  

self.puts(“hello,world”) 或者 main.puts(“hello,world”)。

由此可知 puts 多半是 Object 的一个实例方法。

去掉括号的写法使得它像个关键字,同时也更为简洁,因此称之为拟态方法。

来自 Camping 的例子:

这里的 R 实际上是一个方法,'/help' 是它的参数,返回值是一个 Class的实例。

  1. class Help < R '/help'
  2.     def get
  3.         # rendering for HTTP GET...


属性的问题:

  1. class MyClass
  2.     attr_accessor :my_attr
  3.     def initialize_attributes
  4.         my_attr = 10 # 应该改写为 self.my_attr = 10 或 @my_attr = 10
  5.     end
  6. end
  7. obj = MyClass.new
  8. obj.initialize_attributes
  9. obj.my_attr # => nil

注意在 initialize_attributes 中的 my_attr 具有二义性,Ruby 将无从判断这是一个局部变量,或者是一个方法,默认会当成局部变量,因此我们需要显式使用 self ,或者直接访问 @my_attr。 

A.2 空指针保护

a ||= [] 等效于 a = a || []

很明显,这是Ruby 从 perl 偷师的,就是perl 的短路操作符。

A.3 关于方法参数的技巧

具名参数:又一个从 perl 学来的东西


  1. def my_method(args)
  2.     args
  3. end
  4. my_method(:a => 'X' , :b => 3, :c => 'Y' ) # => {:c=>"Y", :a=>"X", :b=>3}

  5. #Ruby 1.9 中引入了一种更为简洁的写法

  6. my_method(a:'X',b:3,c:'Y')
参数数组和默认值


*操作符可以把多个参数收集到一个数组中; 


  1. def my_method(*args)
  2.     args
  3. end
  4. my_method(1, '2' , 'three' ) # => [1, "2", "three"]
Ruby 也支持如下参数默认值:



  1. def my_method(x, y = "a default value" )
  2.     "#{x} and #{y}"
  3. end
  4. my_method("a value" ) # => "a value and a default value"
混合使用参数的惯用法



  1. def my_method(*args)
  2.     args
  3. end
  4. my_method(:x, :y => 1, :z => 'A' ) # => [:x, {:y=>1, :z=>"A"}]


A.4 Self Yield

给方法传入一个块时,可以使用 Yield 回调。对象也可以把自身传递给块 。

来自 RubyGems 的例子


  1. #传统写法
  2. spec = Gem::Specification.new
  3. spec.name = "My Gem name"
  4. spec.version
  5. # ...
  6. #Self Yield 写法
  7. spec = Gem::Specification.new do |s|
  8.     s.name = "My Gem name"
  9.     s.version = "0.0.1"
  10.     # ...
  11. end

  12. # Gem::Specification 源代码
  13. module Gem
  14.     class Specification
  15.         def initialize
  16.             yield self if block_given?
  17.             # ...
来自 tap() 的例子



  1. # Ruby 中,长长的方法调用链很普遍
  2. ['a' , 'b' , 'c' ].push('d' ).shift.upcase.next # => "B"

  3. # 但是某一步出错,你将不得不如下调试
  4. temp = ['a' , 'b' , 'c' ].push('d' ).shift
  5. puts temp
  6. x = temp.upcase.next

  7. # 这非常笨拙;Ruby 1.9 中引入了 tap() 方法,我们可以这样做
  8. ['a' , 'b' , 'c' ].push('d' ).shift.tap {|x| puts x }.upcase.next

  9. # 老版本的 Ruby ,我们也可以很容易的实现一个
  10. class Object
  11.     def tap
  12.         yield self
  13.         self
  14.     end
  15. end

  16. # Ruby 很强大吧,缺少某项功能,我们不必坐等软件新版本的发布,我们随时可以增强它。
A.5 Symbol#to_proc() 方法

先看段代码


  1. names = ['bob' , 'bill' , 'heather' ]
  2. names.map {|name| name.capitalize } # => ["Bob", "Bill", "Heather"]
其实已经很简洁了,可变态的 Ruby 程序员还不甘心,还要可怕的压榨 Ruby。


分析上面代码,无非就是调用 capitalize 。因此诞生了如下写法:

  1. names = ['bob' , 'bill' , 'heather' ]
  2. names.map(&:capitalize) # => ["Bob", "Bill", "Heather"]
当 & 操作符作用于一个对象时,它会调用该对象的 to_proc 方法,将其转化为一个 proc 对象。


  1. &:capitalize.to_proc  # 等价于 &::capitalize
 看下 to_proc 的实现 
  1. class Symbol
  2.     def to_proc
  3.         Proc.new {|x| x.send(self) }
  4.     end
  5. end





09-04 10:58