Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Thoát Chương Trình Ruby Một Cách Nhu Nhược: Các Phương Pháp Hay Nhất

Là lập trình viên, chúng ta dành nhiều thời gian để làm cho chương trình chạy mà dễ dàng bỏ qua cách chúng thoát. Và điều đó quan trọng! Khi chương trình hoạt động đúng khi thoát, chúng dễ dàng quản lý hơn và khả năng làm việc với các công cụ devops tiêu chuẩn cao hơn.

Có nhiều cách để thoát một chương trình Ruby. Tôi đã chỉ ra một số dưới đây. Trong bài này, chúng ta sẽ thảo luận chi tiết từng cách, và cách chúng có thể được dùng để làm cho ứng dụng của bạn trở thành một "công dân unix" chu đáo.

# Bạn có thể thoát bằng cách gọi phương thức
exit
exit!
abort("She cannot take any more of this, Captain!")
# ...hoặc bằng cách không bắt exception
raise("Destroyed...")
fail
# ...hoặc để chương trình kết thúc tự nhiên. :)

Mã thoát, và BẠN

Mọi chương trình bạn chạy trên Linux và OSX trả về một mã trạng thái thoát khi nó chạy xong. Bạn thường không thấy mã thoát. Nó được dùng bởi OS bên dưới để xác định xem chương trình thoát bình thường hay có lỗi.

Nếu bạn dùng bash, bạn có thể xem mã thoát của chương trình vừa chạy bằng cách kiểm tra biến môi trường $?. Ví dụ dưới đây cho thấy mã thoát cho thất bại, sau đó cho thành công.

% ls this-file-doesnt-exist
ls: this-file-doesnt-exist: No such file or directory
blog% echo $?
1
% ls .
bm.rb
% echo $?
0

Quy tắc chung cho các hệ thống unix-based là không có nghĩa là thành công. Khác không có nghĩa là thất bại.

Nếu bạn từng dùng toán tử && trong bash, thì bạn đã dùng status codes. Trong ví dụ dưới đây, chúng ta bảo bash chạy chương trình B chỉ nếu chương trình A thành công.

% a && b

Bạn có thể dùng thủ thuật này theo nhiều cách. Ví dụ, bạn có thể muốn precompile assets, và upload chúng lên CDN.

blog% rake assets:precompile && rake cdn:upload_assets

Chỉ định trạng thái thoát với Ruby

Ruby lo phần lớn việc trạng thái thoát cho chúng ta. Nếu chương trình thoát bình thường, nó trả về trạng thái "thành công". Nếu nó thất bại do exception không bắt, nó cho trạng thái "thất bại". Dưới đây tôi cho thấy mã thoát cho script ném exception.

% ruby err.rb
err.rb:1:in `
': goodbye (RuntimeError) tmp% echo $? 1

Nhưng nếu bạn không muốn bất kỳ uncaught exceptions nào? Nếu bạn muốn thoát sạch, nhưng vẫn trả về mã lỗi "thất bại"? Hơn nữa, nếu bạn muốn trả về mã tùy chỉnh với thông báo lỗi?

May mắn thay, nó khá dễ dàng. Chỉ cần truyền một đối số vào hàm exit. Đối số có thể là boolean hoặc integer. Nếu là boolean, thì true nghĩa là thành công. Nếu là integer thì 0 nghĩa là thành công.

exit(true)  # Thoát với mã "thành công"
exit(0)     # Thoát với mã "thành công"
exit(false) # Thoát với mã "thất bại"
exit(1)     # Thoát với mã "thất bại"
exit(436)   # Mã lỗi tùy chỉnh

Cách exit hoạt động bên dưới

Phương thức exit đơn giản chỉ ném một exception SystemExit. Nếu nó không bị bắt, chương trình abort giống như với bất kỳ uncaught exception nào khác. Điều đó khá cool, nhưng có một số hậu quả thú vị.

Nếu bạn nuốt chửng tất cả SystemExit exceptions, bạn sẽ làm hỏng phương thức exit. Tôi đã chỉ ra điều này trong ví dụ dưới đây.

begin
  exit 100
rescue SystemExit => e
  puts "Tried to exit with status #{ e.status }"
end
puts "...but it never exited, because we swallowed the exception"
# Outputs:
# Tried to exit with status 100
# ...but it never exited, because we swallowed the exception

Đây là thêm một lý do không bao giờ rescue Exception. Vì SystemExit kế thừa từ Exception, việc nuốt Exception sẽ làm hỏng exit.

begin
  exit
rescue Exception # never do this
  puts "I just broke the exit function!"
end

Thông báo lỗi đọc được cho con người

Mặc dù mã thoát tuyệt vời cho máy móc, chúng ta con người thường thích một chút văn bản giải thích. May mắn thay, OS cung cấp cho chúng ta một output stream chuyên dùng cho những thứ như thông báo lỗi. Đúng, tôi đang nói về STDERR.

Bạn có thể ghi vào STDERR giống như ghi vào bất kỳ IO object nào. Trong ví dụ dưới đây tôi đang ghi thông báo lỗi và thoát với trạng thái "lỗi".

STDERR.puts("ABORTED! You forgot to BAR the BAZ")
exit(false)

Đây là Ruby, tất nhiên có cách ngắn gọn hơn để ghi ra stdout và thoát với mã lỗi. Chỉ cần dùng phương thức abort.

# Ghi thông báo vào STDERR và thoát với mã trạng thái lỗi.
abort("ABORTED! You forgot to BAR the BAZ")

Callback qua at_exit

Ruby cho phép bạn đăng ký handler có thể được gọi bất cứ khi nào chương trình thoát. Có thể có nhiều hơn một - chúng được gọi theo thứ tự ngược lại với thứ tự đăng ký. Dưới đây là giao diện của nó:

at_exit do
  puts "handler 1"
end
at_exit do
  puts "handler 2"
end
# Outputs "handler2\nhandler1" on exit

Exit handler có thể ghi đè mã thoát. Bạn làm điều này bằng cách gọi exit từ bên trong handler. Mặc dù có vẻ như điều này nên gây vòng lặp vô tận, nhưng nó không.

at_exit do
  exit 100
end
exit 0
# Chương trình này thoát với mã 100

Nếu bạn muốn thoát mà không gọi bất kỳ callback nào, bạn có thể làm như vậy qua phương thức exit!. Nhưng hãy nhớ rằng điều này có thể gây vấn đề nếu bạn có gems hoặc mã third-party khác phụ thuộc vào những callbacks đó.

Một điều thú vị khác

Có vẻ như nhiều thư viện dùng at_exit theo cách sáng tạo - và có người có thể nói là hack. Ví dụ, Sinatra dùng một at_exit hook như một cách để boot lên web app. Điều này cho phép nó chắc chắn rằng tất cả mã của bạn đã được load trước khi nó start server. Dưới đây là giao diện của nó:

module Sinatra
  class Application < Base
    ...
    at_exit { Application.run! if $!.nil? && Application.run? }
  end
end

Có một bài viết tuyệt vời về điều này trên blog Arkency: Are we abusing at_exit?