วันพฤหัสบดีที่ 15 ธันวาคม พ.ศ. 2548

เปรียบ Java กับ Ruby (ด้วยความหนาของหนังสือ)

ไม่ได้เปรียบเทียบทางเทคนิค, แต่เปรียบเทียบด้วยความหนาของหนังสือว่าเรื่องแบบเดียวกันสิ่งที่ต้องเรียนรู้, กับปริมาณโค้ดมันต่างกันเยอะ. ดูแล้วค่อนข้างเวอร์ไปนิด, กึ่งลำเอียง. แต่ยกนิ้วให้คนออกไอเดียนี้ครับ. แต่ที่เขียนเปรียบเทียบจริงจังหน่อยเรื่อง Java web application กับ Ruby on Rails ก็เห็นว่าที่นี่ (ภาษาญี่ปุ่น) อธิบายไว้ดีครับ.

วันอังคารที่ 13 ธันวาคม พ.ศ. 2548

แปลคำศัพท์ด้วย Longdo dictionary จาก Firefox

ต่อยอดจาก blog อันที่แล้วที่เกี่ยวกับการ search คำด้วยการเลือกคำ, คลิ้กขวาแล้วสั่งค้นหา. คือ Mk แนะนำมาว่าให้ลองใช้ Dictionary Search extension ของ Firefox ดู. ใช้ได้ดีทีเดียว.

ขั้นตอนก็เหมือนกับการติดตั้ง extension ทั่วไปคือคลิ้กไฟล์ติดตั้ง extension .xpi ที่อยู่ที่หน้า installation ได้เลย. อาจจะต้องอนุญาตให้ Firefox ติดตั้ง extension นั้น. รีสตารท์ Firefox หนึ่งครั้งแล้วจะใช้ได้.

ต้องปรับค่าเล็กน้อย. ไปที่ Tools, extensions. เลือก DictionarySearch แล้วกด Options. ใส่คำว่า
Search Longdo Dictionary "$"
ในช่อง Text: ของ Dictionary 2. ตรง "$" จะแทนด้วยคำที่ highlight ตอนที่ใช้. และกรอก
http://dict.longdo.org/?search=$&service=
ตอนใช้ก็ highlight คำที่ต้องการแปล, คลิ้กขวา, แล้วเลือก "Search Longdo Dictionary ...". Firefox จะเปิด Tab ใหม่แล้วไปที่เว็บไซด์ http://dict.longdo.org แปลคำนั้นให้. เท่าที่ทดสอบดูมันโอเคนะ. Longdo มันแปลคำญี่ปุ่นได้ด้วยแต่ extension ตัวนี้ไม่เวิร์ก. อีกอย่าง, ไม่รู้ว่าเป็นไปได้หรือเปล่าคือมันน่าจะไปขึ้นที่ side-bar หรือไม่ก็ popup หน้่าต่างใหม่แต่เป็นหน้าต่างเล็กๆ. จะได้ไม่ต้องเปลี่ยน Tab ไปดูคำแปล.

วันอาทิตย์ที่ 11 ธันวาคม พ.ศ. 2548

Object Oriented ใน ruby

รู้สึกว่าจะหลีกเลี่ยงที่จะไม่พูดถึง object oriented ไม่ได้ (ต้องพูด) เพราะใช้ ruby ไปแล้วมันต้องไปเกี่ยวข้องกับเรื่องนี้, ก็ต้องมีความรู้ปูพื้นเรื่องนี้ไว้ด้วย.

ทุกอย่างใน ruby เป็นอ็อบเ็จค (วัตถุ) หมด. อ็อบเจ็คหรืออินสแตนซ์ (instance) เกิดมาจากคลาส (class). ให้คิดว่าคลาสเป็นแม่พิมพ์ต้นแบบหรือเป็นประเภท (type) สำหรับแยกแยะวัตถุ (อ็อบเจค) ต่างๆ. คลาสหรือตัวแม่พิมพ์จะมีการกำหนดไว้ล่วงหน้าแล้วว่าอ็อบเจคที่จัดอยู่ในคลาสนั้นๆจะมีคุณสมบัติอะไร, ทำอะไรได้บ้าง. สมมติว่าเราตั้งคลาสที่ชื่อว่า Car. รถยนต์ก็ต้องมีล้อ, มีพวงมาลัย. นอกจากพวกส่วนประกอบแล้วก็ยังต้องมีกริยาหรือการกระทำ. เช่นรถยนต์ก็ต้องวิ่งได้. เวลาเขียนโปรแกรมพวกคุณสมบัติก็มักจะเก็บอยู่ในตัวแปร, ส่วนกริยาก็เป็นฟังก์ชัน. แต่ฟังก์ชันของคลาสเรามักจะเรียกว่าเมตธอต (method). การควบคุมอ็อบเจคนั้นมักจะเกิดจากการส่ง message ให้อ็อบเจคซึ่งก็คือการเรียกใช้เมตธอตนั่นเอง. เช่นมีตัวแปรชื่อ var เก็บอ็อบเจคของคลาส String. เราก็สามารถสั่งอ็อบเจคนั้นให้ทำงานต่างๆได้ถ้าเรารู้ว่าอ็อบเจคนั้นทำอะไรได้บ้าง. สมมติว่าเราต้องการสั่งให้ var มันแสดงจำนวนอักขระที่มีอยู่ในตัวมันก็ต้องรู้ว่าต้องใช้เมตธอต length. แล้วสั่ง

