Ruby :: Substituting variables into an existing string
Posted by PunNeng, Thu Jan 25 11:23:00 UTC 2007
ถ้าเราต้องการจะสร้าง string โดยที่ต้องการใส่ตัวแปรลงไปด้วยในก้อน string น้ันๆ อาจจะทำได้จากการใช้ #{} แทรกเข้าไปใน string เช่น
"#{my_variable}"
|
ถ้าต้องการเปลี่ยน ก็เพียงแค่เปลี่ยนค่า my_variable เช่น my_variable = "new string or expression" หรือว่า my_variable = any_variable จริงๆ แล้ว เราไม่ต้องมาทำการเซ็ตค่าให้ my_variable ตลอด ใน ruby มี 2 วิธี ที่คอยจัดการให้ของพวกนี้ง่ายขึ้่น คือ แบบ printf และ ERB template มาดูทางด้าน printf ตามแนวของ C หรือ python ก่อน
template = 'Oceania has always been at war with %s.%' template % 'Eurasia' # => "Oceania has always been at war with Eurasia." template % 'Eastasia' # => "Oceania has always been at war with Eastasia." 'To 2 decimal places: %.2f' % Math::PI # => "To 2 decimal places: 3.14" 'Zero-padded: %.5d' % Math::PI # => "Zero-padded: 00003" |
มาดูทางด้าน ERB บ้าง
มันก็มีลักษณะคล้ายๆ กับ php หรือ jsp นั่นแหละ เพียงแต่เปลี่ยนเป็น code ของ ruby เท่านั้น เช่น php จะใช้ <?php //php code ?> ฝั่ง ruby จะเป็น <% #ruby code %> ซึ่งมันอาจจะเป็น expression หรือ ตัวแปร ก็ได้ มาดูตัวอย่าง
require 'erb' template = ERB.new %q{Chunky <= food %>!} food = "bacon" template.result(binding) # => "Chunky bacon!" food = "peanut butter" template.result(binding) # = > "Chunky peanut butter!" |
ตัว %q{} ทำหน้าที่สร้าง single quote string เราสามารถใช้ %Q{} ในการสร้าง double quote string ด้วยเช่นกัน
ถ้าเราไม่ได้รันอยู่บน irb เราสามารถใช้ template.result ได้เลย ข้ามการเรียก Kernel#binding ไปได้เลย
ตัว .rhtml ของ rails ก็ใช้ตัว ERB นี่แหละครับ ในการแสดงผล
นอกจากตัวอย่างข้างต้น ใน ERB ยังสามารถใช้ loops หรือ conditions ได้อีกด้วย ลักษณะเหมือน serverside script ทั่วๆ ไป โดยมีข้อสังเกตนิดนึงคือ <% %> ไว้สำหรับ expression หรือ loop หรือ conditions ต่างๆ นานา มันจะไม่แสดง(print) ออกมา แต่ถ้าเราใช้ <%= %> มันจะเป็นการแสดงสิ่งที่อยู่ข้างในออกมา
ยังมีทางเลือกอื่นอืีกครับ จากอันนี้ เรารู้ว่าถ้าใช้ single quote เจ้าตัว #{} มันจะใช้ไ่ม่ได้ เราสามารถใช้ eval ช่วยได้
class String def substitute(binding=TOPLEVEL_BINDING) eval(%{"#{self}"}, binding) # %{} <=> here string end end template = %q{Chunky %{food}!} # => "Chunky \#{food}!" # %q{} <=> single quote food = 'bacon' template.substitue(binding) # => "Chunky bacon!" food = 'peanut butter' template.substitue(binding) # => "Chunky peanut butter!" |
การใช้ eval นี้ต้องระวังหน่อย เราอาจจะเจอการฉีด(injection) อะไรบางอย่างเข้ามาใจ code ของเราโดยตรง อาจจะเป็นช่องว่างในการเปิดให้ชาวบ้านมาโจมตีได้ เช่น อาจจะโดนฉีด command มา มันก็จะทำการรัน command นั้นๆ เช่น
eval("system('ls')",binding) |
ถ้าอยู่ในรูปแบบนี้ละก็ เสร็จแน่ ตัว system มันเป็น method นึงของคลาส kernel มันจะทำการรันคำสั่ง ls ตามที่เราใส่เข้าไป งืมๆๆ แต่ตัวอย่างที่่ให้มา ถูกจัดการเรียบร้อยแล้ว ด้วยการห่อด้วย single quote อีกทีนึง ตอนที่เราสั่ง food = '#{system("ls")}' มันจะมองให้ถูกเป็นแค่ string เท่านั้น ถ้าเปลี่ยนเป็น double quote ละก็ เป็นเรื่อง ลองดูคำสั่งนี้
template = %q{#{food}!} food = '#{system("ls")}' puts template.substitute(binding) # Chunky #{system("ls")}! |
มันจะถูกมองเป็น string เท่านั้น ลองเปลี่ยนเป็น food = "#{system("ls")}" นะครับ
แก้ไขล่าสุด วันที่ 24 กรกฏาคม 2550 เวลา 22.49 น.