ผมมี def อันนึงที่ถูกบังคับให้รับ hash เข้ามา
def computer(com) cpu = com[:cpu] ram = com[:ram] fan = com[:fan] ... end
มีทางอื่นทึ่จะแปลง hash มาเป็น local variable หรือเปล่าครับ
ผมลองไล่ดูคำสั่ง render เพราะน่าจะทำคล้ายกับที่ต้องการ
render :partial => "partial" :locals => {:local => "local"}
ไปเจอแบบนี้ครับ
# File action_controller/base.rb, line 832 def render(options = nil, &block) #:doc: raise DoubleRenderError, "Can only render or redirect once per action" if performed? if options.nil? return render_for_file(default_template_name, nil, true) else .... elsif partial = options[:partial] partial = default_template_name if partial == true add_variables_to_assigns if collection = options[:collection] render_for_text( @template.send!(:render_partial_collection, partial, collection, options[:spacer_template], options[:locals]), options[:status] ) else render_for_text( @template.send!(:render_partial, partial, ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals]), options[:status] ) end elsif options[:update] .... end
คิดว่ามันเข้ามาที่ render_for_text อันที่สอง แต่ผมหา render_for_text ไม่เจอ :'( ต้องไปหาใน http://noobkit.com
แต่คำตอบของผมน่าจะอยู่ใน ObjectWrapper มากกว่าเลยลองตามไปดู น่าจะอยู่แถวนี้ C:\ruby\lib\ruby\gems\1.8\gems\actionpack-2.0.2\lib\action_view\base.rb
เห็นแล้วเป็นลม + ตกใจ
class ObjectWrapper < Struct.new(:value) #:nodoc: end
เจอ #:nodoc: แถมไม่มีคำสั้งอยู่ใน class นี้ซักบรรทัดเดียว คงต้องตามไปดูที่ Struct ... ผมลองตามหาดูรู้แค่ว่าเป็น Standard lib แต่ไม่รู้มันอยู่ไหน :'(
มันมีวิธีอะไรที่จะเอาค่าใน hash ออกมาเป็น local variable บ้างครับ
กระทู้เก่าๆ จะย้ายตามไปในภายหลัง ตอนนี้ปิดการโพสต์กระทู้ไว้ เหลือไว้เฉพาะอ้างอิงเท่านั้น
เวลาไล่ code ลึกๆอย่างนี้ , grep -R นี่ขาดไม่ได้เลย
ตัว method จริงๆ ที่เป็นคนแปลง Hash ให้เป็น local variables ก็คือ
method "create_template_source" ใน action_view/base.rb
คำสั่ง delegate_compile จะทำหน้าที่ compile template โดยมันจะดูชนิดของ template ด้วย
เช่น .rhtml ก็ให้ ERB เป็นคน compile
ผลลัพท์ที่ได้ ก็จะเก็บไว้ในตัวแปร body
วิธีการ compile ของ ERB มันจะไปใช้สั่งคำสั่งประมาณนี้
จากนั้น มันก็จะ iterate เจ้า Hash (locals variable) ของเรา เพื่อสร้าง assignment statement
สุดท้าย มันก็จะ return (string) code ที่ทำหน้าที่ render partial นั้นๆให้เรา
code ที่ได้จะถูก compile ด้วยคำสั่ง module_eval อีกที
ตัวที่น่าสนใจ ก็คือ definition ของ CompiledTemplates (อยู่ใน base.rb เหมือนกัน)
ตัว CompiledTemplates เป็นแค่ Module เปล่าๆ และถูก include ไว้ใน base.rb
เท่าที่ค้นคว้าดู ใน ruby เราไม่สามารถ dynamic create local variables ได้นะ (create ผ่าน eval ได้ แต่เวลา access ก็ต้อง access ผ่าน eval ด้วยเหมือนกัน)
มีทางอ้อมทางอื่นเช่น dynamic create getter method แบบนี้
ถ้าผมลองเลียนแบบดู น่าจะเป็นแบบนี้
สมเป็นภาษา script เท่หลายๆ
ของ apirak, run แล้วไม่ error หรือ
ที่บรรทัด
puts cpu if cpu
ของผมมันจะฟ้อง error
เท่าที่ผมทดลอง มันดูเหมือนว่า ตอนที่ compile, คำสั่ง puts มัน binding กับ variable ที่ชื่อ cpu ไปเรียบร้อยแล้ว, การที่เราสั่ง eval ("cpu=xx") ไม่มีผลต่อ ตัวแปร cpu ใน puts
ก็อย่างที่พี่อธิบายไว้ คงต้อง access ผ่าน eval ด้วยเหมือนกัน
พลาดเลย :p ผมดันทดลองใน irb น่ะครับ คิดว่าคงเคยเรียกใช้ตัวแปร cpu มาก่อนหน้านี้ พอมาเจอ cup ใน eval มันเลยจำได้ไม่หายไปกัน eval
แบบนี้ถ้าต้องการใช้ก็ต้องประกาศขึ้นมาล่วงหน้า :( มีทาง eval แล้วมันออกมาข้างนอกหรือเปล่าครับ