about 9 years ago

第一章我們學會了定義(Define)一個方法(Method)

第二章我們了解做一個類別(Class)來集合許多Medthod,
並使用實例變數(Instance Variable, 又稱物件變數)來讓Class的功能更強大
並且設定變數的存取權限

本章我們會實際做一個 Ruby檔案, 裡面含有:

  1. class MagaGreeter
  2. 運作method: 初始的say_hi、say_bye(Hello World!, Goodbye World)
  3. 設定一個人名(name) Tom, 然後運作Method: say_hi、say_bye(Hello Tom!, Goodbye Tom)
  4. 設定一群人名(name) 然後輪流運作每個名字的Method
  5. 如果 name 欄位無資料(nil),則跑出 "..."訊息

寫個Ruby程式檔案

打開文字編輯器(本人強烈推薦 Sublime Text 2)
開一個新檔案,檔名儲存成 mg.rb

mg.rb
class MegaGreeter
  attr_accessor :names

  # 初始化這個物件

  def initialize(names = "World")
    @names = names
  end

  # 向每個人說 hi

  def say_hi
    if @names.nil?
      puts "..."
    elsif @names.respond_to?("each")
      # 檢查 @names 是否為可以迭代(Iteration,或稱為重複運作)的陣列容器

      @names.each do |name|
        puts "Hello #{name}!"
      end
    else
      puts "Hello #{@names}!"
    end
  end
  
  # 向每個人說 bye

  def say_bye
    if @names.nil?
      puts "... \n\n" # \n是跳脫字元(Escape),代表換行的意思,打二次是為了換二行讓跑出來的結果能區隔

    elsif @names.respond_to?("join")
      # 用逗號將陣列中的元素串接成一個字串

      puts "Goodbye #{@names.join(", ")}.  Come back soon! \n\n"
    else
      puts "Goodbye #{@names}.  Come back soon! \n\n"
    end
  end

end # class MegaGreeter 結束


if __FILE__ == $0
  mg = MegaGreeter.new
  mg.say_hi
  mg.say_bye

  # 變更成 "Tom"

  mg.names = "Tom"
  mg.say_hi
  mg.say_bye

  # 變更成一個名字的陣列

  mg.names = ["Ariel", "Bell", "Chris",
    "Danny", "Eve"]
  mg.say_hi
  mg.say_bye

  # 變更成 nil

  mg.names = nil
  mg.say_hi
  mg.say_bye
end

然後在終端機(Terminal)輸入

$ ruby mg.rb

試試看跑出什麼東西

如果跑出

ruby: No such file or directory -- mg.rb (LoadError)

代表終端機所在的位子不在你儲存mg.rb檔案的資料夾

應該可以看到出來的結果是

Hello World!
Goodbye World.  Come back soon! 

Hello Tom!
Goodbye Tom.  Come back soon! 

Hello Ariel!
Hello Bell!
Hello Chris!
Hello Danny!
Hello Eve!
Goodbye Ariel, Bell, Chris, Danny, Eve.  Come back soon! 

...
...

我們一開始所說要做出的 2 3 4 5 項結果運作成功!


解析程式碼內容

我們的Method: say_hi 改變了

  # 向每個人說 hi

  def say_hi
    if @names.nil?
      puts "..."
    elsif @names.respond_to?("each")
      # 檢查 @names 是否為可以迭代(Iteration,或稱為重複運作)的陣列容器

      @names.each do |name|
        puts "Hello #{name}!"
      end
    else
      puts "Hello #{@names}!"
    end
  end

它會根據實例變數 @name 的參數不同而有不同的行為
如果是nil(nothing), 它會輸出 "..." 畢竟沒有必要對空氣打招呼麻 XD

程式運作流程邏輯是這樣的:

先檢查 @name是否為nil
如果不是(elsif)
再檢查是否能運作Method: each
如果不是(else)
運作物件的初始化設定


循環、迴圈、迭代(Iteration,或稱為重複運作)

裡面迭代的寫法
@names.each do |name|
  puts "Hello #{name}!"
end

each 是個可以在程式區塊(a block of code)裡運作的Method,它會對實例變數 @name 裡的每個元素一一去執行程式區塊
也就是 do 到 end 之間的程式碼
而 |name| 則是這個程式區塊的參數(本例中代表陣列參數: ["Ariel", "Bell", "Chris", "Danny", "Eve"] 這五個名字)
意思是說,name必須為陣列(Array)參數, each 才能運作


程式區塊的應用

class MegaGreeter後半部
  # 向每個人說 bye

  def say_bye
    if @names.nil?
      puts "... \n\n" # \n是跳脫字元(Escape),代表換行的意思,打二次是為了換二行讓跑出來的結果能區隔

    elsif @names.respond_to?("join")
      # 用逗號將陣列中的元素串接成一個字串

      puts "Goodbye #{@names.join(", ")}.  Come back soon! \n\n"
    else
      puts "Goodbye #{@names}.  Come back soon! \n\n"
    end
  end

say_bye 沒有使用each, 而是檢查 @name 是否能運作 join 這個 Method (參數是Array才能 join )
如果可以,就把這個參數(Array形態)結合成一個字串,中間用 ", "隔開
如果不行,就直接輸出

這個方法並不在乎變數真正的形態(type),而只關心變數是不是可以回應支援某個方法,這種風格叫做 “鴨子型別(Duck Typing)”,意義就是 “如果它走起來像鴨子,叫起來也像鴨子,那就當它是鴨子”。這種思維的好處是它不會被變數的型別所限制。如果有人寫了新的容器類別,並且也實作了 join 這個方法,那麼我們就可以在這裡使用它。


讓程式碼運作

if __FILE__ == $0
...
...
end

FILE 是Ruby預設內建的 Method ,內容是這個檔案的名稱
$0 是內建的全域變數,代表執行這個程式的執行檔名字

整句程式的意思是: 如果執行檔 = 這個檔案(本例中: 是的。因為我們打 $ ruby mg.rb),就執行以下的程式
這個方法可以讓我們把這個檔案當作一個程式庫使用:
如果這個檔案被當作程式庫使用(也就是從別的執行檔中呼叫這個檔案),就不會執行裡面的程式
如果當作執行檔使用,就執行裡面的程式


結尾

以上三章就是 Ruby這個程式語言裡面最基本,同時也是最重要的運作概念
Ruby on Rails就是基於以上的運作概念集合而成一個框架(Framework),來讓網站能在伺服器(server)運作順暢

當然Ruby的世界不止這些而已,只要這個基本概念融會貫通,去閱讀與吸收更進一步的Ruby資訊就不會有障礙了

← [Learn Ruby] 2. 做一個Greeter(接待員)程式 [Rails 學習心得] 4. 建立首頁版面 →
 
comments powered by Disqus