Monday, 7 November 2011

Note FOR Ruby 1.9 之写在最后

  在Ruby中,由于函数调用时可以省略参数列表两边的括号,使一些看起来像关键字的其实却为一个Method。例如:
class X
    def my_attribute= (aValue)
        @attr = aValue
    end
end

ob.my_attribute = 1
ob.my_attribute=(1)
  类似这样把一个函数调用伪装成另一种形式称为“Mimic Method”。类似的还有private,protected,attr_reader等等。
1 class MyClass
2      attr_accessor :my_attr
3
4      def initialize_attributes
5          my_attr = 10
6      end
7 end
8
9 obj = MyClass.new
10 obj.initialize_attributes
11 puts obj.my_attr
  这里结果输出nil,因为在initialize_attributes中的my_attr = 10,这个有歧义,一个是赋值给一个变量,或者是在调用一个Mimic Method,这里Ruby默认解释为赋值,为了消除歧义则改成self.my_attr = 10即可

  Ruby中只有nil和false为布尔值FALSE,所以表达式 a ||= []的作用为: if a != nil
    a = a
else
    a = []
  利用这些特性可以减少很多为避免变量为nil的初始化操作。
  Ruby没有命名参数,但是可以将多个参数当作一个hash传入,例如:
def my_method(args)
end

my_method(:a => 'X', :b => 3, :c => 'Y')
  类似的,如果要传入一个参数数组,则:
def my_method(*args)
end

my_method('X', 3, 'Y')
  并且Ruby中Method也支持参数默认值。
Self yield用法:将对象自己传到block中使用,例如用作类的初始化:
class MyClass
    def initialize
        yield self if block_given?
......
ob = MyClass.new { |o|
    o.var = "aVar"
}
  Ruby1.9中增加了tap方法,其yields x到block中,然后返回x,可用于一个method chain中检查调用链中某方法是否正确。

  Symbol#to_proc:
names = ['a', 'b', 'c']
names.map { |name| name.capitalize }
  类似这样一个参数,并且这个参数调用一个方法称为‘one-call block’,这个在Ruby中很常见,所以有办法将其简化:
class Symbol
    def to_proc
        Proc.new { |x| x.send(self) }
    end
end
  为Symbol添加了一个to_proc方法,由此可以简化为:
names.map(&:capitalize.to_proc)
  或者names.map(&:capitalize),因为&会自动调用to_proc方法将object转化为Proc.在Ruby1.9中Symbol已经定义了to_proc方法,并且支持block带多个参数,例如inject方法

Sunday, 6 November 2011

Note FOR Ruby 1.9 之动态编程

  Ruby中动态编程特性是最Magic的部分,它支持在运行时修改执行的代码,又叫元编程,举两个例子:
  • 双引号中#{}部分可以包含一段简单的表达式,甚至一段函数,一个类
  • attr_accessor传入一个:symbol参数会生成两个方法:symbol和symbol=
  eval:eval提供计算一个字符串形式的Ruby表达式
eval("1 + 2")
  利用eval的特性很容易实现一个类似于irb的程序
  三种特殊的eval:
  1. instance_eval:访问对象的实例变量
  2. ob.instance_eval{ @aVar }
    ob.instance_eval("@aVar")
      由于eval是Object的私有方法,而instance_eval是public的,当然也可以改变eval为public的,但是不推荐
    class Object
        public :eval
    end
  3. module_eval:
  4. module X
    end

    X::module_eval { define_method(:xyz){ } }
  5. class_eval:
  6. class Y
    end

    Y::class_eval { define_method(:abc){ } }
    Y::class_eval('def hi; puts "abc"; end')
  eval的binding参数,Ruby中binding是Binding类实例:
def getBinding(str)
    return binding()
end

str = "hello"
puts eval("str + ' Fred'")
puts eval("str + ' Fred'", getBinding("bye"))
  binding方法是Kernel模块的私有方法,在这里binding是返回当前上下文的str值,所以第一个eval的上下文为main,第二个eval的上下文为getBinding方法。
  类变量操作:class_variable_get/class_variable_set/class_variables
  类实例变量操作:instance_variable_get/instance_variable_set/instance_variables
  类常量操作:const_get/const_set
  to_sym: 转换为Symbol
  remove_method移除类的某方法,而其父类的此方法保持不变;undef_method禁止调用某方法,通过实现method_missing方法来改变当调用某未定义方法时的默认行为

附:RDoc
  生成文档:rdoc
  rdoc支持在注释中包含某些格式: