1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
use crate::{binding::vm, util, AnyObject, Array, Class, Object, RString};
/// Descendants of class Exception are used to communicate between Kernel#raise
/// and rescue statements in `begin ... end` blocks. Exception objects carry
/// information about the exception – its type (the exception's class name), an
/// optional descriptive string, and optional traceback information. Exception
/// subclasses may add additional information like NameError#name.
///
/// Programs may make subclasses of Exception, typically of StandardError or
/// RuntimeError, to provide custom classes and add additional information.
/// See the subclass list below for defaults for `raise` and `rescue`.
pub trait Exception: Object {
/// Construct a new Exception object, optionally passing in a message.
///
/// # Examples
/// ```
/// use rutie::{AnyException, Exception, Object, VM};
/// # VM::init();
///
/// assert_eq!(
/// AnyException::new("StandardError", None).to_s(),
/// "StandardError"
/// );
/// ```
///
/// A nested exception
///
/// ```
/// use rutie::{AnyException, Exception, Object, VM, Class};
/// # VM::init();
///
/// let mut klass = Class::new("MyGem", None);
/// let se = Class::from_existing("StandardError");
/// let _ = klass.define_nested_class("MyError", Some(&se));
///
/// assert_eq!(
/// AnyException::new("MyGem::MyError", None).to_s(),
/// "MyGem::MyError"
/// );
/// ```
fn new(class: &str, msg: Option<&str>) -> Self {
let class = util::inmost_rb_object(class);
let msg = msg.map(|s| RString::new_utf8(s).value());
Self::from(vm::call_method(class, "new", util::option_to_slice(&msg)))
}
/// With no argument, or if the argument is the same as the receiver,
/// return the receiver. Otherwise, create a new exception object of
/// the same class as the receiver, but with a message equal
/// to `string.to_str`.
///
/// # Examples
/// ```
/// use rutie::{AnyException, Exception, Object, VM};
/// # VM::init();
///
/// assert_eq!(
/// AnyException::new("StandardError", Some("something went wrong")).exception(None),
/// AnyException::new("StandardError", Some("something went wrong"))
/// );
/// ```
fn exception(&self, string: Option<&str>) -> Self {
let string = string.map(|s| RString::new_utf8(s).value());
Self::from(vm::call_method(
self.value(),
"exception",
util::option_to_slice(&string),
))
}
/// Returns any backtrace associated with the exception. The
/// backtrace is an array of strings, each containing either
/// “filename:lineNo: in `method''' or “filename:lineNo.''
///
/// # Examples
/// ```
/// use rutie::{AnyException, Exception, Object, VM, RString};
/// # VM::init();
///
/// let x = AnyException::new("StandardError", Some("something went wrong"));
///
/// assert!(x.backtrace().is_none());
/// ```
fn backtrace(&self) -> Option<Array> {
let result = vm::call_method(self.value(), "backtrace", &[]);
if result.is_nil() {
return None;
}
Some(Array::from(result))
}
/// Returns any backtrace associated with the exception. This
/// method is similar to #backtrace, but the backtrace is an
/// array of Thread::Backtrace::Location.
///
/// Now, this method is not affected by #set_backtrace.
///
/// # Examples
/// ```
/// use rutie::{AnyException, Exception, Object, VM, RString};
/// # VM::init();
///
/// let x = AnyException::new("StandardError", Some("something went wrong"));
///
/// assert!(x.backtrace_locations().is_none());
/// ```
fn backtrace_locations(&self) -> Option<Array> {
let result = vm::call_method(self.value(), "backtrace_locations", &[]);
if result.is_nil() {
return None;
}
Some(Array::from(result))
}
/// Returns the previous exception at the time this
/// exception was raised. This is useful for wrapping exceptions
/// and retaining the original exception information.
///
/// # Examples
/// ```
/// use rutie::{AnyException, Exception, Object, VM, RString};
/// # VM::init();
///
/// let x = AnyException::new("StandardError", Some("something went wrong"));
///
/// assert!(x.cause().is_none());
/// ```
fn cause(&self) -> Option<Self> {
let result = vm::call_method(self.value(), "cause", &[]);
if result.is_nil() {
return None;
}
Some(Self::from(result))
}
/// Return this exception's class name and message
///
/// # Examples
/// ```
/// use rutie::{AnyException, Exception, Object, VM};
/// # VM::init();
///
/// assert_eq!(
/// AnyException::new("StandardError", Some("oops")).inspect(),
/// "#<StandardError: oops>"
/// );
/// ```
fn inspect(&self) -> String {
RString::from(vm::call_method(self.value(), "inspect", &[])).to_string()
}
/// Returns the result of invoking `exception.to_s`. Normally this
/// returns the exception's message or name.
///
/// # Examples
/// ```
/// use rutie::{AnyException, Exception, Object, VM};
/// # VM::init();
///
/// assert_eq!(
/// AnyException::new("StandardError", Some("oops")).message(),
/// "oops"
/// );
/// ```
fn message(&self) -> String {
RString::from(vm::call_method(self.value(), "message", &[])).to_string()
}
/// Sets the backtrace information associated with exc. The backtrace
/// must be an array of String objects or a single String in the format
/// described in #backtrace.
///
/// # Examples
/// ```
/// use rutie::{AnyException, Exception, Object, VM, RString, Array};
/// # VM::init();
///
/// let x = AnyException::new("StandardError", Some("something went wrong"));
///
/// let mut arr = Array::new();
/// arr.push(RString::new_utf8("prog.rb:10"));
///
/// x.set_backtrace(arr.to_any_object());
///
/// assert_eq!(
/// x.backtrace().
/// unwrap().
/// pop().
/// try_convert_to::<RString>().
/// unwrap().
/// to_string(),
/// "prog.rb:10"
/// );
/// ```
fn set_backtrace(&self, backtrace: AnyObject) -> Option<Array> {
let result = vm::call_method(self.value(), "set_backtrace", &[backtrace.value()]);
if result.is_nil() {
return None;
}
Some(Array::from(result))
}
/// Returns exception's message (or the name of the exception if no message is set).
///
/// # Examples
/// ```
/// use rutie::{AnyException, Exception, Object, VM};
/// # VM::init();
///
/// assert_eq!(
/// AnyException::new("StandardError", Some("oops")).to_s(),
/// "oops"
/// );
/// ```
fn to_s(&self) -> String {
RString::from(vm::call_method(self.value(), "to_s", &[])).to_string()
}
}