irb(main):001:0> var = "Hello world"
=> "Hello world"
irb(main):002:0> puts var.length
11
=> nil
การสั่งให้อ็อบเจคทำงานในภาษา ruby จะใช้เครื่องหมายจุด . แล้วตามด้วยชื่อเมตธอต.

ถ้าอยากรู้ว่าอ็อบเจคนั้นๆจัดอยู่ในคลาสอะไรก็ใช้เมตธอต class.

irb(main):007:0> var.class
=> String
ในแนวคิดเรื่อง object oriented จะมีแนวคิดเรื่องการสืบทอดหรือที่ภาษาอังกฤษเรียกว่า inheritant อยู่ด้วยคือคลาสต่างๆสามารถสืบทอดคุณสมบัติและการกระทำมาจากคลาสอื่นๆได้ด้วย. และีคลาสต้นตระกูลร่วมของคลาสทุกตัวได้แก่คลาสที่มีชื่อว่า Object. ในตัวอย่างข้างบน var เป็นตัวแปรที่เก็บอ็อบเจคของคลาส String ก็จริงแต่เมตธอต class ที่เรียกใช้นั้นสืบทอดมาจากคลาส Object ไม่ใช่เมตธอตที่กำหนดโดยคลาส String. เมตธอตของคลาส Object ที่น่าสนใจอีกตัวคือ to_s ย่อมาจาก to string ใช้แสดงข้อมูลของอ็อบเจคนั้นในรูปของสายอักขระ.
irb(main):017:0> 4
=> 4
irb(main):018:0> 4.class
=> Fixnum
irb(main):019:0> 4.to_s
=> "4"
irb(main):020:0> 4.to_s.class
=> String
จากตัวอย่างข้างบนจะเห็นว่าถ้ามีตัวเลขเช่น 4 ในโค้ด, ruby จะถือว่า 4 นี่คืออ็อบเจคซึ่งจัดอยู่ในคลาส Fixnum. ถ้าจะแปลงให้อยู่ในรูปของสายอักขระก็ใช้เมตธอต to_s. "4.to_s" นี่ถือว่าเป็นอ็อบเจคของคลาส String แล้วดังนั้นจะส่ง message ต่อไปอีกก็ได้เช่น "4.to_s.class" ก็จะได้ผลลัพธ์เป็น String.

ทีนี้เรามาดูเรื่องการสร้างอ็อบเจค. อ็อบเจคสร้างยังไง? มันขึ้นอยู่กับคลาส, แต่ก็จะมีรูปแบบเป็นเขียนชื่อคลาสแล้วตามด้วยอาร์กิวเมนต์. ตัวอย่างเช่นจะสร้างอินสแตนซ์ของคลาส String ก็ต้องกำหนดข้อมูลของอ็อบเจคนั้นๆ.

irb(main):023:0> String("Hello")
=> "Hello"
irb(main):024:0> String "Hello"
=> "Hello"
irb(main):025:0> "Hello"
=> "Hello"
อย่าลืมว่ามันละไม่เขียนวงเล็บก็ได้. และคลาส String นี่มันพิเศษ, เวลาสร้างอินสแตนซ์ไม่ต้องเขียนชื่อคลาสก็ได้. เขียนสายอักขระในเครื่องหมายคำพูดได้เลย, ถือว่าเป็นการสร้างอ็อบเจคของคลาส String.

ในตัวอย่างข้างบนสร้างอินสแตนซ์ของคลาส String แล้วแต่ไม่มีตัวแปรเก็บอินสแตนซ์นั้นไว้. อินสแตนซ์ที่สร้างมามันก็หายไป. มันอาจจะยังไม่หายไปทันทีหรือหายไปทันที, อันนี้ไม่รู้. แต่ที่แน่ๆคือมีสิ่งที่เรียกว่า garbage collector (GC) ตรวจดูอยู่ว่าถ้ามีอินสแตนซ์ที่ไม่ได้ใช้มันก็จะลบออกไปจากหน่วยความจำ. ตรงนี้แหละทำให้เราืทำงานได้สะดวกขึ้น, ไม่ต้องมาสนใจเรื่องการจัดการหน่วยความจำเพราะมี garbage collector จัดการให้.

ถ้าไม่ต้องการให้อินสแตนซ์ที่สร้างมาหายไปเฉยๆก็เอาไปเก็บในตัวแปรซะ. โดยตัวชื่อตัวแปรได้เลยแล้วใช้เครื่องหมายเท่ากับ = จัดเก็บอ็อบเจคนั้นๆ.

