Keyword Argument ใน Ruby 3
ไม่ว่าจะใช้ภาษาอะไรในการพัฒนาโปรแกรม เมื่อมีอัพเดตเวอร์ชันที่เป็นเมเจอร์เกิดขึ้นใหม่ จะมีการเปลี่ยนแปลงที่ส่งผลกระทบต่อโค้ดเก่าไม่มากก็น้อย ซึ่งในส่วนของ Ruby เวอร์ชัน 3 ก็เช่นกัน โดยในบทความนี้จะกล่าวถึงผลกระทบที่เกิดขึ้นกับการใช้งาน keyword argument เพราะผมเพิ่งจะโดนเข้าไปเนื่องจากการไมเกรตโปรเจ็คจาก Ruby เวอร์ชัน 2 ไปเป็นเวอร์ชัน 3 นั้นเอง
ก่อนอื่นต้องทำความเข้าใจกันก่อนว่าใน Ruby 2 เราจะใช้ keyword argument กันอย่างไร
## Ruby 2.7
def foo(name: "default")
puts name
end
# foo -> "default"
# foo("karn") -> "karn"
def foo(kwargs = {})
puts kwargs
end
# foo -> {}
# foo(name: "karn", value: 3) -> {:name=>"karn", :value=>3}
# foo({ name: "karn", value: 3 }) -> {:name=>"karn", :value=>3}
def foo(**kwargs)
puts kwargs
end
# foo -> {}
# foo(name: "karn", value: 3) -> {:name=>"karn", :value=>3}
โดยรูปแบบของการใช้งาน keyword argument จะเป็นดังตัวอย่างโค้ดข้างต้นคือ
- นิยามโดยใช้ keyword แบบตรงไปตรงมา ซึ่งเราสามารถกำหนดเป็น required หรือ optional ก็ได้
- นิยามผ่าน hash โดยใน Ruby 2 จะมอง Hash ที่ถูกส่งมาเป็น keyword argument
- นิยามโดยใช้ ** (double splat)
ใน Ruby 3 รูปแบบของ keyword argument จะถูกแยกออกจาก postional argument จึงทำให้เหลือ 2 รูปแบบในการเรียกใช้งาน keyword argument ซึ่งก็คือ def foo(name: "default"); end
และ def foo(**kwargs); end
ส่วนการเรียกใช้งาน def foo(kwargs = {})
ซึ่งรับค่าเป็น Hash จะไม่มองว่าเป็น keyword argument อีกต่อไป และโค้ดที่เราใช้อยู่ใน Ruby 2 ก็ยังคงทำงานได้ปกติใน Ruby 3
แต่โค้ดที่จะพังทันทีก็คือโค้ดที่มีการเรียกใช้งาน def foo(**kwargs); end
พร้อมส่งผ่านพารามิเตอร์ที่เป็น Hash เข้าไป โดยจะฟ้องข้อผิดพลาดที่ชื่อ ArgumentError
ขึ้นมา
## Ruby 3
def foo(**kwargs)
puts kwargs
end
foo({ name: "karn", value: 3 }) -> foo': wrong number of arguments (given 2, expected 1) (ArgumentError)
แน่นอนว่าโปรเจ็คของทีมมีการนิยามเมธอดที่เป็น keyword argument ดังโค้ดข้างต้น ดังนั้นเมื่อมีการอัพเดตไปใช้ Ruby เวอร์ชัน 3 เราต้องรีบมาทางแก้ไขปัญหาดังกล่าว ซึ่งสามารถทำได้ 2 วิธีในการเรียกใช้เมธอดคือ
-
ใส่
**
(double splat) ไว้ด้านหน้า{ }
foo(**{ name: "karn", value: 3 })
-
ถอดเอา
{ }
ออก
foo(name: "karn", value: 3)
เรียบร้อยเพียงเท่านี้เราก็แก้ปัญหาเรื่อง keyword argument ใน Ruby 3 ได้