Wednesday, June 28, 2006

Rails, Enhance Symbol

ใน revision 4455 มีการเพิ่ม method to_proc ใน class Symbol
ส่งผลให้เราสามารถทำแบบนี้
orders.collect(&:total)

ซึ่งถ้าเป็นแบบเดิมๆ เราจะต้องเขียนแบบนี้
orders.collect {|o| o.total}


เอาไป apply ได้อื้อเลย
orders.sum(&:total)

people.select(&:manager?).collect(&:salary)


ชอบ ruby+rails ตรงนี้แหล่ะ มันเปิดให้ใช้ความคิดสร้้างสรรค์ได้เต็มที่

Related link from Roti

Charles Reid

ผมชอบรูป Nude ที่ใช้สีน้ำนะ
Charles Reid @ Stremmel Gallery



Related link from Roti

Standpedia


Standpedia
ไม่รู้เห็นกันหรือยัง

เหมาะแก่การใช้ประกอบการถกเถียงเป็นอย่างยิ่ง
เส้นยึกยัก คือ คำค้าน (challenging Reason)
เส้นตรง คือ ความเห็น หรือข้อความสนับสนุน (Supporting Reason)

GotoKnow น่าเอาไปทำบ้างนะ

Related link from Roti

Erlang, ลองใช้ Mnesia

Mnesia คือ database ที่เขียนด้วย erlang เพื่อ erlang
เนื่องจากเขียนด้วย erlang ,ประเด็นปัญหาเรื่อง impedance mismatch
ระหว่าง data format ของ DBMS กับ data format ของ programming language
ก็เลยไม่มี (impedance mismatch ก็คือที่มาของ Oิbject relation mapping)
feature ที่ชอบก็คือ
  • Tables can be moved or replicated to several nodes to improve fault tolerance.
  • Table locations are transparent to the programmer.


โปรแกรม Mnesia นั้น bundle มาพร้อมกับ erlang เลย
สามารถใช้งานได้ทันที ไม่ต้องติดตั้งเพิ่มเติม

การสร้าง table ใน Mnesia เริ่มต้นด้วยการ define Record Datatype
ที่จะใช้เก็บข้อมูล
-record(employee,{emp_no, 
name,
salary,
sex,
phone,
room_no}).


การสร้าง table ก็ใช้คำสั่ง
init() ->
mnesia:create_table(employee,
[{attributes, record_info(fields, employee)}]).

เวลาจะ insert ก็ใช้คำสั่ง
insert(Emp_no, Name, Salary, Sex, Phone, Room_no) ->
insert(#employee{emp_no = Emp_no,
name = Name,
salary = Salary,
sex = Sex,
phone = Phone,
room_no = Room_no}).

insert(Emp) ->
Fun = fun() ->
mnesia:write(Emp)
end,
mnesia:transaction(Fun).

Note: #employee{key = value,...} เทียบได้กับ constructor ของ Record

เวลา select ก็มีอยู่ 2 แบบ
พวก select กับ read
ลองแบบ read ก่อน (read ทั้ง record)
get(Emp) ->
Fun = fun() ->
mnesia:read({employee, Emp})
end,
mnesia:transaction(Fun).

การใช้งาน ก็เช่น
30> dbtest:get(111).
{atomic,[{employee,111,pok,2000.00,male,xxxx,412}]}

Note: read คือการดึงข้อมูลโดยใช้ key, โดยมี assumption ว่า element แรกใน record เป็น key

ส่วน select ก็ใช้ดังนี้
all_males() ->
Fun = fun() ->
Male = #employee{sex = male, name = '$1', _ = '_'},
mnesia:select(employee, [{Male, [], ['$1']}])
end,
mnesia:transaction(Fun).

Note: $1 ใช้เป็นตัวเชื่อมระหว่าง record member ที่ต้องการนำมาแสดงผลใน result list

ส่วนการ update นั้นยุ่งขึ้นมานิดหนึ่ง
เพราะ variable ใน erlang assign แล้วห้ามแก้ (immutable)
raise(Eno, Raise) -> 
F = fun() ->
[E] = mnesia:read(employee, Eno, write),
Salary = E#employee.salary + Raise,
New = E#employee{salary = Salary},
mnesia:write(New)
end,
mnesia:transaction(F).

Related link from Roti