irb(main):026:0> var = "Hello"
=> "Hello"
สังเกตว่าตัวแปรเหมือนกับชื่อซึ่งตั้งให้กับอ็อบเจค. ถ้าคิดในแง่ของโลกจริงๆทุกอย่างมันมีชื่อเสมอ. ของที่ไม่มีชื่อก็คือยังไม่ได้ตั้งชื่อให้แต่มีตัวตน. ก็เหมือนกับเราสร้างอินสแตนซ์ขึ้นมาแล้วไม่เก็บใส่ตัวแปร, อินสแตนซ์นั้นมีตัวตนจริงแต่ไม่มีชื่อ, เลยอ้างอิงไม่ได้ (หรืออ้างอิงลำบาก). ตัวแปรใน ruby สามารถสร้างได้ทันทีเลย, ไม่ต้องประกาศเหมือนกับตัวแปรที่ใช้ใน Java, C, C++. นอกจากจะแตกต่างตรงที่ไม่ต้องประกาศชื่อตัวแปรก่อนแล้วยังไม่ต้องระบุประเภทของตัวแปรด้วย. คือไม่ต้องบอกก่อนว่าตัวแปรชื่อ var นี่เป็นตัวแปรสำหรับอ็อบเจคประเภท (type) อะไร. ดังนั้นถ้าอยู่ๆเห็น var เฉยๆเราก็ไม่รู้หรอกว่าตัวแปรนั้นเก็บอ็อบเจคประเภทอะไรอยู่, จึงต้องใช้เมตธอต class ช่วยจะได้รู้.

ข้อสังเกตถัดไป. ถ้าเรามีตัวแปรของคลาส String อยู่เฉยๆเราจะรู้ได้อย่างไรว่าตัวแปรนั้นมีข้อมูลหรือเปล่า? ตรงนี้สามารถใช้เมตธอตของคลาส Object หรือเมตธอตของคลาส String ช่วยในเรื่องนี้.

irb(main):029:0> var.empty?
=> false
irb(main):030:0> var.nil?
=> false
เมตธอต empty? ใช้สำหรับตรวจสอบดูว่าเนื้อหาของสายอักขระนั้นมันว่างเปล่าหรือไม่. ปรกติชื่อเมตธอตที่ใช้ตรวจสอบมักจะส่งค่า true หรือ false กลับมาและชื่อเมตธอตลงท้ายด้วยเครื่องหมายคำถาม ?. ดูตอนแรกอาจจะแปลกๆ. ส่วน nil? ตรวจสอบว่ามันไม่มีตัวตนใช่หรือไม่. มาดูตัวอย่างจะเข้าใจง่ายกว่า.
irb(main):039:0> var = ""
=> ""
irb(main):040:0> var.empty?
=> true
irb(main):041:0> var.nil?
=> false
จากตัวอย่าง var มันมีตัวตน, แต่ empty ไม่ได้หมายความว่ามัน nil (ไม่มีตัวตน).

ปัญหาต่อไปคือเราจะรู้ได้อย่างไรว่ามีคลาสอะไรให้ใช้บ้างและคลาสนั้นๆมีเมตธอตอะไร? อันนี้อาจจะต้องไปอ่านเอกสาร ruby manual ก่อนรอบหนึ่งก็จะรู้ว่ามันมีคลาสมาตรฐานอะไรบ้างเช่น Object, String, Fixnum, ฯลฯ. หรือใช้คำสั่ง ri. คำสั่ง ri คล้ายๆกับ man ที่คอยจะบอกว่ามีคลาสอะไรทำอะไรได้บ้าง. ตัวอย่างการใช้เช่น

$ ri -l # แสดงคลาสทั้งหมด
OptionParser
OptionParser::accept
OptionParser::inc
...
$ ri Object#class
----------------------------------------------------------- Object#class
     obj.class    => class
------------------------------------------------------------------------
     Returns the class of _obj_, now preferred over +Object#type+, as an
     object's type in Ruby is only loosely tied to that object's class.
     This method must always be called with an explicit receiver, as
     +class+ is also a reserved word in Ruby.

        1.class      #=> Fixnum
        self.class   #=> Object
สรุป
  • คลาสเปรียบเสมือนแม่แบบ, ประเภทของวัตถุ.
  • อ็อบเจคจะมีประเภท (คลาส) เสมอ
  • คลาสที่สามารถสืบทอดคุณสมบัติกันได้และคลาสต้นตระกูลสูงสุดคือ Object.
  • ตัวแปรคือชื่อที่ตั้งให้อ็อบเจค
  • การสร้า้งอ็อบเจคหรืออินสแตนซ์ทำได้โดยการเขียนชื่อคลาสแล้วตามด้วยอาร์กิวเมนต์
  • ใช้คำสั่ง ri ดูรายชื่อคลาส, การใช้เมตธอต.

วันเสาร์ที่ 10 ธันวาคม พ.ศ. 2548

พวกคำย่อ

คำย่อที่พึ่งเรียนรู้. ชอบย่อกันนัก, ทำให้ต้องเรียนรู้.
  • RoR นึกว่าอะไร มันคือ Ruby on Rails.
  • REST: Representational State Transfer.
  • CRUD: Create, Retrieve, Update, Delete.

ruby เบื้องต้น


ไม่รู้ว่าจะเริ่มยังไงดี. เอาเป็นว่าเริ่มจาก built-in method เบื้องต้นก็แล้วกัน. built-in method นี่ก็คือ private method ที่แนะนำไปในครั้งที่แล้วหรือเรียกอีกอย่างว่า kernel method.

