magnus/module.rs
1//! Types and functions for working with Ruby modules.
2//!
3//! See also [`Ruby`](Ruby#core-modules) for more module related methods.
4
5use std::{ffi::CString, fmt, mem::transmute, os::raw::c_int};
6
7use rb_sys::{
8 rb_alias, rb_attr, rb_class_inherited_p, rb_const_get, rb_const_set, rb_define_class_id_under,
9 rb_define_method_id, rb_define_module_function, rb_define_module_id_under,
10 rb_define_private_method, rb_define_protected_method, rb_include_module, rb_mComparable,
11 rb_mEnumerable, rb_mErrno, rb_mFileTest, rb_mGC, rb_mKernel, rb_mMath, rb_mProcess,
12 rb_mWaitReadable, rb_mWaitWritable, rb_mod_ancestors, rb_module_new, rb_prepend_module,
13 ruby_value_type, VALUE,
14};
15
16use crate::{
17 class::{Class, RClass},
18 error::{protect, Error},
19 exception::ExceptionClass,
20 into_value::IntoValue,
21 method::Method,
22 object::Object,
23 r_array::RArray,
24 try_convert::TryConvert,
25 value::{
26 private::{self, ReprValue as _},
27 IntoId, NonZeroValue, ReprValue, Value,
28 },
29 Ruby,
30};
31
32/// # `RModule`
33///
34/// Functions that can be used to create Ruby modules.
35///
36/// See also the [`RModule`] type.
37impl Ruby {
38 /// Create a new anonymous module.
39 ///
40 /// # Examples
41 ///
42 /// ```
43 /// use magnus::{prelude::*, Error, Ruby};
44 ///
45 /// fn example(ruby: &Ruby) -> Result<(), Error> {
46 /// let module = ruby.module_new();
47 /// assert!(module.is_kind_of(ruby.class_module()));
48 ///
49 /// Ok(())
50 /// }
51 /// # Ruby::init(example).unwrap()
52 /// ```
53 pub fn module_new(&self) -> RModule {
54 unsafe { RModule::from_rb_value_unchecked(rb_module_new()) }
55 }
56}
57
58/// A Value pointer to a RModule struct, Ruby's internal representation of
59/// modules.
60///
61/// See the [`Module`] trait for defining instance methods and nested
62/// classes/modules.
63/// See the [`Object`] trait for defining singleton methods (aka class methods).
64///
65/// See the [`ReprValue`] trait for additional methods available on this type.
66/// See [`Ruby`](Ruby#rmodule) for methods to create an `RModule`.
67#[derive(Clone, Copy)]
68#[repr(transparent)]
69pub struct RModule(NonZeroValue);
70
71impl RModule {
72 /// Return `Some(RModule)` if `val` is a `RModule`, `None` otherwise.
73 ///
74 /// # Examples
75 ///
76 /// ```
77 /// use magnus::{eval, RModule};
78 /// # let _cleanup = unsafe { magnus::embed::init() };
79 ///
80 /// assert!(RModule::from_value(eval("Enumerable").unwrap()).is_some());
81 /// assert!(RModule::from_value(eval("String").unwrap()).is_none());
82 /// assert!(RModule::from_value(eval("nil").unwrap()).is_none());
83 /// ```
84 #[inline]
85 pub fn from_value(val: Value) -> Option<Self> {
86 unsafe {
87 (val.rb_type() == ruby_value_type::RUBY_T_MODULE)
88 .then(|| Self(NonZeroValue::new_unchecked(val)))
89 }
90 }
91
92 #[inline]
93 pub(crate) unsafe fn from_rb_value_unchecked(val: VALUE) -> Self {
94 Self(NonZeroValue::new_unchecked(Value::new(val)))
95 }
96
97 /// Create a new anonymous module.
98 ///
99 /// # Panics
100 ///
101 /// Panics if called from a non-Ruby thread. See [`Ruby::module_new`] for
102 /// the non-panicking version.
103 ///
104 /// # Examples
105 ///
106 /// ```
107 /// # #![allow(deprecated)]
108 /// use magnus::{class, prelude::*, RModule};
109 /// # let _cleanup = unsafe { magnus::embed::init() };
110 ///
111 /// let module = RModule::new();
112 /// assert!(module.is_kind_of(class::module()));
113 /// ```
114 #[cfg_attr(
115 not(feature = "old-api"),
116 deprecated(note = "please use `Ruby::module_new` instead")
117 )]
118 #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
119 #[inline]
120 pub fn new() -> Self {
121 get_ruby!().module_new()
122 }
123
124 /// Define a method in `self`'s scope as a 'module function'. This method
125 /// will be visible as a public 'class' method on the module and a private
126 /// instance method on any object including the module.
127 ///
128 /// # Examples
129 ///
130 /// ```
131 /// use magnus::{function, r_string, rb_assert, Error, RString, Ruby};
132 ///
133 /// fn greet(ruby: &Ruby) -> RString {
134 /// r_string!(ruby, "Hello, world!")
135 /// }
136 ///
137 /// fn example(ruby: &Ruby) -> Result<(), Error> {
138 /// let module = ruby.define_module("Greeting")?;
139 /// module.define_module_function("greet", function!(greet, 0))?;
140 ///
141 /// rb_assert!(ruby, r#"Greeting.greet == "Hello, world!""#);
142 ///
143 /// rb_assert!(
144 /// ruby,
145 /// r#"
146 /// include Greeting
147 /// greet == "Hello, world!"
148 /// "#,
149 /// );
150 ///
151 /// Ok(())
152 /// }
153 /// # Ruby::init(example).unwrap()
154 /// ```
155 pub fn define_module_function<M>(self, name: &str, func: M) -> Result<(), Error>
156 where
157 M: Method,
158 {
159 debug_assert_value!(self);
160 let name = CString::new(name).unwrap();
161 protect(|| {
162 unsafe {
163 rb_define_module_function(
164 self.as_rb_value(),
165 name.as_ptr(),
166 transmute(func.as_ptr()),
167 M::arity().into(),
168 )
169 };
170 Ruby::get_with(self).qnil()
171 })?;
172 Ok(())
173 }
174}
175
176impl fmt::Display for RModule {
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 write!(f, "{}", unsafe { self.to_s_infallible() })
179 }
180}
181
182impl fmt::Debug for RModule {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 write!(f, "{}", self.inspect())
185 }
186}
187
188impl IntoValue for RModule {
189 #[inline]
190 fn into_value_with(self, _: &Ruby) -> Value {
191 self.0.get()
192 }
193}
194
195impl Object for RModule {}
196impl Module for RModule {}
197
198unsafe impl private::ReprValue for RModule {}
199
200impl ReprValue for RModule {}
201
202impl TryConvert for RModule {
203 fn try_convert(val: Value) -> Result<Self, Error> {
204 Self::from_value(val).ok_or_else(|| {
205 Error::new(
206 Ruby::get_with(val).exception_type_error(),
207 format!("no implicit conversion of {} into Module", unsafe {
208 val.classname()
209 },),
210 )
211 })
212 }
213}
214
215/// Functions available on both classes and modules.
216pub trait Module: Object + ReprValue + Copy {
217 /// Define a class in `self`'s scope.
218 ///
219 /// # Examples
220 ///
221 /// ```
222 /// use magnus::{prelude::*, rb_assert, Error, Ruby};
223 ///
224 /// fn example(ruby: &Ruby) -> Result<(), Error> {
225 /// let outer = ruby.define_module("Outer")?;
226 /// outer.define_class("Inner", ruby.class_object())?;
227 /// rb_assert!(ruby, "Outer::Inner.is_a?(Class)");
228 ///
229 /// Ok(())
230 /// }
231 /// # Ruby::init(example).unwrap()
232 /// ```
233 fn define_class<T>(self, name: T, superclass: RClass) -> Result<RClass, Error>
234 where
235 T: IntoId,
236 {
237 debug_assert_value!(self);
238 debug_assert_value!(superclass);
239 let id = name.into_id_with(&Ruby::get_with(self));
240 let superclass = superclass.as_rb_value();
241 protect(|| unsafe {
242 RClass::from_rb_value_unchecked(rb_define_class_id_under(
243 self.as_rb_value(),
244 id.as_rb_id(),
245 superclass,
246 ))
247 })
248 }
249
250 /// Define a module in `self`'s scope.
251 ///
252 /// # Examples
253 ///
254 /// ```
255 /// use magnus::{prelude::*, rb_assert, Error, Ruby};
256 ///
257 /// fn example(ruby: &Ruby) -> Result<(), Error> {
258 /// let outer = ruby.define_module("Outer")?;
259 /// outer.define_module("Inner")?;
260 /// rb_assert!(ruby, "Outer::Inner.is_a?(Module)");
261 /// rb_assert!(ruby, "!Outer::Inner.is_a?(Class)");
262 ///
263 /// Ok(())
264 /// }
265 /// # Ruby::init(example).unwrap()
266 /// ```
267 fn define_module<T>(self, name: T) -> Result<RModule, Error>
268 where
269 T: IntoId,
270 {
271 let id = name.into_id_with(&Ruby::get_with(self));
272 protect(|| unsafe {
273 RModule::from_rb_value_unchecked(rb_define_module_id_under(
274 self.as_rb_value(),
275 id.as_rb_id(),
276 ))
277 })
278 }
279
280 /// Define an exception class in `self`'s scope.
281 ///
282 /// # Examples
283 ///
284 /// ```
285 /// use magnus::{prelude::*, rb_assert, Error, Ruby};
286 ///
287 /// fn example(ruby: &Ruby) -> Result<(), Error> {
288 /// let outer = ruby.define_module("Outer")?;
289 /// outer.define_error("InnerError", ruby.exception_standard_error())?;
290 /// rb_assert!(ruby, "Outer::InnerError.is_a?(Class)");
291 /// rb_assert!(ruby, "Outer::InnerError < Exception");
292 ///
293 /// Ok(())
294 /// }
295 /// # Ruby::init(example).unwrap()
296 /// ```
297 fn define_error<T>(self, name: T, superclass: ExceptionClass) -> Result<ExceptionClass, Error>
298 where
299 T: IntoId,
300 {
301 self.define_class(name, superclass.as_r_class())
302 .map(|c| unsafe { ExceptionClass::from_value_unchecked(c.as_value()) })
303 }
304
305 /// Include `module` into `self`.
306 ///
307 /// Effectively makes `module` the superclass of `self`. See also
308 /// [`prepend_module`](Module::prepend_module).
309 ///
310 /// # Examples
311 ///
312 /// ```
313 /// use magnus::{function, prelude::*, rb_assert, Error, RClass, Ruby};
314 ///
315 /// fn test() -> i64 {
316 /// 42
317 /// }
318 ///
319 /// fn example(ruby: &Ruby) -> Result<(), Error> {
320 /// let module = ruby.module_new();
321 /// module.define_method("test", function!(test, 0))?;
322 ///
323 /// let class = RClass::new(ruby.class_object())?;
324 /// class.include_module(module)?;
325 ///
326 /// let obj = class.new_instance(())?;
327 /// rb_assert!(ruby, "obj.test == 42", obj);
328 ///
329 /// Ok(())
330 /// }
331 /// # Ruby::init(example).unwrap()
332 /// ```
333 fn include_module(self, module: RModule) -> Result<(), Error> {
334 protect(|| {
335 unsafe { rb_include_module(self.as_rb_value(), module.as_rb_value()) };
336 Ruby::get_with(self).qnil()
337 })?;
338 Ok(())
339 }
340
341 /// Prepend `self` with `module`.
342 ///
343 /// Similar to [`include_module`](Module::include_module), but inserts
344 /// `module` as if it were a subclass in the inheritance chain.
345 ///
346 /// # Examples
347 ///
348 /// ```
349 /// use magnus::{function, prelude::*, rb_assert, Error, RClass, Ruby};
350 ///
351 /// fn test(ruby: &Ruby) -> Result<i64, Error> {
352 /// Ok(ruby.call_super::<_, i64>(())? + 2)
353 /// }
354 ///
355 /// fn example(ruby: &Ruby) -> Result<(), Error> {
356 /// let module = ruby.module_new();
357 /// module.define_method("test", function!(test, 0))?;
358 ///
359 /// let class: RClass = ruby.eval(
360 /// r#"
361 /// class Example
362 /// def test
363 /// 40
364 /// end
365 /// end
366 /// Example
367 /// "#,
368 /// )?;
369 /// class.prepend_module(module)?;
370 ///
371 /// let obj = class.new_instance(())?;
372 /// rb_assert!("obj.test == 42", obj);
373 ///
374 /// Ok(())
375 /// }
376 /// # Ruby::init(example).unwrap()
377 /// ```
378 fn prepend_module(self, module: RModule) -> Result<(), Error> {
379 protect(|| {
380 unsafe { rb_prepend_module(self.as_rb_value(), module.as_rb_value()) };
381 Ruby::get_with(self).qnil()
382 })?;
383 Ok(())
384 }
385
386 /// Set the value for the constant `name` within `self`'s scope.
387 ///
388 /// # Examples
389 ///
390 /// ```
391 /// use magnus::{rb_assert, Error, Module, Ruby};
392 ///
393 /// fn example(ruby: &Ruby) -> Result<(), Error> {
394 /// ruby.class_array().const_set("EXAMPLE", 42)?;
395 ///
396 /// rb_assert!(ruby, "Array::EXAMPLE == 42");
397 ///
398 /// Ok(())
399 /// }
400 /// # Ruby::init(example).unwrap()
401 /// ```
402 fn const_set<T, U>(self, name: T, value: U) -> Result<(), Error>
403 where
404 T: IntoId,
405 U: IntoValue,
406 {
407 let handle = Ruby::get_with(self);
408 let id = name.into_id_with(&handle);
409 let val = value.into_value_with(&handle);
410 protect(|| {
411 unsafe { rb_const_set(self.as_rb_value(), id.as_rb_id(), val.as_rb_value()) };
412 handle.qnil()
413 })?;
414 Ok(())
415 }
416
417 /// Get the value for the constant `name` within `self`'s scope.
418 ///
419 /// # Examples
420 ///
421 /// ```
422 /// use magnus::{rb_assert, Error, Module, RClass, Ruby, Value};
423 ///
424 /// fn example(ruby: &Ruby) -> Result<(), Error> {
425 /// ruby.eval::<Value>(
426 /// "
427 /// class Example
428 /// VALUE = 42
429 /// end
430 /// ",
431 /// )?;
432 ///
433 /// let class = ruby.class_object().const_get::<_, RClass>("Example")?;
434 /// rb_assert!(ruby, "klass::VALUE == 42", klass = class);
435 ///
436 /// Ok(())
437 /// }
438 /// # Ruby::init(example).unwrap()
439 /// ```
440 fn const_get<T, U>(self, name: T) -> Result<U, Error>
441 where
442 T: IntoId,
443 U: TryConvert,
444 {
445 debug_assert_value!(self);
446 let id = name.into_id_with(&Ruby::get_with(self));
447 let res =
448 unsafe { protect(|| Value::new(rb_const_get(self.as_rb_value(), id.as_rb_id()))) };
449 res.and_then(TryConvert::try_convert)
450 }
451
452 /// Returns whether or not `self` inherits from `other`.
453 ///
454 /// Classes including a module are considered to inherit from that module.
455 ///
456 /// # Examples
457 ///
458 /// ```
459 /// use magnus::{prelude::*, Error, Module, RClass, Ruby};
460 ///
461 /// fn example(ruby: &Ruby) -> Result<(), Error> {
462 /// let a = RClass::new(ruby.class_object())?;
463 /// let b = RClass::new(a)?;
464 /// assert!(b.is_inherited(a));
465 /// assert!(!a.is_inherited(b));
466 ///
467 /// Ok(())
468 /// }
469 /// # Ruby::init(example).unwrap()
470 /// ```
471 fn is_inherited<T>(self, other: T) -> bool
472 where
473 T: ReprValue + Module,
474 {
475 unsafe {
476 Value::new(rb_class_inherited_p(
477 self.as_rb_value(),
478 other.as_rb_value(),
479 ))
480 .to_bool()
481 }
482 }
483
484 /// Return the classes and modules `self` inherits, includes, or prepends.
485 ///
486 /// # Examples
487 ///
488 /// ```
489 /// use magnus::{rb_assert, Error, Module, Ruby};
490 ///
491 /// fn example(ruby: &Ruby) -> Result<(), Error> {
492 /// let ary = ruby.class_string().ancestors();
493 ///
494 /// rb_assert!(
495 /// ruby,
496 /// "ary == [String, Comparable, Object, Kernel, BasicObject]",
497 /// ary,
498 /// );
499 ///
500 /// Ok(())
501 /// }
502 /// # Ruby::init(example).unwrap()
503 /// ```
504 fn ancestors(self) -> RArray {
505 unsafe { RArray::from_rb_value_unchecked(rb_mod_ancestors(self.as_rb_value())) }
506 }
507
508 /// Define a method in `self`'s scope.
509 ///
510 /// # Examples
511 ///
512 /// ```
513 /// use magnus::{method, rb_assert, Error, Module, Ruby};
514 ///
515 /// fn escape_unicode(s: String) -> String {
516 /// s.escape_unicode().to_string()
517 /// }
518 ///
519 /// fn example(ruby: &Ruby) -> Result<(), Error> {
520 /// ruby.class_string()
521 /// .define_method("escape_unicode", method!(escape_unicode, 0))?;
522 ///
523 /// rb_assert!(
524 /// ruby,
525 /// r#""🤖\etest".escape_unicode == "\\u{1f916}\\u{1b}\\u{74}\\u{65}\\u{73}\\u{74}""#,
526 /// );
527 ///
528 /// Ok(())
529 /// }
530 /// # Ruby::init(example).unwrap()
531 /// ```
532 fn define_method<T, M>(self, name: T, func: M) -> Result<(), Error>
533 where
534 T: IntoId,
535 M: Method,
536 {
537 debug_assert_value!(self);
538 let handle = Ruby::get_with(self);
539 let id = name.into_id_with(&handle);
540 protect(|| {
541 unsafe {
542 rb_define_method_id(
543 self.as_rb_value(),
544 id.as_rb_id(),
545 transmute(func.as_ptr()),
546 M::arity().into(),
547 )
548 };
549 handle.qnil()
550 })?;
551 Ok(())
552 }
553
554 /// Define a private method in `self`'s scope.
555 ///
556 /// # Examples
557 ///
558 /// ```
559 /// use magnus::{eval, function, rb_assert, Error, Module, Ruby, Value};
560 ///
561 /// fn percent_encode(c: char) -> String {
562 /// if c.is_ascii_alphanumeric() || c == '-' || c == '_' || c == '.' || c == '~' {
563 /// String::from(c)
564 /// } else {
565 /// format!("%{:X}", c as u32)
566 /// }
567 /// }
568 ///
569 /// fn example(ruby: &Ruby) -> Result<(), Error> {
570 /// ruby.class_string()
571 /// .define_private_method("percent_encode_char", function!(percent_encode, 1))?;
572 ///
573 /// ruby.eval::<Value>(
574 /// r#"
575 /// class String
576 /// def percent_encode
577 /// chars.map {|c| percent_encode_char(c)}.join("")
578 /// end
579 /// end
580 /// "#,
581 /// )?;
582 ///
583 /// rb_assert!(ruby, r#""foo bar".percent_encode == "foo%20bar""#);
584 ///
585 /// assert!(eval::<bool>(r#"" ".percent_encode_char(" ")"#)
586 /// .unwrap_err()
587 /// .is_kind_of(ruby.exception_no_method_error()));
588 ///
589 /// Ok(())
590 /// }
591 /// # Ruby::init(example).unwrap()
592 /// ```
593 fn define_private_method<M>(self, name: &str, func: M) -> Result<(), Error>
594 where
595 M: Method,
596 {
597 debug_assert_value!(self);
598 let name = CString::new(name).unwrap();
599 protect(|| {
600 unsafe {
601 rb_define_private_method(
602 self.as_rb_value(),
603 name.as_ptr(),
604 transmute(func.as_ptr()),
605 M::arity().into(),
606 )
607 };
608 Ruby::get_with(self).qnil()
609 })?;
610 Ok(())
611 }
612
613 /// Define a protected method in `self`'s scope.
614 ///
615 /// # Examples
616 ///
617 /// ```
618 /// use magnus::{method, rb_assert, Error, Module, Ruby, Value};
619 ///
620 /// fn escape_unicode(s: String) -> String {
621 /// s.escape_unicode().to_string()
622 /// }
623 ///
624 /// fn is_invisible(c: char) -> bool {
625 /// c.is_control() || c.is_whitespace()
626 /// }
627 ///
628 /// fn example(ruby: &Ruby) -> Result<(), Error> {
629 /// ruby.class_string()
630 /// .define_method("escape_unicode", method!(escape_unicode, 0))?;
631 /// ruby.class_string()
632 /// .define_protected_method("invisible?", method!(is_invisible, 0))?;
633 ///
634 /// ruby.eval::<Value>(
635 /// r#"
636 /// class String
637 /// def escape_invisible
638 /// chars.map {|c| c.invisible? ? c.escape_unicode : c}.join("")
639 /// end
640 /// end
641 /// "#,
642 /// )?;
643 ///
644 /// rb_assert!(
645 /// ruby,
646 /// r#""🤖\tfoo bar".escape_invisible == "🤖\\u{9}foo\\u{20}bar""#,
647 /// );
648 ///
649 /// assert!(ruby
650 /// .eval::<bool>(r#"" ".invisible?"#)
651 /// .unwrap_err()
652 /// .is_kind_of(ruby.exception_no_method_error()));
653 ///
654 /// Ok(())
655 /// }
656 /// # Ruby::init(example).unwrap()
657 /// ```
658 fn define_protected_method<M>(self, name: &str, func: M) -> Result<(), Error>
659 where
660 M: Method,
661 {
662 debug_assert_value!(self);
663 let name = CString::new(name).unwrap();
664 protect(|| {
665 unsafe {
666 rb_define_protected_method(
667 self.as_rb_value(),
668 name.as_ptr(),
669 transmute(func.as_ptr()),
670 M::arity().into(),
671 )
672 };
673 Ruby::get_with(self).qnil()
674 })?;
675 Ok(())
676 }
677
678 /// Define public accessor methods for the attribute `name`.
679 ///
680 /// `name` should be **without** the preceding `@`.
681 ///
682 /// # Examples
683 ///
684 /// ```
685 /// use magnus::{eval, prelude::*, rb_assert, Attr, Error, Module, RClass, Ruby, Value};
686 ///
687 /// fn example(ruby: &Ruby) -> Result<(), Error> {
688 /// let class = RClass::new(ruby.class_object())?;
689 /// class.define_attr("example", Attr::ReadWrite)?;
690 ///
691 /// let obj = class.new_instance(())?;
692 /// let _: Value = eval!(ruby, "obj.example = 42", obj)?;
693 /// rb_assert!(ruby, "obj.example == 42", obj);
694 ///
695 /// Ok(())
696 /// }
697 /// # Ruby::init(example).unwrap()
698 /// ```
699 fn define_attr<T>(self, name: T, rw: Attr) -> Result<(), Error>
700 where
701 T: IntoId,
702 {
703 let handle = Ruby::get_with(self);
704 let id = name.into_id_with(&handle);
705 protect(|| {
706 unsafe {
707 rb_attr(
708 self.as_rb_value(),
709 id.as_rb_id(),
710 rw.is_read() as c_int,
711 rw.is_write() as c_int,
712 0,
713 )
714 };
715 handle.qnil()
716 })?;
717 Ok(())
718 }
719
720 /// Alias the method `src` of `self` as `dst`.
721 ///
722 /// # Examples
723 ///
724 /// ```
725 /// use magnus::{function, prelude::*, rb_assert, Error, Module, RClass, Ruby};
726 ///
727 /// fn test() -> i64 {
728 /// 42
729 /// }
730 ///
731 /// fn example(ruby: &Ruby) -> Result<(), Error> {
732 /// let class = RClass::new(ruby.class_object())?;
733 /// class.define_method("test", function!(test, 0))?;
734 /// class.define_alias("example", "test")?;
735 ///
736 /// let obj = class.new_instance(())?;
737 /// rb_assert!(ruby, "obj.example == 42", obj);
738 ///
739 /// Ok(())
740 /// }
741 /// # Ruby::init(example).unwrap()
742 /// ```
743 fn define_alias<T, U>(self, dst: T, src: U) -> Result<(), Error>
744 where
745 T: IntoId,
746 U: IntoId,
747 {
748 let handle = Ruby::get_with(self);
749 let d_id = dst.into_id_with(&handle);
750 let s_id = src.into_id_with(&handle);
751 protect(|| {
752 unsafe { rb_alias(self.as_rb_value(), d_id.as_rb_id(), s_id.as_rb_id()) };
753 handle.qnil()
754 })?;
755 Ok(())
756 }
757}
758
759/// Argument for [`define_attr`](Module::define_attr).
760#[derive(Clone, Copy, Debug)]
761pub enum Attr {
762 /// Define a reader method like `name`.
763 Read,
764 /// Define a writer method like `name=`.
765 Write,
766 /// Define both reader and writer methods like `name` and `name=`.
767 ReadWrite,
768}
769
770impl Attr {
771 fn is_read(self) -> bool {
772 match self {
773 Attr::Read | Attr::ReadWrite => true,
774 Attr::Write => false,
775 }
776 }
777
778 fn is_write(self) -> bool {
779 match self {
780 Attr::Write | Attr::ReadWrite => true,
781 Attr::Read => false,
782 }
783 }
784}
785
786/// # Core Modules
787///
788/// Functions to access Ruby's built-in modules.
789///
790/// See also [`Ruby::define_module`] and the [`module`](self) module.
791impl Ruby {
792 /// Return Ruby's `Comparable` module.
793 ///
794 /// # Examples
795 ///
796 /// ```
797 /// use magnus::{rb_assert, Error, Ruby};
798 ///
799 /// fn example(ruby: &Ruby) -> Result<(), Error> {
800 /// rb_assert!(ruby, "md == Comparable", md = ruby.module_comparable());
801 ///
802 /// Ok(())
803 /// }
804 /// # Ruby::init(example).unwrap()
805 /// ```
806 #[inline]
807 pub fn module_comparable(&self) -> RModule {
808 unsafe { RModule::from_rb_value_unchecked(rb_mComparable) }
809 }
810
811 /// Return Ruby's `Enumerable` module.
812 ///
813 /// # Examples
814 ///
815 /// ```
816 /// use magnus::{rb_assert, Error, Ruby};
817 ///
818 /// fn example(ruby: &Ruby) -> Result<(), Error> {
819 /// rb_assert!(ruby, "md == Enumerable", md = ruby.module_enumerable());
820 ///
821 /// Ok(())
822 /// }
823 /// # Ruby::init(example).unwrap()
824 /// ```
825 #[inline]
826 pub fn module_enumerable(&self) -> RModule {
827 unsafe { RModule::from_rb_value_unchecked(rb_mEnumerable) }
828 }
829
830 /// Return Ruby's `Errno` module.
831 ///
832 /// # Examples
833 ///
834 /// ```
835 /// use magnus::{rb_assert, Error, Ruby};
836 ///
837 /// fn example(ruby: &Ruby) -> Result<(), Error> {
838 /// rb_assert!(ruby, "md == Errno", md = ruby.module_errno());
839 ///
840 /// Ok(())
841 /// }
842 /// # Ruby::init(example).unwrap()
843 /// ```
844 #[inline]
845 pub fn module_errno(&self) -> RModule {
846 unsafe { RModule::from_rb_value_unchecked(rb_mErrno) }
847 }
848
849 /// Return Ruby's `FileTest` module.
850 ///
851 /// # Examples
852 ///
853 /// ```
854 /// use magnus::{rb_assert, Error, Ruby};
855 ///
856 /// fn example(ruby: &Ruby) -> Result<(), Error> {
857 /// rb_assert!(ruby, "md == FileTest", md = ruby.module_file_test());
858 ///
859 /// Ok(())
860 /// }
861 /// # Ruby::init(example).unwrap()
862 /// ```
863 #[inline]
864 pub fn module_file_test(&self) -> RModule {
865 unsafe { RModule::from_rb_value_unchecked(rb_mFileTest) }
866 }
867
868 /// Return Ruby's `GC` module.
869 ///
870 /// # Examples
871 ///
872 /// ```
873 /// use magnus::{rb_assert, Error, Ruby};
874 ///
875 /// fn example(ruby: &Ruby) -> Result<(), Error> {
876 /// rb_assert!(ruby, "md == GC", md = ruby.module_gc());
877 ///
878 /// Ok(())
879 /// }
880 /// # Ruby::init(example).unwrap()
881 /// ```
882 #[inline]
883 pub fn module_gc(&self) -> RModule {
884 unsafe { RModule::from_rb_value_unchecked(rb_mGC) }
885 }
886
887 /// Return Ruby's `Kernel` module.
888 ///
889 /// # Examples
890 ///
891 /// ```
892 /// use magnus::{rb_assert, Error, Ruby};
893 ///
894 /// fn example(ruby: &Ruby) -> Result<(), Error> {
895 /// rb_assert!(ruby, "md == Kernel", md = ruby.module_kernel());
896 ///
897 /// Ok(())
898 /// }
899 /// # Ruby::init(example).unwrap()
900 /// ```
901 #[inline]
902 pub fn module_kernel(&self) -> RModule {
903 unsafe { RModule::from_rb_value_unchecked(rb_mKernel) }
904 }
905
906 /// Return Ruby's `Math` module.
907 ///
908 /// # Examples
909 ///
910 /// ```
911 /// use magnus::{rb_assert, Error, Ruby};
912 ///
913 /// fn example(ruby: &Ruby) -> Result<(), Error> {
914 /// rb_assert!(ruby, "md == Math", md = ruby.module_math());
915 ///
916 /// Ok(())
917 /// }
918 /// # Ruby::init(example).unwrap()
919 /// ```
920 #[inline]
921 pub fn module_math(&self) -> RModule {
922 unsafe { RModule::from_rb_value_unchecked(rb_mMath) }
923 }
924
925 /// Return Ruby's `Process` module.
926 ///
927 /// # Examples
928 ///
929 /// ```
930 /// use magnus::{rb_assert, Error, Ruby};
931 ///
932 /// fn example(ruby: &Ruby) -> Result<(), Error> {
933 /// rb_assert!(ruby, "md == Process", md = ruby.module_process());
934 ///
935 /// Ok(())
936 /// }
937 /// # Ruby::init(example).unwrap()
938 /// ```
939 #[inline]
940 pub fn module_process(&self) -> RModule {
941 unsafe { RModule::from_rb_value_unchecked(rb_mProcess) }
942 }
943
944 /// Return Ruby's `IO::WaitReadable` module.
945 ///
946 /// # Examples
947 ///
948 /// ```
949 /// use magnus::{rb_assert, Error, Ruby};
950 ///
951 /// fn example(ruby: &Ruby) -> Result<(), Error> {
952 /// rb_assert!(
953 /// ruby,
954 /// "md == IO::WaitReadable",
955 /// md = ruby.module_wait_readable()
956 /// );
957 ///
958 /// Ok(())
959 /// }
960 /// # Ruby::init(example).unwrap()
961 /// ```
962 #[inline]
963 pub fn module_wait_readable(&self) -> RModule {
964 unsafe { RModule::from_rb_value_unchecked(rb_mWaitReadable) }
965 }
966
967 /// Return Ruby's `IO::WaitWritable` module.
968 ///
969 /// # Examples
970 ///
971 /// ```
972 /// use magnus::{rb_assert, Error, Ruby};
973 ///
974 /// fn example(ruby: &Ruby) -> Result<(), Error> {
975 /// rb_assert!(
976 /// ruby,
977 /// "md == IO::WaitWritable",
978 /// md = ruby.module_wait_writable()
979 /// );
980 ///
981 /// Ok(())
982 /// }
983 /// # Ruby::init(example).unwrap()
984 /// ```
985 #[inline]
986 pub fn module_wait_writable(&self) -> RModule {
987 unsafe { RModule::from_rb_value_unchecked(rb_mWaitWritable) }
988 }
989}
990
991/// Return Ruby's `Comparable` module.
992///
993/// # Panics
994///
995/// Panics if called from a non-Ruby thread. See [`Ruby::module_comparable`]
996/// for the non-panicking version.
997#[cfg_attr(
998 not(feature = "old-api"),
999 deprecated(note = "please use `Ruby::module_comparable` instead")
1000)]
1001#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1002#[inline]
1003pub fn comparable() -> RModule {
1004 get_ruby!().module_comparable()
1005}
1006
1007/// Return Ruby's `Enumerable` module.
1008///
1009/// # Panics
1010///
1011/// Panics if called from a non-Ruby thread. See [`Ruby::module_enumerable`]
1012/// for the non-panicking version.
1013#[cfg_attr(
1014 not(feature = "old-api"),
1015 deprecated(note = "please use `Ruby::module_enumerable` instead")
1016)]
1017#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1018#[inline]
1019pub fn enumerable() -> RModule {
1020 get_ruby!().module_enumerable()
1021}
1022
1023/// Return Ruby's `Errno` module.
1024///
1025/// # Panics
1026///
1027/// Panics if called from a non-Ruby thread. See [`Ruby::module_errno`] for the
1028/// non-panicking version.
1029#[cfg_attr(
1030 not(feature = "old-api"),
1031 deprecated(note = "please use `Ruby::module_errno` instead")
1032)]
1033#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1034#[inline]
1035pub fn errno() -> RModule {
1036 get_ruby!().module_errno()
1037}
1038
1039/// Return Ruby's `FileTest` module.
1040///
1041/// # Panics
1042///
1043/// Panics if called from a non-Ruby thread. See [`Ruby::module_file_test`] for
1044/// the non-panicking version.
1045#[cfg_attr(
1046 not(feature = "old-api"),
1047 deprecated(note = "please use `Ruby::module_file_test` instead")
1048)]
1049#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1050#[inline]
1051pub fn file_test() -> RModule {
1052 get_ruby!().module_file_test()
1053}
1054
1055/// Return Ruby's `GC` module.
1056///
1057/// # Panics
1058///
1059/// Panics if called from a non-Ruby thread. See [`Ruby::module_gc`] for the
1060/// non-panicking version.
1061#[cfg_attr(
1062 not(feature = "old-api"),
1063 deprecated(note = "please use `Ruby::module_gc` instead")
1064)]
1065#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1066#[inline]
1067pub fn gc() -> RModule {
1068 get_ruby!().module_gc()
1069}
1070
1071/// Return Ruby's `Kernel` module.
1072///
1073/// # Panics
1074///
1075/// Panics if called from a non-Ruby thread. See [`Ruby::module_kernel`] for
1076/// the non-panicking version.
1077#[cfg_attr(
1078 not(feature = "old-api"),
1079 deprecated(note = "please use `Ruby::module_kernel` instead")
1080)]
1081#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1082#[inline]
1083pub fn kernel() -> RModule {
1084 get_ruby!().module_kernel()
1085}
1086
1087/// Return Ruby's `Math` module.
1088///
1089/// # Panics
1090///
1091/// Panics if called from a non-Ruby thread. See [`Ruby::module_math`] for the
1092/// non-panicking version.
1093#[cfg_attr(
1094 not(feature = "old-api"),
1095 deprecated(note = "please use `Ruby::module_math` instead")
1096)]
1097#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1098#[inline]
1099pub fn math() -> RModule {
1100 get_ruby!().module_math()
1101}
1102
1103/// Return Ruby's `Process` module.
1104///
1105/// # Panics
1106///
1107/// Panics if called from a non-Ruby thread. See [`Ruby::module_process`] for
1108/// the non-panicking version.
1109#[cfg_attr(
1110 not(feature = "old-api"),
1111 deprecated(note = "please use `Ruby::module_process` instead")
1112)]
1113#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1114#[inline]
1115pub fn process() -> RModule {
1116 get_ruby!().module_process()
1117}
1118
1119/// Return Ruby's `IO::WaitReadable` module.
1120///
1121/// # Panics
1122///
1123/// Panics if called from a non-Ruby thread. See [`Ruby::module_wait_readable`]
1124/// for the non-panicking version.
1125#[cfg_attr(
1126 not(feature = "old-api"),
1127 deprecated(note = "please use `Ruby::module_wait_readable` instead")
1128)]
1129#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1130#[inline]
1131pub fn wait_readable() -> RModule {
1132 get_ruby!().module_wait_readable()
1133}
1134
1135/// Return Ruby's `IO::WaitWritable` module.
1136///
1137/// # Panics
1138///
1139/// Panics if called from a non-Ruby thread. See [`Ruby::module_wait_writable`]
1140/// for the non-panicking version.
1141#[cfg_attr(
1142 not(feature = "old-api"),
1143 deprecated(note = "please use `Ruby::module_wait_writable` instead")
1144)]
1145#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1146#[inline]
1147pub fn wait_writable() -> RModule {
1148 get_ruby!().module_wait_writable()
1149}