ช่วง 2 วันนี้เมามันอยู่กับการเขียน Ruby
โดยพยายามจะเขียนโปรแกรมที่ generate Graph แสดงภาพรวมการ
ทำงานของ User ในระบบ
ตอนนี้เริ่มเขียน version ที่ 2 แล้ว หลังจากปล้ำให้ version แรกทำงานได้แล้ว
ใน version ใหม่นี้ สิ่งที่พยายามจะทำ ก็คือการพยายามใช้ feature
ของ Ruby ให้มากขึ้น (แทนที่จะเขียนโดยใช้กรอบความคิดที่เคยชิน
จากการเขียน Java)
feature หนึ่งที่พยายามจะดู หรือหาว่า จะนำมาใช้อย่างไรก็คือ
การ extend class
ตัวอย่างที่เจอแล้วรู้สึกชอบก็คือ ใน module
RMagick(ซึ่งเป็น api ที่ใช้ในการ manipulate image)
Class RVG (Ruby Vector Graphic) ใน RMagic
จะมี constructor ที่รับตัวเลข 2 ตัว เพื่อใช้
ในการกำหนด ขนาดของ image ที่จะสร้างขึ้น
rvg = RVG.new(width,height)
คำถามของคนที่จะใช้ api นี้ก็คือ เราจะ pass ค่าอะไรเข้าไป, และเป็นหน่วยอะไร
เช่นถ้าผมต้องการรูปขนาด 4x5 นิ้ว ผมควรจะใช้ width, height เป็นเท่าไรดี
และถ้ามีหลายๆหน่วย api ควรจะ implement Unit Converter Function
นี้ไว้ที่ไหนดี
RVG เลือกใช้วิธีที่ดูเข้าทีมาก เขาเปิดโอกาสให้เราเขียนได้ดังนี้
rvg1 = RVG.new(4.in, 5.in)
rvg2 = RVG.new(30.cm, 15.5.cm)
ที่นี้ ruby จะเข้าใจ syntax นี้อย่างไร
ruby จะมองว่า 4.in ก็คือ การเรียกใช้ method ที่ชื่อ
in
ของ Object Fixnum (4 ก็คือ Fixnum Object)
ส่วน 15.5.cm ก็คือ การเรียกใช้ method
cm
ของ
Float Object นั้น
ประเด็นก็คือ method
in
หรือ
cm
มันไม่ได้ build-in มาใน Fixnum หรือ Float ตั้งแต่ต้น
แต่ ruby เปิดโอกาสให้เรา modify class definition ได้
โดยในกรณีนี้
RMagic กำหนด syntax มาให้เราเรียกใช้ดังนี้
RVG::dpi = 72
ถ้ามีการกำหนดค่านี้เมื่อไร RVG จะเข้าไป add method ใน
Fixnum กับ Float Class ให้เราทันที โดยอาศัยข้อมูล dpi ที่กำหนด
เป็นค่าที่ใช้ในการ convert
ถ้าตามไปดูใน source code ของ RVG จะเห็นวิธีที่เขาเขียน
def dpi=(n)
if !defined?(@dpi)
[Float, Fixnum].each do |c|
c.class_eval do
def px
self
end
def in
self * ::Magick::RVG.dpi
end
def mm
self * ::Magick::RVG.dpi / 25.4
end
def cm
self * ::Magick::RVG.dpi / 2.54
end
.....
จะเห็นว่ามีการ iterate Float class กับ Fixnum class
เพื่อเพิ่ม method เข้าไป (ผ่านทางคำสั่ง class_eval)
ดูแล้วชอบจริงๆ