สคริปต์ต่อไปนี้สมมติว่าชื่อ inout.rb. เวลารันมันจะถามให้คนใช้พิมพ์อะไรเข้าไปแล้วส่งสิ่งที่พิมพ์นั้นกลับมาทางหน้าจอ. ตัวเลขที่อยู่หน้าทุกบรรทัดนั้นเพื่อความสะดวกในการอ้างอิง, ไม่ต้องพิมพ์ตาม.

     1  #!/usr/bin/ruby
     2  # filename: inout.rb
     3  # version: 0.1
     4  print "Input something: "
     5  gets
     6  print
ลองรันกันก่อนเลยดีกว่า
$ ./inout.rb
Input something: Hello there
Hello there
จะเห็นได้ว่าเราพิมพ์คำว่า Hello there ลงไปมันก็แสดงคำนั้นออกมาเท่านั้นเอง.

บรรทัดที่ 1 เป็นบรรทัดที่ต้องเขียนอยู่แล้วคือบอกว่า ruby มันอยู่ที่ไหน. บรรทัดที่ 2, 3 เป็นคอมเมนต์. ruby ก็เหมือนกับ perl, bash คือ ruby จะไม่แปลความหมายของสิ่งที่เขียนหลังเครื่องหมาย # (pound sign, ทำไมเมืองไทยเรียกเครื่องหมายสี่เหลี่ยมหวา) ไปจนจบบรรทัด.

บรรทัดที่ 4 เป็นการใช้ kernel method "print" แสดงสายอักขระบนเทอร์มินอล (stdout) และไม่เติม newline ("\n") ให้ (ขึ้นบรรทัดใหม่). บรรทัดที่ 5, gets จะอ่านข้อมูลจาก stdin หนึ่งบรรทัดและเก็บไว้ในตัวแปรพิเศษ $_ (เหมือน perl). ส่วนบรรทัดที่ 6, ใช้ print อย่างเดียวจะพิมพ์ข้อมูลที่อยู่ในตัวแปร $_ ออกมา.

ข้อสังเกตของการทำงานของสคริปต์ตัวนี้อยู่ที่เวลาเราพิมพ์ข้อความแล้วกด Enter ไป, ตัวโปรแกรมจะอ่าน newline ที่เกิดจากการกดคีย์ Enter ไปด้วย. ดังนั้นเวลาใช้ print ที่บรรทัดที่ 6 มันจะขึ้นบรรทัดใหม่ให้ด้วย.

คราวนี้ลองมาแกไขตัวโปรแกรมใหม่ให้ดูดีกว่านี้

     1  #!/usr/bin/ruby
     2  # filename: inout.rb
     3  # version: 0.2
     4  print "Input something: "
     5  line = readline
     6  line.chomp!
     7  print "You typed \"" + line + "\"\n"
แล้วลองรันดู
$ ./inout.rb 
Input something: Hello ruby
You typed "Hello ruby"
ส่วน output ของโปรแกรมเปลี่ยนไปเล็กน้อยคือมีเครื่องหมายคำพูดล้อมคำที่พิมพ์เข้าไป.

โค้ดที่แตกต่างจากอันที่แล้วคือบรรทัดที่ 5, คือใช้ method "readline" แทน "gets". readline กับ gets ทำงานเหมือนกันแต่ readline จะมีการส่ง exception EOFError เมื่อจบข้อมูล. ส่วนสิ่งที่อ่านมาได้จาก stdin ก็เก็บไว้ในตัวแปรที่ชื่อ line (ตั้งชื่อเอง). ตัวแปรใน ruby เป็นอักขระ ASCII ที่ขึ้นต้นด้วย _ หรืออักษรตัวเล็ก.

อย่างที่บอกไปแล้วว่าข้อมูลที่อ่านมากจะมี newline ติดมาด้วย, ถ้าต้องการจะตัด newline ("\n") ออกให้เหลือแต่สายอักขระล้วนๆก็ใช้ method "chomp" ที่เป็น method ที่อยู่ในคลาส String. คือข้อมูลจาก readline จะมาเป็นสายอักขระหมายความว่า line มันคือ String. เวลาเรียกใช้ method ก็แค่ใช่ใช้จุดช่วยโดยมีแบบรูปเป็น

obj.method()
หรือ
obj.method
Ruby มันอนุญาตไม่ต้องใส่วงเล็บเวลาเรียก method ก็ได้ถ้าไม่กำกวม.

method บางตัวอาจมีได้ 2 แบบเช่นในคลาส String จะมี chomp กับ chomp! อันนี้เป็นคุณลักษณะพิเศษของ ruby คือ method ที่ลงท้ายด้วยเครื่องหมายตกใจ ! จะเป็นการแก้ข้อมูลของ object ที่เรียกใช้ method นั้น. ส่วนถ้าเป็นชื่อเดียวกันแต่ไม่มีเครื่องหมายตกใจก็จะเป็นการส่งค่านั้นออกมาโดยไม่แก้ไขข้อมูลใน object.