Tuesday, June 27, 2006

Kenichi Koshine


Kenichi Koshine

Related link from Roti

Monday, June 26, 2006

เก็บตก Rails

By our best estimates, over 90% of the 550 people at RailsConf 2006 are using Apple laptops

เขาเลยมีการแจก certificate ให้กับคนที่ไม่ใช้ apple (stand against the norm)


Ruby/Rails works for Kiosks Our kiosk project really impressed a lot of people. We designed it from top to bottom with all Ruby software on Gentoo Linux. Working in Ruby really helped the integration with USB devices such as bill validator and coin readers. The fancy UI was done entirely with Scriptaculous, running on a fullscreen-mode instance of Firefox.

Related link from Roti

playboy centerfold

ลองดูวิวัฒนาการของ photographs บน centerfold ใน playboy magazine
ตั้งแต่ปี 1960 - 1990
PlayboyDecades

Related link from Roti

Sunday, June 25, 2006

GotoKnow version ใหม่ implement ด้วย rails

ไม่ได้เข้า GotoKnow นานแล้ว
เห็นแว็บๆว่าเปลี่ยน version แต่ไม่ได้สังเกตอะไรเพิ่มเติม

วันนี้พึ่งรู้ว่าเปลี่ยนไปเป็น implement ด้วย Rails แล้ว
(ของเดิมใช้ python)
source code อยู่ที่ KnowledgeVolution.org
เลยถือโอกาสเข้าไป scan ดู code หน่อย
(อาจารย์ธวัชชัย ที่เป็นคนเขียน เขาเก่งอยู่ เพื่อจะได้ trick อะไรติดมือกลับมา)

  • plugin ที่ใช้ เห็นมี Exception Notifier Plugin
    ใช้สำหรับส่ง mail เตือน กรณีที่เกิด error ขึ้นใน app
  • deployment เห็นว่าใช้ capistrano ด้วย
  • ส่วน Localization ใช้ GetText ทำ
  • มี patch เรื่องเกี่่ยวกับ Date ใน http://knowledgevolution.org/browser/trunk/lib/overrides.rb
    ถ้าเราดูใน source file ของ ruby
    # === Doesn't depend on strftime
    #
    # This library doesn't use +strftime+. Especially #rfc2822 doesn't depend
    # on +strftime+ because:
    #
    # * %a and %b are locale sensitive
    #
    # Since they are locale sensitive, they may be replaced to
    # invalid weekday/month name in some locales.

    เห็นใน code ใช้วิธีแปะเดือน กับวัน จาก Constants Array ใน Date ทับลงไป
    โดย string ชุดนี้ถูก replace จาก application.rb (controller) บรรทัดที่ 33 ซึ่งใช้ gettext แปลงตาม locale อีกที
  • มีการใช้ rmagick ช่วย generate background image ตาม theme ด้วย
    generate_images.rb
  • ใช้ Rmagick generate รูปที่ใช้ถามเวลา comment เพื่อป้องกัน spam
    generate.rb
    โดย generate ไว้ตั้งแต่ต้นเลย เพื่อไม่ให้เสียเวลา generate ตอนที่ request วิ่งเข้ามา
  • changeset ล่าสุด เห็นมีการใช้ thread มา expire_fragment
  • ส่วนเรื่อง Testing เห็นมี unit test ที่ user model กับ mailer test
    (ผมก็เหมือนกัน ถ้า app มันตรงไปตรงมา บางที ก็ขี้เกียจ test
    แต่ก็พยายามหัดอยู่)

Note: source code เขาใช้ tab = 8 space ดูสะอาดตาดี

Related link from Roti

Erlang 101 ตอน 3

วันนี้จะลองเขียน Server Process ดูบ้าง
เริ่มต้นง่ายๆที่ Echo Server

เริ่มต้นด้วยการประกาศ module
-module(echo).
-export([start/0,loop/1]).

function start จะทำหน้าที่ spawn process ขึ้นมาใหม่
แล้วทำการ register process เข้ากับชื่อ "echo"
(การ register จะช่วยให้ client สามารถส่ง message มาให้ server ได้ง่ายขึ้น
แทนที่จะต้องรู้ว่า server มี process id เป็นอะไร
ก็ให้ระบุชื่อ server แทน)
start() ->
register(echo,
spawn(echo, loop, [nil])).

