RUBY 程式語言 入門導覽 [email_address]   2010.05.23@ OSSF
Who am I? 鄧慕凡, Ryudo http://blog.freebbs.tw
twitter: ryudoawaru 從 2007 年初開始使用 Ruby(Rails)
TOMLAN Software Studio founder http://www.freebbs.tw
http://www.gameclub.tw
講義 http://ryudo.freebbs.tw/
什麼是  Ruby? 開放原碼、物件導向的直譯式   (interpreted) 腳本 (script) 程式語言
簡單哲學、高生產力
精巧、自然的語法
創造者  Yukihiro Matsumoto 靈感來自  Lisp, Perl,  和  Smalltalk
減少編程時候的不必要的瑣碎時間,令編寫程序的人高興
irb: Interactive Ruby     馬上動手練習 開啟終端機: ryudo@ryudo-x61:~$ irb irb(main):001:0> 1+3 => 4 irb(main):002:0> 'hello' + ' world' => "hello world"
IRB(Interactive Ruby Shell) 互動式交談 每次指令的結果都會在下一行輸出 簡單測試的最佳工具
Ruby  是直譯式強型別語言 直譯式語言 Ruby/PHP/Perl/Python/VB 編譯式語言 Java/C/C++ 強型別 Ruby/JAVA 弱型別 PHP
Ruby 是強型別 (Strongly typed) 語言 irb(main): 003 : 0 > i= 1   =>  1   irb(main): 004 : 0 >  'hello'  + i  TypeError : can 't convert Fixnum into String from (irb):4:in `+'  from (irb): 4
整數  Integer 10 5 10000 9999999999999999999999 0 -100000
浮點數  Float 1.1 -100.28 3.14159
輸出 PUTS 輸出結果值的.to_s,然後換行 P 輸出結果值的.inspect,然後換行
通常拿來debug
輸入 gets 得到按下enter前的內容
內容是字串
後接.chomp避免把換行也加進來
整數四則運算 ( 結果整數 ) 1 + 1   #= 2 200 * 3   #= 600  10 - 999   #= -989  100 / 20   #= 5  100 / 30   #= 3
浮點數四則運算 ( 結果 Float) irb(main): 001 : 0 >  5  *  2.0  =>  10.0  irb(main): 002 : 0 >  2.0  +  100.2  =>  102.2  irb(main): 003 : 0 >  2.2  *  5.5  =>  12.1  irb(main): 004 : 0 >  100.0  /  4.0  =>  25.0  irb(main): 008 : 0 >  9.0  /  2.0  =>  4.5
更多運算 puts  5  * ( 10  +  5 ) - 13   puts  999  + ( 31456  / ( 13  *  7 ) ) *  -70
字串  String puts  'Hello, world!'   puts  ''  puts  'Good-bye.'
puts  ' 馬上就會好 '
Try it out!
字串的建構 'abc'單引號 裡面可包含" "def"雙引號 可內插變數
可內插控制字元(\r\n\t等..)
字串可 + 不可 - irb(main): 008 : 0 >  'abc'  +  'def'   =>  "abcdef"
irb(main): 010 : 0 >  'abc' .concat( 'def' )
=>  "abcdef"
irb(main): 009 : 0 >  'abc'  -  'def'
NoMethodError : undefined method `-' for "abc":String
更多字串函式 var1 =  'stop'   var2 =  'foobar'
var3 =  "aAbBcC"
var4 =  '  那很好哇  '
puts var1.reverse  #  反轉
puts var2.length  #  長度
puts var3.upcase  # 轉大寫
puts var3.downcase  # 轉小寫
puts var4.strip  # 左右去空白
格式化字串 sprintf(輸出變數)
printf(輸出畫面)
風格類似C的同名函式
%s字串, %d整數, %f浮點數..
格式化字串 i1 =  123 f1 =  456.789 printf( ' 我有  %d  元 ' , i1)  # 我有  123  元 printf( '%0.5d' , i1)  #00123 printf( '%3.5f' , f1)  #456.78900
練習1 輸出詢問名稱和年紀的訊息,再於畫面中show出對話
練習1 puts  'Hello there, and what \' s your name?' name = gets.chomp puts  'Your name is '  + name +  '? What a nice name!' puts  'Pleased to meet you, '  + name +  '. :)'
執行 ruby xx.rb
完全物件導向的語言    包括字串和數字都是物件,無內建型別 irb(main): 001 : 0 >  'abc123' .upcase  =>  "ABC123"
irb(main): 002 : 0 >  'abc123' .class
=>  String
irb(main): 003 : 0 >  'abc123'  ==  String .new( 'abc123' )
=>  true
irb(main): 004 : 0 >  5 .times{puts  ' 你累了嗎 ?' }
你累了嗎 ?
你累了嗎 ?
你累了嗎 ?
你累了嗎 ?
你累了嗎 ?
=>  5
( 區域 ) 變數  Variable 必需是小寫英文字開頭 a =  100 b =  10.5 a * b  #= 1050.0 c =  'SO' d =  'GO' c+d  #= "SOGO"
全域變數 以$開頭的變數
字串內插變數 i1 =  123 puts  "Iam#{i1}"   #"Iam123"
型別轉換  Conversions var1 =  '2' var2 =  4 var3 =  4.5 var1.to_i * var2  #= 8  var1.to_f * var3  #= 9.0  var3.to_s + var1  #=  注意是字串
常數  Constant     大寫開頭 irb(main): 001 : 0 > foo =  1   =>  1
irb(main): 002 : 0 > foo =  2
=>  2
irb(main): 003 : 0 >  Foo  =  1
=>  1
irb(main): 004 : 0 >  Foo  =  2
(irb): 4 : warning: already initialized constant  Foo
=>  2     # 雖然警告但其實 OK
irb(main): 005 : 0 >  RUBY_PLATFORM
=>  "i686-linux"
irb(main): 006 : 0 >  ENV     # 會噴出一堆環境變數
Nil 空值  表示為空
不等於false/0/空字串('') irb(main): 001 : 0 >  nil =>  nil irb(main): 002 : 0 >  nil  ==  false =>  false irb(main): 003 : 0 >  nil  ==  '' =>  false
註解 # 以#開頭之後為註解
陣列 Array http://ruby-doc.org/core-1.8.7/classes/String.html [ 1 , 2 , 3 , 4 ]  [ 1 , 'abc' , false ,[ nil , nil ]]  # 多維陣列 [ 1 , 2 , 3 , 4 ].reverse  # [4, 3, 2, 1] [ 1 , 'abc' , false ,[ nil , nil ]].size  # 4 [ 1 , 'abc' , false ,[ nil , nil ]].flatten  # [1, "abc", false, nil, nil]
索引操作 [n] 取得第n個
[n..m] 取得第n至m個
[n...m] 取得n至m-1個
[n,len]取得n開始的len個
索引操作 arr = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] p arr[ 2 .. 3 ]  #[3, 4] p arr[ 2 ... 4 ]  #[3, 4] p arr[ 2 , 2 ]  #[3, 4]
陣列相加 [ 1 , 2 , 3 ] + [ 4 , 5 , 6 ]  # [1, 2, 3, 4, 5, 6] [ 1 , 2 , 3 ].concat [ 4 , 5 , 6 ]  # [1, 2, 3, 4, 5, 6]
更多陣列函式(1) ossf=[ 'whoswho' , 'openfoundry' , 'org' ] ossf <<  'tw' # [&quot;whoswho&quot;, &quot;openfoundry&quot;, &quot;org&quot;, &quot;tw&quot;] ossf.push  'www2' # [&quot;whoswho&quot;, &quot;openfoundry&quot;, &quot;org&quot;, &quot;tw&quot;, &quot;www2&quot;] ossf.unshift  'www2' # [&quot;www2&quot;, &quot;whoswho&quot;, &quot;openfoundry&quot;, &quot;org&quot;, &quot;tw&quot;, &quot;www2&quot;
更多陣列函式 ossf.pop  # 返回從後面取出的值 ,  但陣列本身已被改變 #= [&quot;www2&quot;, &quot;whoswho&quot;, &quot;openfoundry&quot;, &quot;org&quot;, &quot;tw&quot;] ossf.shift  ## 返回從前面取出的值 ,  但陣列本身已被改變 #= [&quot;whoswho&quot;, &quot;openfoundry&quot;, &quot;org&quot;, &quot;tw&quot;]
字串陣列共通的方法 操作索引 [n]、[m..m]、[n,len]等 Enumerable類方法 each、map等 連接、逆轉相關方法 reverse、concat、delete
取得字串的字元碼 'Abcde123HG' .bytes.to_a => [ 65 ,  98 ,  99 ,  100 ,  101 ,  49 ,  50 ,  51 ,  72 ,  71 ] 'Abcde123HG' [ 1 ] =>  98
雜湊 Hash h = { :abc  =>  123 ,  'def'  =>  456 } #= {&quot;def&quot;=>456, :abc=>123} h[ :abc ] #= 123 h[ 'def' ] #= 456
字串符號 Symbols 不會變動的唯一辨識符 h2 = {  :abc  =>  123 ,  'abc'  =>  456 } #= {&quot;abc&quot;=>456, :abc=>123} :abc .object_id #= 263138  # 不論宣告幾次都是一樣的實體 'abc' .object_id #= 84140440 'abc' .object_id #= 84137350  # 字串重複宣告後就不一樣實體
PUTS/P 範例 irb(main): 011 : 0 > h = { :abc  =>  123 } => { :abc => 123 } irb(main): 012 : 0 > p h { :abc => 123 } irb(main): 013 : 0 > puts h abc123 irb(main): 014 : 0 > puts  :ossf ossf irb(main): 015 : 0 > p  :ossf :ossf
流程控制 大於  >
小於  <
大於等於  >=
等於  ==
不等於  !=
AND &&
OR ||
NOT !
結構控制 If … end
Unless … end
Case when end
if puts  &quot; 請輸入你的月薪 &quot; your_money = gets.to_i if  your_money >=  100000 puts  &quot; 哩金好野 &quot; elsif  your_money >=  22000 puts  &quot; 還好比 22K 多 &quot; else puts  ' 唉 ' end
unless 除了沒有elsif外都跟if一樣,只是條件相反
CASE aaa = [ 1  , 'abc' ,  1.3 ] p aaa printf( ' 你要確認哪一個 ?' ) idx = gets.to_i case  aaa[idx] when   String puts  &quot; 這是一個字串 &quot; when   Integer puts  &quot; 這是一個整數 &quot; when   Float puts  &quot; 這是一個浮點數 &quot; when   Numeric puts  ' 這是一個數字 ' else puts  &quot; 這是其它類型的物件 &quot; end
三元運算子 EXPRESSION ? (True Condition):(False Condition) a =  10 ; b =  100 a > b ? ( &quot;#{a} > #{b}&quot; ):( &quot;#{a} < #{b}&quot; )  #=> &quot;10 < 100&quot;
迴圈 10 .times  do   puts  ' 那很好啊 ' end for  i  in   1 .. 10 puts i end x =  100 while  x >  10 x = x -  10 puts x end x =  100 until  x <=  10 x = x –  10 next if   x ==  50  # 跳過下一步繼續 puts x end abc = [ 1 , 2 , 3 ] loop  do abc.pop p abc break   if  abc.empty?  # 跳出 end
真或假 只有nil 和 false為假,其它為真
所以空字串和0也是真
練習2 : 猜數字 亂數產生一個數字 rand(20)會產生0~20間的隨機數字
避免0 輸入一個數字
猜對了就跳出
猜錯了就顯示猜錯了 差10顯示差很大
10比內顯示接近了
練習2 : 猜數字 randnum =  0 loop  do randnum = rand( 20 ) break   if  randnum >  0 end 5 .times  do print  ' 請輸入一個數字 :' num = gets.chomp.to_i if  num == randnum puts  ' 猜對了 ~YEAH!' break end if  num - randnum >=  10 puts  &quot; 猜的大很多 &quot; elsif  (num - randnum) <  10  && (num - randnum) >=  1 puts  ' 猜的大一點 ' elsif  randnum - num >=  10 puts  ' 猜的小很多 ' else puts  ' 猜的小一點 ' end end
正規表示式 phone =  &quot;002-2882-5252&quot; if  phone =~  /( \d +) \- ( \d +) \- ( \d +)/ area =  $1 first =  $2 second =  $3 end p [area, first, second]
Method 方法 依接收者分為三大類 實體方法(Instance Method)
類別方法(Class Method)
函式性的方法
實體方法 (Instance Method) 屬於某個類別new出來的「物件實體」之方法
接收者(self)為物件實體 'abcdef' .reverse  #=> &quot;fedcba&quot;
類別方法(Class Method) 類別本身的方法
接收者(self)為類別
建立物件的.new即為類別方法 irb(main): 009 : 0 > a =  Date .today =>  #<Date: 4910677/2,0,2299161> irb(main): 010 : 0 > puts a 2010 - 05 - 22
函式性的方法 沒有接收者也能執行的方法
其實並非沒有接收者,只是被省略的情形 sprintf( &quot;%d %04x&quot; ,  123 ,  123 )  #=> &quot;123 007b
定義函式 Def 函式名稱..end
以return返回值
如無設定return,以最後一個運算式的結果為return def   hello (name) sprintf( ' 哈囉  %s' , name) end
定義函式之參數 def( 參數 ..)
可設定預設值,表示可省略
可省略者「必需」在不可省略者之前 def   showmanytimes (text2show, times =  10 )  #=> OK! times.times{puts text2show} end def   showmanytimes (times =  10 , text2show)  # =>  錯誤 times.times{puts text2show} end
? 與 ! 的慣例 函式定義以?結尾者 表示回傳值為boolean 函式定義以!結尾者 表示會改變接收者本身 irb(main): 001 : 0 > [ 1 , 2 , 3 , 4 ].empty? =>  false irb(main): 002 : 0 > [ 1 , 2 , 3 , 4 ,[ 5 , 6 ]].flatten => [ 1 ,  2 ,  3 ,  4 ,  5 ,  6 ]
類別 (Class) 與實體 (Instance) 類別 -> 模子
實體 -> 模子印出來的
Ruby的萬物皆類別! ' 我愛 OSSF' .class =>  String
定義類別 class   Duck def   initialize (name) @name  = name end def   quack  # 實體方法 &quot;#{ @name } is quacking!&quot; end end d =  Duck .new( ' 唐老鴨 !' ) puts d.quack  # 唐老鴨 ! is quacking! 建構式 ! 物件實體變數
定義類別 class  Car @@amount =  0 def   initialize (name) @name   = name @@amount +=  1 end def   name= (val) @name   = val end def   name @name end def   self . amount @@amount end end c1 =  Car .new( ' 霹靂車 '  ); c2 =  Car .new( ' 火戰車 '  ) c3 =  Car .new( 'Focus' ); c3.name =  'Focus ST' puts  &quot; 現在有  &quot;   +  Car .amount.to_s +  &quot;  台車了 &quot; 物件類別變數 實體方法
類別定義內也可以執行程式 class   Car @@amount =  0 def   initialize (name) @name  = name @@amount +=  1 end attr_accessor  :name def   self . amount @@amount end end class  Car @@amount =  0 def   initialize (name) @name   = name @@amount +=  1 end def   name= (val) @name   = val end def   name @name end def   self . amount @@amount end end =
建立物件變數的存取函式 attr_accessor 等於下面兩者相加 attr_writer 只有寫入 代替def xxx=(val) end attr_reader 只有讀取 代替 def xxx end
Public/Protected/Private Public 預設值,無限制呼叫對象 Protected 繼承者可以呼叫,外部禁止,但同類別(含子類別)的其它實體可以呼叫 Private 繼承者可以呼叫,外部禁止同類別(含子類別)的其它實體 不可以 呼叫
私有/保護 定義方式 class   Abc def   pub ... end def   priv ... end def   prot ... end private  :priv public  :pub protected  :prot end class   Abc public def   pub ... end private def   priv ... end protected def   prot ... end end =
類別之繼承 萬物皆繼承Object這個類別的子類
被繼承者為父類別(superclass)
繼承者為子類別(subclass)
繼承類別 class  Vehicle attr_accessor  :tires end class   Tire attr_accessor  :size end class   Car  <  Vehicle def   initialize (name) @tires  = [] 4 .times{ @tires  <<  Tire .new} end end class   Motorcycle  <  Vehicle def   initialize (name) @tires  = [] 2 .times{ @tires  <<  Tire .new} end end

Ruby程式語言入門導覽