บรรทัดที่ 7 สาธิตการเอาสายอักขระมารวมกัน. การรวมสายอักขระใน ruby ใช้เครื่องหมายบวก +

string1 + string2 + ...
จริงๆแล้ว + เป็น method อย่างหนึ่งของคลาส String, พวกนี้เรียกว่า "Instance method". ให้ดูตัวอย่างจาก irb คงเห็นภาพได้ชัดเจนขึ้น.
irb(main):001:0> data = "abc"
=> "abc"
irb(main):002:0> data + "def"
=> "abcdef"
irb(main):003:0> data.+("def")
=> "abcdef"
irb(main):004:0> data.+ "def" 
=> "abcdef"

อีกอย่างจากตัวอย่างสคริปต์คือการสร้าง object ของคลาส String ทำได้โดยการเขียนสายอักขระในเครื่องหมายคำพูดเท่านั้นเอง. หมายความว่าถ้าเราเขียน "Hello" ในโค้ดก็เรียก method ได้เลยตามตัวอย่างที่แสดงต่อไปนี้.

irb(main):001:0> "Hello".length
=> 5
irb(main):002:0> var = "Hello".upcase
=> "HELLO"
irb(main):003:0> var.downcase!
=> "hello"
irb(main):004:0> var
=> "hello"

สรุป

  • print เป็น kernel method ใช้พิมพ์ข้อความออกทาง stdout
  • gets คล้ายกับ readline แต่ readline มีการปล่อย EOFError เมื่ออ่านข้อมูลเสร็จ
  • gets กับ readline ถ้าไม่มีการเอาผลลัพธ์ไปใส่ตัวแปรก็จะเก็บค่าที่อ่านจาก stdin ไว้ที่ตัวแปรพิเศษที่ชื่อ $_
  • การเรียกใช้ method ของ object ทำได้โดยการเขียนเครื่องหมายจุด . ระหว่าง object กับ method.
  • เวลาเรียกใช้ method ไม่ต้องใส่เครื่องหมายวงเล็บก็ได้ หรือจะใส่ถ้าไม่อยากให้งง
  • object หรือ instance ของคลาส String สร้างขึ้นมาโดยใช้เครื่องหมายคำพูดเช่น "Hello", 'Hello'.
  • การรวมสายอักขระใช้เครื่องหมายบวก ซึ่งจริงๆแล้วเป็นการเรียก instance method ที่ชื่อ +.

del.icio.us/poonlap

อ่านข่าวจาก slashdot ว่า Yahoo! ซื้อ del.icio.us ไปเรียบร้อยแล้ว, หลังจากที่ก่อนหน้านี้ก็ซื้อ Flickr ซึ่งเป็นเว็บไซด์บริการอัปโหลดรูปภาพ. คราวนี้มาซื้อ del.icio.us ซึ่งเป็นเว็บไซด์บริการเก็บ bookmark. ก็น่าสนใจว่า Yahoo! จะซื้ออะไรต่อไป.

เห็น del.icio.us มานานพอควรแต่ไม่เคยใช้. สิ่งแรกที่่สะดุดตาคือชื่อ domain. เข้าใจตั้งชื่อ Delicious เล่นกับ .us ซึ่งเป็น TLD ของอเมริกา. เข้าไปใช้บริการของ del.icio.us ดูแล้ว. ให้ความรู้สึกเหมือน Flickr คือผู้บันทึก bookmark เป็นคนกำหนด Tag ของ URL ที่บันทึกลงไป. ตอนแรกก็ยังนึกอยู่ว่าบริการนี้ไม่เห็นน่าใช้เลย, เป็นแค่ bookmark บนเว็บ, ถ้าจะ bookmark ก็ทำในเว็บเบราเซอร์ของตัวเองก็ได้. แต่พอลองใช้ดูสักพักก็พอว่ามันดึงดูดตรง Tag นี่แหละ. สมมติเรา bookmark URL ที่เราชอบไว้, ก็เห็นคนอื่นๆที่ bookmark URL เดียวกันด้วย. หรือดู Tag ยอดฮิต, ฯลฯ. อีกอย่างเก็บ bookmark ไว้บนเน็ตก็แบ่งให้คนอื่นดูได้ด้วย.

ตอนที่สมัครสมาชิกจะมี bookmarklet สองตัวคือ "my del.icio.us" กับ "Post to del.icio.us" ให้. ก็ใช้เมาส์ลากเข้าไปใส่ใน Bookmark Toolbar ได้เลย. อันนี้สะดวกและให้ความรู้สึกเหมือนกับใช้ bookmark ของเบราเซอร์. สมมติว่าไปดูเว็บใดเว็บหนึ่งแล้วอยากจะ bookmark ก็กดที่ "Post to del.icio.us" แล้ว URL ที่ดูอยู่รวมถึงหัวข้อของเว็บนั้นก็จะถูกกรอกให้ในหน้าบันทึก bookmark อัตโนมัติ. หลังจากกนั้นก็แค่เขียนคำอธิบายและ tag เท่านั้นเอง. เวลาจะดู bookmark ของตัวเองก็กด "my del.icio.us". ต

