高見龍

iOS app/Ruby/Rails Developer & Instructor, 喜愛非主流的新玩具 :)

Ruby 語法放大鏡之「有時候會看到有兩個冒號寫法是什麼意思?」

Ruby 語法放大鏡」系列短文主要是針對在大家學習 Ruby 或 Rails 時看到一些神奇但不知道用途的語法介紹,希望可以藉由這一系列的短文幫大家更容易的了解到底 Ruby 或 Rails 是怎麼回事。

隨便打開你 Rails 專案裡的 model 檔案,它可能會長得像這樣:

1
2
3
4
class Post < ActiveRecord::Base
  belongs_to :user
  belongs_to :category
end

第一行後面那個 ActiveRecord::Base 裡面的 2 個冒號 ::,各位知道是什麼意思嗎?

菜市場名

也許你也叫金城武(或自己覺得自己長得像金城武),然後我也剛好也很巧叫金城武,這樣在大街上大叫一聲帥哥就一堆人回頭了,不太好。

寫程式偶爾也會遇到這樣的狀況,舉例來說,如果大家剛好都有一個叫做 Animal 的類別或是 Flyable 的模組,放在同一個專案裡就會打架了。所以 Ruby 有設計 namespace 來解決這個問題。

在 Ruby 裡,因為 moduleclass 可以有巢狀結構(類別裡可以包模組,模組裡面可以包類別,就是大腸包小腸的概念啦),剛好可以拿來做 namespace 的包裝,例如:

1
2
3
4
5
6
7
module Utility
  module Flyable
    def fly
      # ....
    end
  end
end

這樣一來,如果要使用 Flyable 這個類別的話:

1
2
3
class Cat
  include Utility::Flyable
end

要 include 那個 Flyable 模組,就必須連名帶姓的 include,也就是「樹林::金城武」、「三重::劉德華」的概念。

除此之外,其實你也可把常數包在 namespace 裡:

1
2
3
4
5
6
7
8
9
10
11
12
module Utility
  TaxRate = 10
  module Flyable
    Speed = 20
    def fly
      # ....
    end
  end
end

puts Utility::TaxRate          # => 10
puts Utility::Flyable::Speed   # => 20

要使用這些常數,也是一樣要提供完整的路徑給才行。(如果你知道的話,其實不管是類別或模組,它們的名字基本上也就是常數而已)

所以,原來這段程式範例:

1
2
3
4
class Post < ActiveRecord::Base
  belongs_to :user
  belongs_to :category
end

它的意思就是說有一個叫做 Post 的類別,它是繼承自某個放在 ActiveRecord 的模組(或類別)裡的 Base 類別。如果去 github 上翻 Rails 的原始碼的話(連結),應該可以看到這段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module ActiveRecord
  # .....
  # 中略
  # .....
  class Base
    extend ActiveModel::Naming
    extend ActiveSupport::Benchmarkable
    extend ActiveSupport::DescendantsTracker

    extend ConnectionHandling
    extend QueryCache::ClassMethods
    # ... 略
  end
end

的確是有一個 ActiveRecord 的模組,裡面包了一個 Base 的類別沒錯 :)

Comments