ในส่วนของ function loop ก็คือ loop ที่เราจะรอรับ message จาก client
ให้สังเกตว่ากรณี message ประเภท echo พอตอบ message กลับไปแล้ว
จะมีการ recursive เรียกใช้ loop อีกครั้ง
ส่วนกรณี stop จะไม่มีการเรียก loop ซ้ำ ซึ่งก็หมายความ process จะ terminate
loop(State) ->
receive
{From, {echo, Msg}} ->
From ! {ok, Msg},
loop(State);
{From, {stop}} ->
true
end.

ใน echo server เราสนใจ message อยู่ 2 แบบคือ
  • {From, {echo, Msg}}
    From ก็คือ process id ของ client
    จะได้ส่งข้อมูลกลับไปให้ client ได้
    echo ขึ้นต้นด้วยตัวเล็ก แสดงว่ามันเป็น atom หรือ Constants แบบหนึ่ง
    Msg คือ ข้อความที่ user ส่งมา
  • {From, {stop}}


เวลาใช้งาน ก็จะทำดังนี้
Erlang (BEAM) emulator version 5.4.13 [source] [hipe]

Eshell V5.4.13 (abort with ^G)
1> c("/Users/pphetra/projects/erlang/echo2/src/echo", [{outdir, "/Users/pphetra/projects/erlang/echo2/src/"}]).
/Users/pphetra/projects/erlang/echo2/src/echo.erl:13: Warning: variable 'From' is unused
{ok,echo}
2> echo:start().
true
3> echo ! {self(), {echo, "helloworld"}}.
{<0.30.0>,{echo,"helloworld"}}
4> echo ! {self(), {stop}}.
{<0.30.0>,{stop}}
5>

  • <0.30.0> คือเลข pid ของ echo server
  • self() คือ function ที่ return pid ของ process ที่เรียกคำสั่งนี้


ใน erlang มี concept ที่เรียกว่า Behavior
ซึ่งก็คือการดึงเอา pattern ที่ซ้ำๆกันออกมาเป็น code ต่างหาก
แล้วเปิดให้เราเขียน code ที่ implement behavior เหล่านี้ได้

erlang เตรียม behavior ของ server ไว้แล้ว
โดยมีชื่อว่า gen_server
ลองดูว่า echo server implement behavior นี้แล้ว code จะเปลี่ยนโฉมไปยังไงบ้าง

เริ่มต้นด้วย การประกาศ behavior(gen_server)
-module(echo).
-behavior(gen_server).
-export([handle_call/3,start/0,init/1,terminate/2]).

gen_server บังคับให้เรา implement callback function ที่ชื่อ init
ซึ่งกรณีของเรา ไม่ได้มีการ allocate resources อะไร
ก็เลยแค่ return ok พร้อม state [] ว่างๆกลับไป

start() ->
gen_server:start_link({local, echo}, echo, [], []).

init(_Arg) ->
{ok, []}.

ตัว handle_call คือ callback ที่ใช้รองรับ syncronous call (พวกต้องการรับค่ากลับ)
จะเห็นว่าเรา return กลับเป็น {reply, Msg}
ซึ่ง gen_server จะส่ง message กลับไปให้เอง
ส่วน function terminate ก็เป็น callback ที่ gen_server call
เมื่อพบ message {stop, normal, ..}
ซึ่งในการทำงานจริง ตรงนี้จะเป็นการคืนค่าทรัพยากรที่จองไว้ กลับคืนสู่ระบบ
handle_call(Msg, _From, State) ->
case Msg of
{echo, Text} ->
{reply, {ok, Text}, State};
{stop} ->
{stop, normal, State}
end.

terminate(normal, _) ->
ok.


ดูแล้ว มันเทอะทะขึ้นอีกนิด แต่ว่าผลประโยชน์ที่ได้จากการ implement gen_server behavior ก็คือ
เราสามารถใช้ pattern supervisor มาช่วย monitor server เรา
ถ้ามีการตาย หรือ terminate แบบผิดธรรมชาติ เช่นมี bug หรือ IO มีปัญหา
supervisor สามารถ restart server ให้เราอัติโนมัติได้
ซึ่งช่วยเพิ่ม reliability ให้กับระบบเรา

Related link from Roti