A.1 拟态方法
puts “hello,world”
这里的 puts 实际上是个方法,完整写法
puts(“hello,world”)
如果加上上下文,就是
self.puts(“hello,world”) 或者 main.puts(“hello,world”)。
由此可知 puts 多半是 Object 的一个实例方法。
去掉括号的写法使得它像个关键字,同时也更为简洁,因此称之为拟态方法。
来自 Camping 的例子:
这里的 R 实际上是一个方法,'/help' 是它的参数,返回值是一个 Class的实例。
- class Help < R '/help'
- def get
- # rendering for HTTP GET...
属性的问题:
- class MyClass
- attr_accessor :my_attr
- def initialize_attributes
- my_attr = 10 # 应该改写为 self.my_attr = 10 或 @my_attr = 10
- end
- end
- obj = MyClass.new
- obj.initialize_attributes
- obj.my_attr # => nil
注意在 initialize_attributes 中的 my_attr 具有二义性,Ruby 将无从判断这是一个局部变量,或者是一个方法,默认会当成局部变量,因此我们需要显式使用 self ,或者直接访问 @my_attr。
A.2 空指针保护
a ||= [] 等效于 a = a || []
很明显,这是Ruby 从 perl 偷师的,就是perl 的短路操作符。
A.3 关于方法参数的技巧
具名参数:又一个从 perl 学来的东西
- def my_method(args)
- args
- end
- my_method(:a => 'X' , :b => 3, :c => 'Y' ) # => {:c=>"Y", :a=>"X", :b=>3}
- #Ruby 1.9 中引入了一种更为简洁的写法
- my_method(a:'X',b:3,c:'Y')
*操作符可以把多个参数收集到一个数组中;
- def my_method(*args)
- args
- end
- my_method(1, '2' , 'three' ) # => [1, "2", "three"]
- def my_method(x, y = "a default value" )
- "#{x} and #{y}"
- end
- my_method("a value" ) # => "a value and a default value"
- def my_method(*args)
- args
- end
- my_method(:x, :y => 1, :z => 'A' ) # => [:x, {:y=>1, :z=>"A"}]
A.4 Self Yield
给方法传入一个块时,可以使用 Yield 回调。对象也可以把自身传递给块 。
来自 RubyGems 的例子
- #传统写法
- spec = Gem::Specification.new
- spec.name = "My Gem name"
- spec.version
- # ...
- #Self Yield 写法
- spec = Gem::Specification.new do |s|
- s.name = "My Gem name"
- s.version = "0.0.1"
- # ...
- end
- # Gem::Specification 源代码
- module Gem
- class Specification
- def initialize
- yield self if block_given?
- # ...
- # Ruby 中,长长的方法调用链很普遍
- ['a' , 'b' , 'c' ].push('d' ).shift.upcase.next # => "B"
- # 但是某一步出错,你将不得不如下调试
- temp = ['a' , 'b' , 'c' ].push('d' ).shift
- puts temp
- x = temp.upcase.next
- # 这非常笨拙;Ruby 1.9 中引入了 tap() 方法,我们可以这样做
- ['a' , 'b' , 'c' ].push('d' ).shift.tap {|x| puts x }.upcase.next
- # 老版本的 Ruby ,我们也可以很容易的实现一个
- class Object
- def tap
- yield self
- self
- end
- end
- # Ruby 很强大吧,缺少某项功能,我们不必坐等软件新版本的发布,我们随时可以增强它。
先看段代码
其实已经很简洁了,可变态的 Ruby 程序员还不甘心,还要可怕的压榨 Ruby。当 & 操作符作用于一个对象时,它会调用该对象的 to_proc 方法,将其转化为一个 proc 对象。 看下 to_proc 的实现
- names = ['bob' , 'bill' , 'heather' ]
- names.map {|name| name.capitalize } # => ["Bob", "Bill", "Heather"]
分析上面代码,无非就是调用 capitalize 。因此诞生了如下写法:
- names = ['bob' , 'bill' , 'heather' ]
- names.map(&:capitalize) # => ["Bob", "Bill", "Heather"]
- &:capitalize.to_proc # 等价于 &::capitalize
- class Symbol
- def to_proc
- Proc.new {|x| x.send(self) }
- end
- end