Search ด้วยคลิ้กขวาใน Firefox

ก่อนหน้านี้เวลาจะอ่าน web site แล้วเจอคีย์เวิร์ดหรือคำบางที่ต้องการหา, ผมมักจะเคยชินการทำขั้นตอนเหล่านี้
  • ใช้เมาส์ hightlight คำคำนั้น
  • Ctrl+c เพื่อ copy
  • Ctrl+t (เปิด tab)
  • Ctrl+Tab (เลื่อนไปที่ tab ตัวใหม่)
  • Ctrl+l (เลื่อนเคอร์เซอร์ไปที่ address bar)
  • พิมพ์คำว่า google
  • Ctrl+v
  • Enter
ไม่รู้ว่าทำไมไม่ชอบใช้ช่อง google search ที่ Firefox เตรียมไว้ให้. อาจจะเป็นเพราะว่า, รู้สึกว่าใช้แป้นพิมพ์แล้วสะดวก (ถนัด) กว่าการใช้เมาส์เอาไปจิ้มที่ช่อง search แล้วค้นหา.

มาวันนี้พึ่งรู้สึกตัวว่าวิธีต่อไปนี้น่าจะเวิร์กกว่า

  • ใช้เมาส์ hightlight คำที่ต้องการหา
  • คลิ้กขวา
  • เลือก "search web for"
แล้ว Firefox จะเปิด google (แล้วแต่ตั้งว่า default search engine เป็นอะไร) หาคำนั้นให้. จริงๆแล้วรู้ว่ามี "search web for" มาตั้งนานแล้วแต่พึ่งมาตระหนักวันนี้ว่าสะดวกดี.

คิดไว้ตั้งนานแล้วว่าอยากทำ search คลิ้กขวาแบบนี้ใช้กับ Longdo Dict แบบว่าคลิ้กขวาแล้วมีเมนู "Search Longdo Dict" แล้วไปขึ้นคำแปลใน side-bar. แต่ไม่มีโอกาสศึกษา Firefox extension ซะที.

วันพฤหัสบดีที่ 8 ธันวาคม พ.ศ. 2548

ติดตั้ง ruby แล้ว Hello world!


ว่าจะข้ามตรงนี้ไปเลยก็อดไม่ได้ที่จะเขียนให้. วันนี้เป็นเรื่องของการติดตั้ง ruby.

สำหรับคนที่ใช้ิลินุกซ์ตระกูล debian ก็ apt-get. พวกที่ใช้ fedora ก็ใช้ yum, พวกที่ใช้ gentoo ก็ emerge. หรือดาว์นโหลดรหัสต้นฉบับจาก ruby-1.8.3 จากเว็บไซด์ต้นตำหรับ. ถ้าจะใช้บนวินโดวส์ก็ลง cygwin หรือ RubyForge ก็ได้.

สมมติว่าเป็น debian เหมือนที่ผมใช้อยู่บน colinux ก็ขอดูก่อนแล้วกันว่ามี package อะไรบ้างที่เกี่ยวกับ ruby. ที่น่าสนใจก็มี

# apt-cache search ruby
...
eruby - Embedded Ruby Language
...
irb - Interactive Ruby (irb)
...
rails - MVC ruby based framework geared for web application development
rake - a ruby build program
rbbr - a browser for Ruby classes and documentation
...
ri - Ruby Interactive reference (ri)
...
ruby - An interpreter of object-oriented scripting language Ruby
ruby-elisp - Emacs-lisp ruby-mode for Ruby
...
ruby-gnome2 - GNOME-related bindings for the Ruby language
ruby-manual - Manual for the scripting language Ruby.
...
rubybook - the "Programming Ruby" book
...
vim-ruby - Vi IMproved, with ruby scripting support
...
อยากดูรายละเอียดอีกหน่อยก็ apt-cache show ตามด้วยชื่อแพ็กเกจเอง. แต่ที่แน่ๆต้อง install ขั้นต่ำคือ ruby กับ irb. ส่วนเอกสารหรือหนังสือจะ install ด้วยก็ดี.
# apt-get install ruby irb ri ruby-manual
เวลาสร้างสคริปต์, ก็เหมือนกับการสร้างเชลล์สคริปต์หรือสคริปต์อื่นๆทั่วไปในยูนิกซ์คือบรรทัดแรกเริ่มต้นด้วย shabang (sharp and bang) แล้วตามด้วย path ของโปรแกรม ruby. หลังจากนั้นก็เขียนสคริปต์ได้เลยเช่น
#!/usr/bin/ruby
print("Hello world!\n")
print "Hello world\n"
เสร็จแล้วก็ chmod ให้ไฟล์สคริปต์นั้น execute ได้
$ chmod +x hello.rb
$ ./hello.rb
Hello world!
Hello world!
สรุึปว่าอันนี้เป็น ruby สคริปต์อันแรกแล้วกัน. มันไม่ได้ทำอะไรมากแค่เรียกใช้ method ชื่อ print พิมพ์สายอักขระ Hello world! ออกทางเทอร์มินอลเท่านั้นเอง. expression แต่ละประโยคไม่ต้องมีเครื่องหมาย ; เหมือน perl หรือ C. จะเห็นได้ว่าเวลาเขียนสามารถละเครื่องหมายวงเล็บได้ด้วย. ทำให้สับสนไหม? ก็เลือกเอาสักอย่างแล้วกันว่าถนัดเขียนแบบไหน. คนออกแบบภาษาเขาอุตสาห์ยืดหยุ่นให้.

