GitHub

@@ -127,6 +127,42 @@ MRB_API mrb_value mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_val

127127

mrb_func_t rescue, mrb_value r_data,

128128

mrb_int len, struct RClass **classes);

129129130+

/**

131+

* Calls `func` via `mrb_protect_error()` and then always executes the user block exactly once.

132+

* Even if a global jump (similar to a Ruby exception) occurs within `func`, the block will be executed,

133+

* and after the block's completion, the global jump will be re-thrown.

134+

*

135+

* By checking `mrb->exc != NULL` within the block, you can determine if a global jump occurred in `func`.

136+

*

137+

* If you want to suppress the global jump and continue processing, use `mrb_clear_error(mrb); break;`.

138+

*

139+

* - `mrb`: The mruby state reference

140+

* - `result_var`: Pre-defined mrb_value type variable (to receive `func`'s return value)

141+

* - `func`: Function to call (compatible with `mrb_protect_error_func`)

142+

* - `data`: User data to pass to `func`

143+

*

144+

* Example:

145+

*

146+

* mrb_value result;

147+

* MRB_ENSURE(mrb, result, body_func, userdata) {

148+

* // This block is always executed (equivalent to Ruby's ensure)

149+

*

150+

* if (mrb->exc) {

151+

* // Post-processing when an exception occurs

152+

* }

153+

*

154+

* // To ignore the global jump, use `mrb_clear_error(mrb); break;` here

155+

* }

156+

*/

157+

#define MRB_ENSURE(mrb, result_var, func, data) \

158+

for (mrb_bool MRB_UNIQNAME(_break_) = FALSE; \

159+

!MRB_UNIQNAME(_break_) && \

160+

(((result_var) = mrb_protect_error(mrb, func, data, &MRB_UNIQNAME(_break_))), \

161+

((mrb)->exc = (MRB_UNIQNAME(_break_) ? mrb_obj_ptr((result_var)) : NULL)), \

162+

TRUE); \

163+

(void)(MRB_UNIQNAME(_break_) && (mrb)->jmp && (mrb_exc_raise(mrb, result_var), TRUE)), \

164+

MRB_UNIQNAME(_break_) = TRUE)

165+130166

MRB_END_DECL

131167132168

#endif /* MRUBY_ERROR_H */

Read the original on github.com ↗