หากคุณไม่เคยใช้การปรับแต่งมาก่อน คุณอาจจะแปลกใจ คุณอาจเคยได้ยินว่ามีการแนะนำการปรับแต่งเพื่อแทนที่การปะลิง ดังนั้นคุณอาจคาดหวังว่าคุณจะสามารถใช้งานบางอย่างเช่น hours
. ของ ActiveSupport วิธีการ:
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)
หากคุณรันโค้ดด้านบน คุณจะพบว่ามันไม่ได้ผล แล้วให้อะไร?
เช่นเดียวกับแนวคิดที่ยอดเยี่ยมอื่นๆ มากมาย แนวคิดดั้งเดิมของการปรับแต่งต้องได้รับการปรับแต่งเพื่อให้ทำงานกับความเป็นจริงที่เยือกเย็นได้
พฤติกรรมที่น่าประหลาดใจในโค้ดที่เราดูด้านบนนี้เกิดจากการปรับแต่งอย่างใดอย่างหนึ่งเหล่านี้ โดยเฉพาะอย่างยิ่ง กฎที่ระบุว่าการปรับแต่งมีการกำหนดขอบเขตคำศัพท์
การกำหนดขอบเขตคำศัพท์คืออะไร
เมื่อเราพูดว่าบางสิ่งเป็นศัพท์เฉพาะ นั่นหมายความว่าเกี่ยวข้องกับข้อความ — โค้ดบนหน้าจอซึ่งต่างจากความหมายของโค้ดนั้น
หากมีการกำหนดขอบเขตคำศัพท์สองบรรทัด ก็หมายความว่าเกิดขึ้นภายในบล็อกโค้ดเดียวกัน โดยไม่คำนึงว่าบล็อกโค้ดนั้นจะประเมินอะไร
ดูตัวอย่างง่ายกว่าพูดมาก:
class B
# x and y share the same lexical scope
x = 1
y = 1
end
class B
# z has a different lexical scope from x and y, even though it's in the same class.
z = 3
end
การปรับแต่งมีการกำหนดขอบเขตคำศัพท์
เมื่อเราใช้การปรับแต่งด้วยคำสำคัญที่ใช้ การปรับแต่งจะปรากฏเฉพาะภายในขอบเขตคำศัพท์เท่านั้น
นี่คือตัวอย่างที่ฉันหมายถึง:
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
เมธอดมีการเข้าถึงการปรับแต่ง เพราะมีเพียงการใช้ขอบเขตคำศัพท์ร่วมกับ using
คำสั่ง
นี่อาจดูแปลกๆ นิดหน่อย เพราะเกือบทุกอย่างใน Ruby นั้นมีการกำหนดขอบเขตแบบไดนามิก เมื่อคุณเพิ่มเมธอดในคลาส เมธอดจะอยู่ที่นั่นเมื่อคุณออกจากนิยามคลาส แต่นั่นไม่ใช่วิธีการกลั่นกรอง
นี่เป็นผลที่ตามมาจำนวนหนึ่งที่อาจไม่ชัดเจนในตอนแรก
คุณไม่สามารถเรียกวิธีการปรับแต่งแบบไดนามิกได้
เนื่องจาก send
ไม่ได้กำหนดเมธอดภายในบล็อคโค้ดเดียวกันกับที่ใช้คำสั่งของคุณ แต่จะไม่เห็นการปรับแต่ง
วิธีนี้ใช้ไม่ได้ผล:
class MyApp
using TimeExtension
def index
1.send(:hours)
end
end
คุณไม่สามารถสืบค้นการมีอยู่ของวิธีการปรับแต่งได้
respond_to?
เมธอดไม่ได้อยู่ในบล็อคโค้ดเดียวกัน ดังนั้นจึงใช้งานไม่ได้ด้วยเหตุผลเดียวกันกับที่send
วิธีการไม่ได้
class MyApp
using TimeExtension
def index
1.respond_to?(:hours)
end
end
บทสรุป
ฉันหวังว่าสิ่งนี้จะช่วยขจัดความสับสนบางอย่างที่ฉันเห็นผู้คนมีเกี่ยวกับการปรับแต่ง เป็นคุณสมบัติที่มีประโยชน์อย่างแน่นอนของ Ruby แต่ถ้าคุณไม่เคยใช้มาก่อน มันอาจจะยุ่งยากเล็กน้อย