ที่นี้ ruby มันจะมีคำสั่ง irb ย่อมาจาก Interactive ruby เป็นตัวแปลภาษาเชิงโต้ตอบคล้ายๆกับเชลล์นั่นแหละ. ลองสั่งดู

$ irb
irb(main):001:0> 
main คือชื่อ method, 001 แสดงจำนวนบรรทัด, เลข 0 นั่นเป็นระดับความลึก (level) ของโค้ดเวลาเขียนพวก expression ที่ซับซ้อนเป็นชุด. เช่น
irb(main):012:0> if true
irb(main):013:1> print "Yes"
irb(main):014:1> end
Yes=> nil
irb(main):015:0>
จะเห็นว่าพวกอยู่ใน expression ของ if แล้วระดับจะเปลี่ยนจาก 0 เป็น 1 แล้วกลับมาเป็น 0 เหมือนเดิมตอนจบ. ก็เลยได้เรียนรู้อีกอย่างว่าพวกที่เป็นบล็อกๆพวก if นี่จะจบด้วย end. คำว่า "if", "true", "end" พวกนี้เรียกว่า Reserved words ได้แก่
        BEGIN    class    ensure   nil      self     when
        END      def      false    not      super    while
        alias    defined  for      or       then     yield
        and      do       if       redo     true
        begin    else     in       rescue   undef
        break    elsif    module   retry    unless
        case     end      next     return   until
คำพวกนี้เอามาสร้างเป็นชื่อตัวแปรหรืออะไรทำนองนี้ไม่ได้. อ่านในช่วง syntax เพิ่มเติม

ลองกลับมาดูสคริปต์ Hello world! อีกทีหนึ่ง. จะเห็นว่า print มันก็เหมือนกับฟังก์ชัน print ใน perl. แต่จริงๆแล้วมันเหมือนกัน. ruby เป็นภาษาแบบ object oriented แต่ถ้าเขียน print แบบนี้มันก็ไม่ใช่ object oriented สิ. ในแนวคิดของ object oriented มันต้องมี receiver ที่คอยรับ message ซึ่งจริงๆแล้ว print เป็น message ที่ส่งให้กับ receiver ที่พิเศษที่เรียกว่า self (ใน java เทียบเท่ากับ this). ถ้าจะเขียนเต็มยศต้องเป็น

self.print( "Hello world!\n")
คือมี self เป็น receiver. แต่อันนี้จะมี error, ruby ไม่อนุญาตให้ใช้ print แบบนี้. ใน ruby เรียก method ที่ไม่ต้องระบุ receiver (เรียกใช้เหมือนฟังก์ชันในภาษาอื่นๆ)เช่น method print เหล่านี้ว่า "private method". ลองดูใน irb ก็ได้
irb(main):001:0> self.print "He\n" 
NoMethodError: private method `print' called for main:Object
        from (irb):1
irb(main):002:0>
irb มันบอกว่า "private method `print' called for main:Object".

ก่อนจากกัน. ความรู้หนึ่งที่ไปอ่านจาก why’s (poignant) guide to ruby มาคือ irb นี่มันทำ command line completion ได้.

