Ruby 1.9 更新 (語法與核心部份)

Ruby 的聖誕禮物就是版本 1.9 的釋出。

Ruby 在 2007 年的聖誕節釋出了 1.9 的版本,基本上這個版本可以視為 Ruby 2.0 的搶鮮(Preview)或是實驗(Experimental)版本,如果你現在手上有很重要的 RoR 程式在執行,還是先不要把 Ruby 更新會比較好。這裡有完整的 Changelog,如果不想看全文的,就由我這篇拙作來為各位介紹一下 Ruby 1.9 究竟有哪些改變。(這一系列的文章會分別把 Ruby 1.9 的更改逐一介紹完畢。)

  • Ruby 1.9 提供了 hash 的新寫法:
    [code lang="ruby"]
    {a: "foo", b: "bar"}
    # 本來是 {:a => "foo", :b => "bar"}
    [/code]
  • 再者,就是當內層區塊使用到與外層區塊相同的變數名稱時(shadow),Ruby 會丟出警告的訊息。另外,區塊(block)所使用的變數一律為 local:
    [code lang="ruby"]
    a = 1
    10.times{|a| a=2} # !> shadowing outer local variable - a
    a # => 1
    [/code]
  • 新的 lambda 語法:
    [code lang="ruby"]
    a = ->(b,c){ b + c }
    a.call(1,2) # => 3
    #也可以拿到括號
    -> b, c { b + c }.call(1,2) # => 3
    # 或是直接用 .() 取代 .call()
    a.(1,2) # => 3
    [/code]
  • 而 block 也可以使用 block 參數(參數名稱前加一&)
    [code lang="ruby"]
    define_method(:foo){|&b| b.call(bar)}
    [/code]
  • 新的 block 參數,會將原本的 |v| 視為 |v,|,也就是說:
    [code lang="ruby"]
    def m; yield 1, 2; end
    m{|v| v}
    [/code]
    在 1.8+ 版本以前,這個例子的 v 會讀到 [1, 2] 當成是傳入一個 array,不過會有警告訊息(說是參數個數不符),但是在 1.9 以後,這個例子的 v 只會接到 1 而忽略掉之後的參數。
  • Array 可以被切開來這樣寫:
    [code lang="ruby"]
    def foo(*a)
    a
    end

    foo(1, *[2,3], 4, *[5,6]) # => [1, 2, 3, 4, 5, 6]
    [/code]
    或是:
    [code lang="ruby"]
    a = [1,2,3]
    b = [4,5,6]
    [*a, *b]
    [/code]
    同時 1.9 也以 to_splat 取代了 to_a

    於是,選擇性的參數傳入也可以這樣寫:
    [code lang="ruby"]
    def m(a, b=nil, *c, d)
    [a,b,c,d]
    end
    m(1,2) # => [1, nil, [], 2]
    [/code]

  • ?a 改為回傳單一字元,而非數字
  • #[] 裡可以傳入 splat, assoc, 及 block 作為參數:
    [code lang="ruby"]
    class Foo; def [](*a, &block); block.call(a) end end

    a = (0..3).to_a
    Foo.new[*a, :op => :+]{|x| x } # => [0, 1, 2, 3, {:op=>:+}]
    [/code]

  • 像 C 語言中的 printf 格式化輸出字串 (%c: 單一字元; %u 數字)
  • 在 ternary (三元) 運算式(如:x ? a : b)裡可以在 : 之前斷行
  • defined? 方法回傳的值不再區分 local-variable 是否 inner-block
  • BasicObject 的結構:
    [code lang="ruby"]
    BasicObject.instance_methods
    # => ["__send__", "__id__", "==", "send", "send!", "respond_to?", "equal?", "object_id"]
    Object.ancestors # => [Object, Kernel, BasicObject]
    [/code]
  • instance_exec 方法能夠根據指定的 self 來執行區塊。
  • send 方法再也不能摸到 private variable 了!
  • require 方法會去讀 $" 裡的值作為完整路徑。所以你可以寫這樣:
    [code lang="ruby"]
    $" << File.expand_path(loaded_file) require loaded_file [/code]
  • =~ 以 nil 取代 false 的回傳值。
  • tap 方法用來作 chain-calling。如:
    [code lang="ruby"]
    "F".tap{|x| x.upcase!}[0] # => "F"
    [/code]
    上述的例子若寫成 "F".upcase![0] 則會因為 "F".upcase! 傳回 nil 而錯誤。
  • 新增 instance_variable_defined?, define_singleton_method, singleton_methods 方法。
  • 第一個hash新語法1.9被標上Ruby2,這次1.9更新會列入嗎

  • [quote comment=””]第一個hash新語法1.9被標上Ruby2,這次1.9更新會列入嗎[/quote]
    Ruby 1.9 應該就是 Ruby 2.0 的 development release。
    而且剛才 build 好 Ruby 1.9 了,的確可以 work.

    只是 p 出來的結果還是用 {:a => "foo", :b => "bar"}