ไม่เคย用 refinements มาก่อน น่าประหลาดใจ คุณอาจได้ยิน refinements introduced เพื่อ replace monkey patching คาดว่า implement ActiveSupport hours method ได้:
module TimeExtension
refine Fixnum do
def hours
self * 60
end
end
end
class MyFramework
using TimeExtension
end
class MyApp < MyFramework
def index
1.hours
end
end
MyApp.new.index # undefined method `hours' for 1:Fixnum (NoMethodError)
รันโค้ดข้างบน จะพบว่าไม่ work ทำไม?
เหมือน great ideas หลายอย่าง original concept refinements tweak ให้ work กับความเป็นจริง
Surprising behavior ข้างบนมาจาก tweak หนึ่ง: rule ว่า refinements are lexically scoped
Lexical Scoping คืออะไร?
พูดว่า something is lexical หมายถึงเกี่ยวกับ text — โค้ดบนหน้าจอ ไม่ใช่ความหมายของโค้ด
สองบรรทัด lexically scoped หมายถึงเกิดใน code block เดียวกัน ไม่ว่าจะ evaluate เป็นอะไร
ตัวอย่างง่ายกว่าอธิบาย:
class B
# x และ y share same lexical scope
x = 1
y = 1
end
class B
# z lexical scope ต่างจาก x และ y แม้ในคลาสเดียวกัน
z = 3
end
Refinements are Lexically Scoped
Apply refinement ด้วย using keyword refinement visible เฉพาะ lexical scope
ตัวอย่างแสดง:
module TimeExtension
refine Fixnum do
def hours
self * 60
end
end
end
class MyApp
using TimeExtension
def index
1.hours
end
end
class MyApp
def show
2.hours
end
end
MyApp.new.show # undefined method `hour' for 1:Fixnum (NoMethodError)
แม้ index และ show อยู่ในคลาสเดียวกัน แค่ index เข้าถึง refinement ได้ เพราะแค่มัน share lexical scope กับ using statement
อาจแปลกเพราะ almost everything else ใน Ruby dynamically scoped เพิ่ม method ให้ class method อยู่ตอน exit class definition แต่ refinements ไม่ทำงานแบบนั้น
Consequences หลายอย่างไม่ชัดเจนตอนแรก
ไม่สามารถ Dynamically Invoke Refinement Method
เพราะ send method ไม่ได้ defined ใน code block เดียวกับ using statement มอง refinement ไม่เห็น
นี้ไม่ work:
class MyApp
using TimeExtension
def index
1.send(:hours)
end
end
ไม่สามารถ Query Existence of Refinement Method
respond_to? method ไม่อยู่ใน code block เดียวกัน ไม่ work เหมือน send
class MyApp
using TimeExtension
def index
1.respond_to?(:hours)
end
end
Conclusion
หวังช่วย clear up confusion เกี่ยว refinements พวกมัน potentially useful feature แต่ไม่เคย用มาก่อน tricky นิดหน่อย