$ irb -r irb/completion
irb(main):007:0> Kernel::  กด tab สองครั้ง
...
Kernel::Array                       Kernel::loop
Kernel::Float                       Kernel::method
Kernel::Integer                     Kernel::method_defined?
Kernel::String                      Kernel::method_missing
Kernel::__id__                      Kernel::methods
Kernel::__send__                    Kernel::module_eval
Kernel::`                           Kernel::name
...
irb ก็จะแสดงพวก private method ให้ดูด้วย (ใช่ private method ทั้งหมดหรือไม่ ไม่แน่ใจ).

วันพุธที่ 7 ธันวาคม พ.ศ. 2548

ติว Ruby ด้วย Ajax

เจอเว็บไซด์ดีๆจากเว็บ blog ของคนญี่ปุ่นมาอีกที. เป็นเว็บไซด์ที่ใช้ Ajax มาทำ tutorial ภาษา ruby. ได้เรียนทั้ง ruby และทึ่งใน Ajax ด้วยในคราวเดียวกัน.

Ruby มันไม่ interactive คือรันคำสั่ง ruby ไปแล้วไม่มีพร้อมไม่มีอะไร. ไม่เหมือนกับ python ที่รันแบบ interactive ได้ด้วย. ถ้าจะใช้ ruby แบบ irb (interactive ruby).

หนังสือที่ลิงก์อยู่ที่เว็บ Try ruby ก็ดีนะ.

กระแส Ruby

เห็นคุณ bact's กับลังใช้ ruby เลยอยากปลุกกระแสบ้างโดยมาเรียน Ruby กันเถอะ. วันนี้เอาเรื่องคุณสมบัติของ ruby ก่อนแล้วกัน.
  • ruby เป็นโปรแกรมแปลภาษา (intepreter)
    ruby เป็นพวกเดียวกับ bash, awk, perl, python ฯลฯ ในแง่ที่ว่าเป็นโปรแกรมแปลภาษา. โปรแกรมภาษาพวกนี้เหมาะสำหรับเขียนสคริปต์เพราะการสร้างโปรแกรมด้วยตัวแปลภาษาพวกนี้ทำได้เร็ว, ไม่ยุ่งยากเมื่อเทียบกับภาษาคอมพิวเตอร์ที่ต้องคอมไพล์. สรุปง่ายๆคือใช้ง่ายและทำอะไรได้หลายอย่างด้วยการเขียนโค้ดสั้นๆ.
  • เป็นภาษาแบบ object oriented
    ruby เป็นภาษาแบบ object oriented โดยกำเนิด. นาย Matsumoto Yukihiro ซึ่งเป็นคนสร้างภาษา ruby เขาตั้งใจตั้งแต่แรกออกแบบให้ ruby เป็นภาษาแบบ object oriented. ข้อมูลหรือค่าทุกอย่างเป็น object หมด. สร้าง class ได้, inherit คลาสได้. บางครั้งมีการซ่อนรูป, ใช้แล้วเหมือนไม่ได้ใช้ภาษา object oriented เช่น
    print("Hello world\n")
    
    ดูแล้วเหมือนกับสั่งฟังก์ชั่นที่ชื่อ print มากกว่า เพราะถ้าเป็น object oriented แล้วต้องมี instance รับ message (method) อยู่.
  • สามารถ port ใช้ได้หลายแพลตฟอร์ม
    จะใช้กับ Linux หรือ Windows หรือแพลตฟอร์มอื่นๆก็ได้. ตัว ruby เองเขียนด้วยภาษา C ไม่ได้ใช้ไลบรารีพิเศษอะไร.
  • ควบคุมหน่วยความจำอัตโนมัติ
    ไม่ต้องไปกังวลเรื่องการจองการใช้หน่วยความจำเหมือนภาษา C. มีตัว garbage collection ให้.
  • มีพวก exception handling
    อิทธิพลจาก Java? ภาษาใหม่ก็มีกันทั้งนั้นรวมถึง ruby ด้วย.
  • ไม่มีประเภทของตัวแปร
    ตัวแปรต่างๆที่ใช้ไม่มีประเภท (type) ทำให้ใช้สะดวก (ไม่อยากใช้คำว่าใช้ง่าย)
  • ไม่ต้องประกาศตัวแปร
    อยู่สร้างตัวแปรขึ้นมาใช้ได้เลยแต่มีแบบรูปดังนี้คือ
    • foo local variable (ขึ้นต้นด้วยตัวเล็ก)
    • $foo global variable (ขึ้นต้นด้วย $)
    • @foo instance varible (ขึ้นต้นด้วย @)
    • Foo constant (ขึ้นต้นด้วยตัวใหญ่)
    ดูแล้วนึกถึงตอนเรียน perl ใหม่ๆในอดีต.... แต่ผมว่า concept ดีนะ, คือดูแล้วรู้เลยว่ามันตัวแปรไหนเป็นแบบใด
  • ไวยกรณ์เป็นแบบ expression
    พูดถึง expression แล้วนึกถึงภาษา lisp. เพราะ lisp มันเป็น expression. เขาบอกไว้ว่าถ้าเป็นภาษา C เขียนโค้ดดังต่อไปนี้แล้วจะมี error.
    result = if (cond) {process(val); } else {0;}
    
    เพราะว่าอันนี้มันเป็นไวยกรณ์ if (if statement). แต่ถ้าเป็น ruby, มันเป็น expression ทำให้เขียนแบบนี้ได้
    result = if cond then process(val) else nil end
    
    พูดง่ายๆว่าเหมือนกับ if มีอาร์กิวเมนต์หลายๆตัวเรียงต่อกันได้. if ในที่นี้ไม่ใช้ไวยกรณ์. หลายคนรู้สึกเหมือนกันว่า ruby มันคล้าย lisp.
  • มี iterator
    ไม่ค่อยรู้มากเกี่ยวกับเรื่องนี้ขอผ่าน. คล้ายกับ Iterator ใน STL ของ C++ แต่ใน ruby จะบอกว่าเหมือนกันหมดก็ไม่ได้.
  • เขียนไลบรารีของ ruby ด้วย C ได้
    อันนี้ผมว่าจำเป็นนะ สะดวกดี (บางครั้ง).
  • มี thread
    เขียนโปรแกรมแบบใช้ thread ได้.
  • มีไลบรารีให้ใช้เยอะ
    จะได้เขียนโปรแกรมทำอะไรได้สะดวกๆ.
สรุปว่าเป็นภาษาที่ออกแบบมาดี, object oriented, เป็นตัวแปลภาษา, จับสิ่งดีๆของภาษาต่างมายำ, และบวกอะไรที่นอกเหนือจากนั้น (เช่นให้ method return ค่าหลายค่าได้). น่าใช้ครับ.

Reference: