Exceptions ในภาษา Ruby

ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับ Exception ในภาษา Ruby เราจะพูดถึงว่าข้อผิดพลาดคืออะไรและมันเกิดขึ้นได้อย่างไรในการเขียนโปรแกรม และการจัดการกับข้อผิดพลาดที่เกิดขึ้นเพื่อทำให้โปรแกรมยังคงสามารถทำงานต่อไปได้ และเรายังจะพูดถึงการออกแบบโปรแกรมให้มีข้อผิดพลาด้วย เมื่อมีบางอย่างไม่เป็นไปตามที่คาดหวัง นอกจากนี้ เรายังจะพูดถึงการสร้างคลาสข้อผิดพลาดของเราเอง โดยสืบทอดมาจากคลาส StandardError

Exception คืออะไร

Exception นั้นเป็นข้อผิดพลาดที่สามารถเกิดขึ้นได้ในขณะที่โปรแกรมกำลังทำงานบาอย่าง Exception นั้นไม่ได้เกิดจากการที่ไวยากรณ์ของภาษาไม่ถูกต้อง แต่มันเกิดจากโปรแกรมเมอร์สั่งให้มันเกิดขึ้นเมื่อโปรแกรมทำงานในสถานการณ์ที่ไม่พึงประสงค์บางอย่าง เมือเกิดข้อผิดพลาดขึ้นจะทำให้โปรแกรมหยุดทำงาน ดังนั้นเราจึงต้องจัดการกับข้อผิดพลาดดังกล่าวเพื่อให้โปรแกรมของเรายังคงสามารถทำงานต่อไปได้

นี่เป็นตัวอย่างของโค้ดที่สามารถทำให้เกิดข้อผิดพลาดขึ้นได้ในภาษา Ruby

puts 5 / 0
puts "Ruby" + 2020

ในโค้ดตัวอย่างเป็นคำสั่งที่จะทำให้เกิดข้อผิดพลาดขึ้น ในคำสั่งแรกจะทำให้เกิดข้อผิดพลาด ZeroDivisionError นั่นเป็นเพราะว่าในคอมพิวเตอร์เราไม่สามารถหารตัวเลขด้วยศูนย์ได้ และในคำสั่งต่อมาจะเกิดข้อผิดพลาด TypeError นั่นเป็นเพราะว่าเราไม่สามารถเชื่อมต่อตัวเลขกับ String ได้นั่นเอง ซึ่งข้อผิดพลาดเหล่านี้เกิดขึ้นโดยภาษา Ruby

การจัดการ Exception

เมื่อข้อผิดพลาดเกิดขึ้นแล้ว เราจะต้องจัดการกับข้อผิดพลาดเหล่านั้นเพื่อให้โปรแกรมยังคงสามารถทำงานต่อไปได้ ในภาษา Ruby นั้นเราสามารถใช้บล็อคคำสั่ง begin และ rescue สำหรับการจัดการข้อผิดพลาดได้ นี่เป็นตัวอย่าง

begin
    print "Enter first number: "
    a = gets.chomp.to_i
    print "Enter second number: "
    b = gets.chomp.to_i

    puts "#{a} / #{b} = #{a / b}"
rescue => e
    puts e.message
    puts "Divider must not be zero, please try again"
end

ในตัวอย่าง เป็นโปรแกรมหารตัวเลขโดยการรับค่าตัวเลขสองตัวจากคีย์บอร์ด และแสดงผลหารของตัวเลขทั้งสองออกทางหน้าจอ ในการหารตัวเลขนั้นสามารถทำให้เกิดข้อผิดพลาดขึ้นได้เมื่อตัวหารในตัวแปร b เป็น 0 เราใช้บล็อค begin เพื่อเขียนโค้ดที่อาจจะทำให้เกิดข้อผิดพลาดขึ้น

rescue
    puts e.message
    puts "Divider must not be zero, please try again"

หลังจากนั้นเราประกาศบล็อค rescue เพื่อตรวจจับข้อผิดพลาดที่อาจจะเกิดขึ้น กล่าวคือเมื่อเกิดข้อผิดพลาดขึ้น โปรแกรมจะย้ายมาทำงานในบล็อคของคำสั่ง rescue ทันที ดังนั้นภายในบล็อคนี้ เราสามารถจัดการข้อผิดพลาดในแบบที่เราต้องการได้ ในกรณีนี้ เราได้แจ้งผู้ใช้ว่าตัวหารที่กรอกเข้ามาต้องไม่เป็นศูนย์ และนี่เป็นวิธีที่เราจัดการกับข้อผิดพลาดดังกล่าว

divided by 0
Divider must not be zero, please try again

นี่เป็นผลลัพธ์การทำงานของโปรแกรม เมื่อเรากรอกตัวหารที่เป็นศูนย์โดยการตั้งใจทำให้เกิดข้อผิดพลาดขึ้น

ในบล็อคของคำสั่ง rescue คุณสามารถกำหนดอาร์กิวเมนต์ให้กับบล็อคได้ การทำเช่นนี้จะทำให้เราสามารถเข้าถึงออบเจ็คของข้อผิดพลาดเพื่อใช้ข้อมูลบางอย่างเกี่ยวกับข้อผิดพลาดได้ นี่เป็นตัวอย่าง

begin
    puts 1 / 0
rescue => exception
    puts exception.inspect
    puts exception.message
end

ในตัวอย่าง เป็นการกำหนดอาร์กิวเมนต์ให้กับบล็อคของคำสั่ง rescue นั่นจะทำให้เมื่อเกิดข้อผิดพลาดขึ้น เราจะสามารถเข้าถึงออบเจ็คของข้อผิดพลาดดังกล่าวผ่านตัวแปร exception ได้นั่นเอง ซึ่งออบเจ็คนี้มีเมธอดต่างๆ จากคลาส StandardError ที่เราสามารถเรียกใช้งานได้

#<ZeroDivisionError: divided by 0>
divided by 0

นี่เป็นผลลัพธ์การทำงานของโปรแกรม เราได้ตรวจสอบออบเจ็คของข้อผิดพลาดด้วยเมธอด inspect และดูคำอธิบายเกี่ยวกับข้อผิดพลาดด้วยเมธอด message ซึ่ง เมธอด message นั้นมีอยู่บนออบเจ็คข้อผิดพลาดที่ประเภท

ในการเขียนโปรแกรมนั้น อาจจะมีข้อผิดพลาดมากกว่าหนึ่งประเภทที่สามารถเกิดขึ้นได้ ดังนั้นในบางครั้งเราอาจจะต้องการจัดการข้อผิดพลาดแต่ละประเภทในวิธีที่แตกต่างกันออกไป ต่อไปเป็นการจัดการข้อผิดพลาดที่เกิดขึ้นตามประเภทของข้อผิดพลาดที่เกิดขึ้น

begin

    ["Ruby", "PHP", "Python"].first(-5)
    no_method

rescue ArgumentError => exception
    # Handle ArgumentError
    puts exception.inspect
rescue NameError => exception
    # Handle NameError
    puts exception.inspect
rescue => exception
    # Handle any StandardError
    puts exception.inspect
end

ในตัวอย่าง โค้ดของโปรแกรมสองบรรทักในบล็อคคำสั่ง begin นั้นมีสองข้อผิดพลาดที่สามารถเกิดขึ้นได้คือ ArgumentError และ NameError

["Ruby", "PHP", "Python"].first(-5)

ข้อผิดพลาด ArgumentError จะเกิดขึ้นเมื่อเราส่งค่าอาร์กิวเมนต์ที่ไม่ถูกต้องเข้าไปยังเมธอด first เนื่องจากเมธอดนี้รับอาร์กิวเมนต์ที่เป็นตัวเลขจำนวนเต็มบวกเท่านั้น แต่ค่าที่เราส่งเข้าไปยังเมธอดนั้นเป็น -5

no_method

คำสั่งต่อมาเราได้เรียกใช้งานเมธอด no_method สังเกตว่าเราไม่ได้ประกาศเมธอดนี้ก่อนเรยกใช้งาน ดังนั้นนี้จะทำให้เกิดข้อผิดพลาด NameError ขึ้น

rescue ArgumentError => exception
    # Handle ArgumentError
    puts exception.inspect
rescue NameError => exception
    # Handle NameError
    puts exception.inspect
rescue => exception
    # Handle any StandardError
    puts exception.inspect
end

ในตอนนี้ในบล็อคของคำสั่ง begin เราทราบว่ามีสองข้อผิดพลาดที่อาจจะเกิดขึ้นได้ ในภาษา Ruby เราสามารถเชื่อมต่อบล็อค rescue มากกว่าหนึ่งบล็อคได้เพื่อจัดการกับข้อผิดพลาดที่แตกต่างกัน เพื่อทำเช่นนี้ เราจะต้องกำหนดประเภทของข้อผิดพลาดเป็นอาร์กิวเมนต์ให้กับบล็อคด้วย และเมื่อเกิดข้อผิดพลาดขึ้น โปรแกรมจะย้ายไปทำงานในบล็อคของคำสั่ง rescue ที่ตรงกับประเภทของข้อผิดพลาดนั้นๆ นั่นเอง

#<ArgumentError: negative array size>

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

#["Ruby", "PHP", "Python"].first(-5)
no_method

และเพื่อทำให้ข้อผิดพลาด NameError เกิดขึ้น เราเพียงแค่คอมเมนต์โค้ดบรรทัดแรกออกไปเพื่อให้โปรแกรมได้ทำงานในบรรทัดที่สองนั่นเอง

#<NameError: undefined local variable or method `no_method' for main:Object>

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

ในตัวอย่างนี้ เราตั้งใจทำให้เกิดข้อผิดพลาดขึ้น เพื่อแสดงให้เห็นว่าเราสามารถกำหนดบล็อคของคำสั่ง rescue เพื่อจัดการกับข้อผิดพลาดต่างประเภทกันได้

การทำให้เกิดข้อผิดพลาดด้วยคำสั่ง raise

คุณได้เรียนรู้เกี่ยวกับวิธีการจัดการข้อผิดพลาดไปแล้ว แต่อาจจะยังคงมีคำถามคือแล้วข้อผิดพลาดเหล่านั่นเกิดขึ้นได้อย่างไร คำตอบก็คือข้อผิดพลาดนั้นเกิดขึ้นได้ก็เพราะเราทำให้มันเกิด และในภาษา Ruby เราสามารถใช้คำสั่ง raise เพื่อสั่งให้เกิดข้อผิดพลาดขึ้น นี่เป็นรูปแบบการใช้งาน

raise exception

คำสั่ง raise นั้นสำหรับทำให้เกิดข้อผิดพลาดประเภทใดๆ ขึ้นได้ โดยข้อผิดพลาดเหล่านั้นต้องเป็นออบเจ็คของข้อผิดพลาดที่สืบทอดมาจากคลาส StandardError หรือออบเจ็คจากคลาส StandardError เอง มาดูตัวอย่างการใช้งาน

print "Enter even number: "
number = gets.chomp.to_i

if number % 2 != 0
    raise StandardError.new("Number you entered is not an even number")
end

puts "Your even number is #{number}"

ในตัวอย่าง เราต้องการเขียนโปรแกรมเพื่อถามให้ผู้ใช้งานกรอกเลขคู่จากทางคีย์บอร์ด และถ้าหากตัวเลขที่กรอกเข้ามานั้นไม่ใช้เลขคู่ เราจะทำให้เกิดข้อผิดพลาดขึ้นด้วยคำสั่ง raise

if number % 2 != 0
    raise StandardError.new("Number you entered is not an even number")
end

นี่เป็นเงื่อนไขที่ทำให้เกิดข้อผิดพลาดขึ้น ถ้าหากตัวเลขนั้นหารด้วยสองไม่ลงตัว เราจะถือว่าเป็นตัวเลขที่ไม่สามารถยอมรับได้ และเราสร้างออบเจ็คของข้อผิดพลาดจากคลาส StandardError โดยคอนสตรัคเตอร์ของคลาสนั้นรับอาร์กิวเมนต์ที่เป็นข้อความสำหรับอธิบายข้อผิดพลาดที่เกิดขึ้น

Enter even number: 4
Your even number is 4
Enter even number: 7
Traceback (most recent call last):
raise.rb:5:in `<main>': Number you entered is not an even number (StandardError)

นี่เป็นผลลัพธ์การทำงานของโปรแกรมจากการรันสองครั้ง ครั้งแรกโปรแกรมไม่เกิดข้อผิดพลาดเนื่องจากตัวเลขที่กรอกเข้ามานั้นเป็นเลขคู่ ส่วนครั้งที่สองทำให้เกิดข้อผิดพลาด StandardError กับข้อความอธิบายที่เราได้กำหนดไปในตอนสร้างออบเจ็คของข้อผิดพลาด

ต่อไปเป็นตัวอย่างของโปรแกรมตรวจสอบจำนวนเฉพาะ โดยเราจะสร้างเมธอดสำหรับหาว่าตัวเลขเป็นจำนวนเฉพาะหรือไม่ และเมธอดนี้จะทำให้เกิดข้อผิดพลาดขึ้นถ้าหากตัวเลขที่ส่งเข้ามายังเมธอดเป็นจำนวนเต็มลบ เนื่องจากเราทราบว่าจำนวนเฉพาะนั้นต้องไม่เป็นลบนั่นเอง นี่เป็นโค้ดของโปรแกรม

def is_prime(n)
    if n < 0
        raise ArgumentError.new("Argument must not be a negative number")
    end
    for i in (2...n)
        return false if n % i == 0 && i != n
    end
    return true
end

begin
    puts("Prime number detector program")
    print("Enter your number: ")
    a = gets.chomp.to_i
    if is_prime(a)
        puts "#{a} is prime number"
    else
        puts "#{a} is not prime number"
    end
rescue => e
    puts e.message
end

ในตัวอย่าง เราได้ประกาศเมธอด is_prime สำหรับตรวจสอบว่าตัวเลขที่ส่งเข้ามานั้นเป็นจำนวนเฉพาะหรือไม่โดยเมธอดจะส่งค่ากลับเป็น Boolean ว่าตัวเลขนั้นเป็นจำนวนเฉพาะหรือไม่ จากเงื่อนไขที่ว่าจำนวนเฉพาะคือตัวเลขที่มีเพียงหนึ่งและตัวมันเองเท่านั้นที่หารลงตัว

if n < 0
    raise ArgumentError.new("Argument must not be a negative number")
end

ภายในเมธอดได้มีการตรวจสอบอาร์กิวเมนต์ที่ส่งเข้ามาด้วย ถ้าหากตัวเลขที่ส่งเข้านั้นมีค่าเป็นค่าลบ เราจะทำให้เกิดข้อผิดพลาด ArgumentError เนื่องจากเราทราบว่าจำนวนเต็มลบนั้นไม่สามารถนำมาตรวจสอบจำนวนเพาะได้

if is_prime(a)

หลังจากนั้นเป็นการเรียกใช้งานเมธอดจากค่าที่รับเข้ามาจากทางคีย์บอร์ด โดยเราได้กำหนดบล็อคคำสั่ง rescue สำหรับจัดการกับข้อผิดพลาดที่จะเกิดขึ้นจากเมธอด is_prime ในกรณีที่ค่าที่ส่งเข้ามาเป็นจำนวนเต็มลบนั่นเอง

Prime number detector program
Enter your number: 5
5 is prime number
Prime number detector program
Enter your number: -1
Argument must not be a negative number

นี่เป็นผลลัพธ์การทำงานของโปรแกรมจากการกรอกค่าเป็น 5 และ -1 ตามลำดับ ในตัวอย่างนี้ได้แสดงให้เห็นว่า เราได้ควบคุมอาร์กิวเมนต์ที่รับเข้ามายังเมธอด โดยการทำให้เกิดข้อผิดพลาดขึ้นเมื่อมันไม่ใช่ค่าที่เราต้องการ

นี่เป็นอีกวิธีหนึ่งในการออกแบบโปรแกรมให้มีความแข็งแรง เมื่อคุณเขียนโปรแกรมหรือเมธอดเพื่องานบางอย่าง เราอาจจะต้องตรวจสอบค่าที่รับเข้ามาว่าจะสามารถทำใช้งานได้หรือไม่

การใช้งานคำสั่ง else และ ensure

ในการจัดการกับข้อผิดพลาด เราสามารถใช้งานคำสั่ง else และคำสั่ง ensure ร่วมกับคำสั่ง raise ได้ คำสั่ง else ใช้สำหรับกำหนดบล็อคเพื่อให้โปรแกรมทำงานเมื่อไม่มีข้อผิดพลาดเกิดขึ้น ในขณะที่คำสั่ง ensure ใช้สำหรับกำหนดบล็อคเพื่อให้โปรแกรมทำงานไม่ว่าจะเกิดข้อผิดพลาดหรือไม่ก็ตาม มาดูตัวอย่างการใช้งาน

login_status = nil

begin
    print "Enter username: "
    username = gets.chomp

    print "Enter password: "
    password = gets.chomp

    if username != "metin"
        raise StandardError.new("Invalid username")
    end

    if password != "1234"
        raise StandardError.new("Invalid password")
    end

rescue => exception
    login_status = false
    puts exception.message
else
    login_status = true
    puts "Hi metin! You've successfully logged in."
ensure
    puts "Log login history for metin: #{login_status}"
end

ในตัวอย่าง เป็นโปรแกรมจำลองการเข้าสู่ระบบ โดยผู้ใช้จะต้องกรอกชื่อผู้ใช้และรหัสผ่านจากคีย์บอร์ด สำหรับชื่อผู้ใช้และรหัสผ่านที่ถูกต้องนั้นเราได้กำหนดไว้ว่าต้องเป็น "metin" และรหัสผ่านต้องเป็น "1234" ตามลำดับ ซึ่งในการเขียนโปรแกรมจริง ชื่อผู้ใช่และรหัสผ่านอาจจะต้องตรวจสอบจากฐานข้อมูล

if username != "metin"
    raise StandardError.new("Invalid username")
end

if password != "1234"
    raise StandardError.new("Invalid password")
end

เมื่อผู้ใช้งานโปรแกรมกรอกชื่อผู้ใช้และรหัสผ่านเรียบร้อยแล้ว เราได้ทำการตรวจสอบว่าถูกต้องหรือไม่ ถ้าหากข้อมูลที่กรอกมาไม่ถูก เราจะสร้างออบเจ็คข้อผิดพลาดจากคลาส StandardError พร้อมกับคำอธิบายว่าทำไม

else
    login_status = true
    puts "Hi metin! You've successfully logged in."

สำหรับในบล็อคของคำสั่ง else จะทำงานเมื่อไม่มีข้อผิดพลาดเกิดขึ้นเลย นั่นหมายความว่าผู้ใช้สามารถเข้าสู่ระบบได้สำเร็จ และเรากล่าวคำทักผู้ใช้งานโปรแกรมภายในบล็อคนี้

ensure
    puts "Log login history for metin: #{login_status}"

ในบล็อคของคำสั่ง ensure นั้นจะทำงานไม่ว่าจะเกิดข้อผิดพลาดขึ้นหรือไม่ ดังนั้นภายในบล็อคนี้เราได้ทำการเก็บบันทึกว่าการเข้าสู่ระบบสำเร็จหรือล้มเหลวที่นี่ จากผลลัพธ์การเข้าสู่ระบบที่เราเก็บไว้ในตัวแปร login_status

Enter username: metin
Enter password: 1234
Hi metin! You've successfully logged in.
Log login history for metin: true
Enter username: metin
Enter password: 5555
Invalid password
Log login history for metin: false

นี่เป็นผลลัพธ์การทำงานของโปรแกรม ในการรันโปรแกรมครั้งแรกข้อมูลการเข้าสู่ระบบที่กรอกเข้ามานั้นถูกต้อง นั่นทำให้ไม่เกิดข้อผิดพลาดขึ้น ดังนั้นในบล็อคของคำสั่ง else จะทำงาน และในการรันครั้งที่สองการทำงานจะถูกข้ามไปเนื่องจากมีข้อผิดพลาดเกิดขึ้น

สำหรับในบล็อคของคำสั่ง ensure จะเห็นว่ามันทำงานเสมอไม่ว่าจะเกิดข้อผิดพลาดขึ้นหรือไม่ก็ตาม เราใช้บล็อคนี้เพื่อให้แน่ใจว่าการบันทึกนั้นจะทำงานไม่ว่าการเข้าสู่ระบบจะสำเร็จหรือล้มเหลว

การสร้างคลาส Exception

ในภาษา Ruby เราสามารถสร้างคลาส Exception ขึ้นมาเองได้ นั่นจะทำให้เราสามารถเพิ่มเติมความสามารถของคลาส และนำไปใช้ได้เมื่อเกิดข้อผิดพลาด อย่างไรก็ตาม คลาส Exception ที่เราจะสร้างขึ้นเองนั้นจะต้องสืบทอดมาจากคลาส StandardError ในการที่จะทำให้เกิดข้อผิดพลาดด้วยคำสั่ง raise ได้ ต่อไปมาดูตัวอย่างการสร้างคลาส Exception ในภาษา Ruby

เราจะเขียนโปรแกรมสำหรับคำนวณเกรด โดยโปรแกรมของเราจะอนุญาติให้กรอกคะแนนตั้งแต่ 1 - 100 เท่านั้น ไม่เช่นนั้นเราจะทำให้เกิดข้อผิดพลาดขึ้นจากคลาสที่เราสร้างขึ้นมา นี่เป็นโค้ดของโปรแกรม

grade.rb
class ScoreError < StandardError

    def initialize(message, score)
        super(message)
        @score = score
        log
    end

    def description
        puts "Please enter a valid score between 1 - 100"
    end

    def log
        file = File.open("error_log.txt", "w")
        file.puts("#{Time.now} #{@score}")
        file.close
    end

end

begin
    print "Enter score: "
    score = gets.chomp.to_i

    if score < 0 || score > 100
        raise ScoreError.new("Invalid score", score)
    else
        if score >= 80
            puts "Your grade is A"
        elsif score >=70
            puts "Your grade is B"
        elsif score >= 60
            puts "Your grade is C"
        elsif score >= 50
            puts "Your grade is D"
        else
            puts "Your grade is F"
        end
    end

rescue ScoreError => exception
    exception.description
end

ในตัวอย่าง เป็นโปรแกรมสำหรับคำนวณเกรดโดยรับคะแนนมาจากทางคีย์บอร์ด โดยโปรแกรมจะทำงานก็ต่อเมื่อคะแนนที่กรอกเข้ามานั้นมีค่าอยู่ระหว่าง 1 - 100 ซึ่งเป็นช่วงคะแนนที่ถูกต้อง ไม่เช่นนั้นเราจะถือว่าค่าของคะแนนที่รับเข้ามานั้นมีความผิดพลาด และเราจะทำให้เกิดข้อผิดพลาดขึ้นจากคลาสที่สร้างขึ้นมา

class ScoreError < StandardError

    def initialize(message, score)
        super(message)
        @score = score
        log
    end

    def description
        puts "Please enter a valid score between 1 - 100"
    end

    def log
        file = File.open("error_log.txt", "w")
        file.puts("#{Time.now} #{@score}")
        file.close
    end

end

ในตอนแรกของโปรแกรม เราได้ประกาศคลาส ScoreError คลาสนี้เป็นคลาสของคะแนนที่ผิดพลาด เราได้สืบทอดคลาสนี้มาจากคลาส StandardError เพื่อทำให้มันเป็นคลาสของข้อผิดพลาดที่สามารถทำให้เกิดข้อผิดพลาดได้ด้วยคำสั่ง raise

ภายในคลาส ScoreError เราได้ประกาสสองเมธอดเพื่อใช้งาน เมธอด description ใช้สำหรับอธิบายการแก้ปัญหาของข้อผิดพลาดที่เกิดขึ้น และเมธอด log ใช้สำหรับเก็บบันทึกเมื่อเกิดข้อผิดพลาดขึ้น กล่าวคือเมื่อผู้ใช้กรอกคะแนนที่ไม่ถูกต้องเข้ามา เราจะเก็บบักทึกข้อผิดพลาดนั้นโดยบันทึกคะแนนและเวลาที่เกิดข้อผิดพลาดขึ้นลงไปบนไฟล์ error_log.txt ด้วย

print "Enter score: "
score = gets.chomp.to_i

if score < 0 || score > 100
    raise ScoreError.new("Invalid score", score)

จากนั้นในบล็อคคำสั่ง begin เราได้เริ่มต้นการรับค่าคะแนนเข้ามาจากทางคียบอร์ดและตรวจสอบคะแนนที่รับเข้ามาด้วยคำสั่ง if ว่าถ้าหากคะแนนไม่อยู่ในระหว่าง 1 - 100 เราจะทำให้เกิดข้อผิดพลาด ScoreError ขึ้น

rescue ScoreError => exception
    exception.description
end

เราจัดการข้อผิดพลาดด้วยคำสั่ง rescue เช่นเดิม ในแต่ในครั้งนี้เราเปลี่ยนประเภทของข้อผิดพลาดเป็น ScoreError เพื่อตรวจจับข้อผิดพลาดที่เราสร้างขึ้นมาเองนั่นเอง เราเรียกใช้เมธอด description เพื่อดูวิธีในการแก้ปัญหาข้อผิดพลาดนี้

Enter score: -4
Please enter a valid score between 1 - 100

นี่เป็นผลลัพธ์การทำงานของโปรแกรมเมื่อเรากรอกคะแนนเป็น -4 ซึ่งจะทำให้เกิดข้อผิดพลาดขึ้น

ในตัวอย่างนี้แสดงให้เห็นว่าเราสามารถสร้างคลาส Exception ของเราเองโดยการสืบทอดมาจากคลาส StandardError เพื่อเพิ่มเติมความสามารถของคลาสข้อผิดพลาดของเรา เช่น การเพิ่มแอตทริบิวต์ หรือเมธอดเพื่อทำงานบางอย่างเพิ่มเติม

ในบทนี้ คุณได้เรียนรู้เกี่ยวกับการจัดการข้อผิดพลาดในภาษา Ruby เราได้พูดถึงการจัดการกับข้อผิดพลาดที่เกิดขึ้น และการออกแบบโปรแกรมให้เกิดข้อผิดพลาดขึ้นเมื่อมีบางอย่างทำงานไม่เป็นไปตามที่ต้องการ นอกจากนี้เรายังสามารถสร้างคลาส Exception ของเราเองได้อีกด้วย