@@ -89,6 +89,13 @@ typedef struct loader_impl_rb_funcall_protect_type
8989 ID id ;
9090} * loader_impl_rb_funcall_protect ;
9191
92+ typedef struct loader_impl_rb_discover_module_protect_type
93+ {
94+ loader_impl impl ;
95+ loader_impl_rb_module rb_module ;
96+ context ctx ;
97+ } * loader_impl_rb_discover_module_protect ;
98+
9299static class_interface rb_class_interface_singleton (void );
93100static object_interface rb_object_interface_singleton (void );
94101static void rb_loader_impl_discover_methods (klass c , VALUE cls , const char * class_name_str , enum class_visibility_id visibility , const char * method_type_str , VALUE methods , int (* register_method )(klass , method ));
@@ -1255,7 +1262,9 @@ loader_handle rb_loader_impl_load_from_file(loader_impl impl, const loader_path
12551262 {
12561263#define rb_str_new_static_size (str ) rb_str_new_static(str, sizeof(str) - 1)
12571264
1258- VALUE wrapped_code = rb_str_plus (rb_str_new_static_size ("module " ), module_name );
1265+ VALUE wrapped_code = rb_str_new_static_size ("require 'rubygems'\n" );
1266+ wrapped_code = rb_str_plus (wrapped_code , rb_str_new_static_size ("module " ));
1267+ wrapped_code = rb_str_plus (wrapped_code , module_name );
12591268 wrapped_code = rb_str_plus (wrapped_code , rb_str_new_static_size ("\n" ));
12601269 wrapped_code = rb_str_plus (wrapped_code , module_data );
12611270 wrapped_code = rb_str_plus (wrapped_code , rb_str_new_static_size ("\nend" ));
@@ -1509,58 +1518,61 @@ void rb_loader_impl_discover_methods(klass c, VALUE cls, const char *class_name_
15091518 VALUE name = rb_sym2str (rb_method );
15101519 const char * method_name_str = RSTRING_PTR (name );
15111520
1512- VALUE instance_method = rb_funcall (cls , rb_intern (method_type_str ), 1 , rb_method );
1513- VALUE parameters = rb_funcallv (instance_method , rb_intern ("parameters" ), 0 , NULL );
1514- size_t args_it , args_count = RARRAY_LEN (parameters );
1515-
1516- log_write ("metacall" , LOG_LEVEL_DEBUG , "Method '%s' inside '%s' of type %s with %" PRIuS " parameters" , method_name_str , class_name_str , method_type_str , args_count );
1517-
1518- /*
1519- * TODO:
1520- * Another alternative (for supporting types), which is not used in the current implementation,
1521- * but it can simplify the parser, it's the following:
1522- *
1523- * - For classes: origin_file, definition_line = MyClass.instance_method(:foo).source_location
1524- * - For plain functions: origin_file, definition_line = method(:foo).source_location
1525- *
1526- * Then:
1527- * method_signature = IO.readlines(origin_file)[definition_line.pred]
1528- *
1529- * Now we have only the method signature, this is going to be less problematic than parsing
1530- * the whole file as we are doing now (although for multi-line signatures it's going to be
1531- * a little bit more complicated...)
1532- *
1533- * We can switch to completely duck typed approach (refactoring the tests) or we can use this
1534- * simplified parsing approach and maintain types
1535- */
1536-
1537- method m = method_create (c ,
1538- method_name_str ,
1539- args_count ,
1540- (method_impl )instance_method ,
1541- visibility ,
1542- SYNCHRONOUS , /* There is not async functions in Ruby */
1543- NULL );
1544-
1545- signature s = method_signature (m );
1546-
1547- for (args_it = 0 ; args_it < args_count ; ++ args_it )
1521+ if (rb_respond_to (cls , RB_SYM2ID (rb_method )))
15481522 {
1549- VALUE parameter_pair = rb_ary_entry (parameters , args_it );
1550-
1551- if (RARRAY_LEN (parameter_pair ) == 2 )
1523+ VALUE instance_method = rb_funcall (cls , rb_intern (method_type_str ), 1 , rb_method );
1524+ VALUE parameters = rb_funcallv (instance_method , rb_intern ("parameters" ), 0 , NULL );
1525+ size_t args_it , args_count = RARRAY_LEN (parameters );
1526+
1527+ log_write ("metacall" , LOG_LEVEL_DEBUG , "Method '%s' inside '%s' of type %s with %" PRIuS " parameters" , method_name_str , class_name_str , method_type_str , args_count );
1528+
1529+ /*
1530+ * TODO:
1531+ * Another alternative (for supporting types), which is not used in the current implementation,
1532+ * but it can simplify the parser, it's the following:
1533+ *
1534+ * - For classes: origin_file, definition_line = MyClass.instance_method(:foo).source_location
1535+ * - For plain functions: origin_file, definition_line = method(:foo).source_location
1536+ *
1537+ * Then:
1538+ * method_signature = IO.readlines(origin_file)[definition_line.pred]
1539+ *
1540+ * Now we have only the method signature, this is going to be less problematic than parsing
1541+ * the whole file as we are doing now (although for multi-line signatures it's going to be
1542+ * a little bit more complicated...)
1543+ *
1544+ * We can switch to completely duck typed approach (refactoring the tests) or we can use this
1545+ * simplified parsing approach and maintain types
1546+ */
1547+
1548+ method m = method_create (c ,
1549+ method_name_str ,
1550+ args_count ,
1551+ (method_impl )instance_method ,
1552+ visibility ,
1553+ SYNCHRONOUS , /* There is not async functions in Ruby */
1554+ NULL );
1555+
1556+ signature s = method_signature (m );
1557+
1558+ for (args_it = 0 ; args_it < args_count ; ++ args_it )
15521559 {
1553- VALUE parameter_name_id = rb_ary_entry (parameter_pair , 1 );
1554- VALUE parameter_name = rb_sym2str (parameter_name_id );
1555- const char * parameter_name_str = RSTRING_PTR (parameter_name );
1560+ VALUE parameter_pair = rb_ary_entry (parameters , args_it );
15561561
1557- signature_set (s , args_it , parameter_name_str , NULL );
1562+ if (RARRAY_LEN (parameter_pair ) == 2 )
1563+ {
1564+ VALUE parameter_name_id = rb_ary_entry (parameter_pair , 1 );
1565+ VALUE parameter_name = rb_sym2str (parameter_name_id );
1566+ const char * parameter_name_str = RSTRING_PTR (parameter_name );
1567+
1568+ signature_set (s , args_it , parameter_name_str , NULL );
1569+ }
15581570 }
1559- }
15601571
1561- if (register_method (c , m ) != 0 )
1562- {
1563- log_write ("metacall" , LOG_LEVEL_ERROR , "Ruby failed to register method '%s' in class '%s'" , method_name_str , class_name_str );
1572+ if (register_method (c , m ) != 0 )
1573+ {
1574+ log_write ("metacall" , LOG_LEVEL_ERROR , "Ruby failed to register method '%s' in class '%s'" , method_name_str , class_name_str );
1575+ }
15641576 }
15651577 }
15661578}
@@ -1587,15 +1599,12 @@ void rb_loader_impl_discover_attributes(klass c, const char *class_name_str, VAL
15871599 }
15881600}
15891601
1590- int rb_loader_impl_discover_module ( loader_impl impl , loader_impl_rb_module rb_module , context ctx )
1602+ static VALUE rb_loader_impl_discover_module_protect ( VALUE args )
15911603{
1592- log_write ("metacall" , LOG_LEVEL_DEBUG , "Ruby loader discovering:" );
1593-
1594- if (rb_module -> empty == 0 )
1595- {
1596- return 0 ;
1597- }
1598-
1604+ loader_impl_rb_discover_module_protect protect = (loader_impl_rb_discover_module_protect )args ;
1605+ loader_impl impl = protect -> impl ;
1606+ loader_impl_rb_module rb_module = protect -> rb_module ;
1607+ context ctx = protect -> ctx ;
15991608 VALUE instance_methods = rb_funcallv (rb_module -> module , rb_intern ("instance_methods" ), 0 , NULL );
16001609 VALUE methods_size = rb_funcallv (instance_methods , rb_intern ("size" ), 0 , NULL );
16011610 int index , size = FIX2INT (methods_size );
@@ -1630,7 +1639,7 @@ int rb_loader_impl_discover_module(loader_impl impl, loader_impl_rb_module rb_mo
16301639 if (scope_define (sp , function_name (f ), v ) != 0 )
16311640 {
16321641 value_type_destroy (v );
1633- return 1 ;
1642+ return INT2NUM ( 1 ) ;
16341643 }
16351644 else
16361645 {
@@ -1640,12 +1649,12 @@ int rb_loader_impl_discover_module(loader_impl impl, loader_impl_rb_module rb_mo
16401649 }
16411650 else
16421651 {
1643- return 1 ;
1652+ return INT2NUM ( 1 ) ;
16441653 }
16451654 }
16461655 else
16471656 {
1648- return 1 ;
1657+ return INT2NUM ( 1 ) ;
16491658 }
16501659 }
16511660 }
@@ -1659,80 +1668,106 @@ int rb_loader_impl_discover_module(loader_impl impl, loader_impl_rb_module rb_mo
16591668 {
16601669 VALUE constant = rb_ary_entry (constants , index );
16611670
1662- if (constant != Qnil )
1671+ if (constant != Qnil && RB_TYPE_P ( constant , T_SYMBOL ) )
16631672 {
1664- if (RB_TYPE_P (constant , T_SYMBOL ))
1665- {
1666- VALUE class_name = rb_sym2str (constant );
1667- const char * class_name_str = RSTRING_PTR (class_name );
1668- VALUE cls = rb_const_get_from (rb_module -> module , rb_intern (class_name_str ));
1669- loader_impl_rb_class rb_cls = malloc (sizeof (struct loader_impl_rb_class_type ));
1670- klass c = class_create (class_name_str , ACCESSOR_TYPE_DYNAMIC , rb_cls , & rb_class_interface_singleton );
1673+ VALUE class_name = rb_sym2str (constant );
1674+ const char * class_name_str = RSTRING_PTR (class_name );
1675+ VALUE cls = rb_const_get_from (rb_module -> module , rb_intern (class_name_str ));
1676+ loader_impl_rb_class rb_cls = malloc (sizeof (struct loader_impl_rb_class_type ));
1677+ klass c = class_create (class_name_str , ACCESSOR_TYPE_DYNAMIC , rb_cls , & rb_class_interface_singleton );
16711678
1672- rb_cls -> class = cls ;
1673- rb_cls -> impl = impl ;
1679+ rb_cls -> class = cls ;
1680+ rb_cls -> impl = impl ;
16741681
1675- /* Discover methods */
1676- VALUE argv [1 ] = { Qtrue }; /* include_superclasses ? Qtrue : Qfalse; */
1677- VALUE methods = rb_class_public_instance_methods (1 , argv , cls ); /* argc, argv, cls */
1678- rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PUBLIC , "instance_method" , methods , & class_register_method );
1682+ /* Discover methods */
1683+ VALUE argv [1 ] = { Qtrue }; /* include_superclasses ? Qtrue : Qfalse; */
1684+ VALUE methods = rb_class_public_instance_methods (1 , argv , cls ); /* argc, argv, cls */
1685+ rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PUBLIC , "instance_method" , methods , & class_register_method );
16791686
1680- methods = rb_class_protected_instance_methods (1 , argv , cls );
1681- rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PROTECTED , "instance_method" , methods , & class_register_method );
1687+ methods = rb_class_protected_instance_methods (1 , argv , cls );
1688+ rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PROTECTED , "instance_method" , methods , & class_register_method );
16821689
1683- methods = rb_class_private_instance_methods (1 , argv , cls );
1684- rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PRIVATE , "instance_method" , methods , & class_register_method );
1690+ methods = rb_class_private_instance_methods (1 , argv , cls );
1691+ rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PRIVATE , "instance_method" , methods , & class_register_method );
16851692
16861693#if RUBY_VERSION_MAJOR == 3 && RUBY_VERSION_MINOR >= 0
1687- methods = rb_obj_public_methods (1 , argv , cls );
1688- rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PUBLIC , "singleton_method" , methods , & class_register_static_method );
1694+ methods = rb_obj_public_methods (1 , argv , cls );
1695+ rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PUBLIC , "singleton_method" , methods , & class_register_static_method );
16891696
1690- methods = rb_obj_protected_methods (1 , argv , cls );
1691- rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PROTECTED , "singleton_method" , methods , & class_register_static_method );
1697+ methods = rb_obj_protected_methods (1 , argv , cls );
1698+ rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PROTECTED , "singleton_method" , methods , & class_register_static_method );
16921699
1693- methods = rb_obj_private_methods (1 , argv , cls );
1694- rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PRIVATE , "singleton_method" , methods , & class_register_static_method );
1700+ methods = rb_obj_private_methods (1 , argv , cls );
1701+ rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PRIVATE , "singleton_method" , methods , & class_register_static_method );
16951702#else
1696- methods = rb_obj_singleton_methods (1 , argv , cls );
1697- rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PUBLIC , "singleton_method " , methods , & class_register_static_method );
1703+ methods = rb_obj_singleton_methods (1 , argv , cls );
1704+ rb_loader_impl_discover_methods (c , cls , class_name_str , VISIBILITY_PUBLIC , "method " , methods , & class_register_static_method );
16981705#endif
16991706
1700- /* Discover attributes */
1701- VALUE static_attributes = rb_mod_class_variables (1 , argv , cls );
1702- rb_loader_impl_discover_attributes (c , class_name_str , static_attributes , & class_register_static_attribute );
1703-
1704- VALUE instance_attributes = rb_obj_instance_variables (cls );
1705- rb_loader_impl_discover_attributes (c , class_name_str , instance_attributes , & class_register_attribute );
1706-
1707- /* Define default constructor. Ruby only supports one constructor, a
1708- * method called 'initialize'. It can have arguments but when inspected via
1709- * reflection, the signature is variadic arguments and cannot be inspected:
1710- *
1711- * MyClass.methods(:initialize).parameters = [[:rest]] # variadic args notation in Ruby
1712- *
1713- * Due to this, we will always register only one default constructor without arguments
1714- * which will take all the arguments when invoking 'new' and apply them as variadic.
1715- */
1716- constructor ctor = constructor_create (0 , VISIBILITY_PUBLIC );
1717-
1718- if (class_register_constructor (c , ctor ) != 0 )
1719- {
1720- log_write ("metacall" , LOG_LEVEL_ERROR , "Failed to register default constructor in class %s" , class_name_str );
1721- }
1707+ /* Discover attributes */
1708+ VALUE static_attributes = rb_mod_class_variables (1 , argv , cls );
1709+ rb_loader_impl_discover_attributes (c , class_name_str , static_attributes , & class_register_static_attribute );
1710+
1711+ VALUE instance_attributes = rb_obj_instance_variables (cls );
1712+ rb_loader_impl_discover_attributes (c , class_name_str , instance_attributes , & class_register_attribute );
1713+
1714+ /* Define default constructor. Ruby only supports one constructor, a
1715+ * method called 'initialize'. It can have arguments but when inspected via
1716+ * reflection, the signature is variadic arguments and cannot be inspected:
1717+ *
1718+ * MyClass.methods(:initialize).parameters = [[:rest]] # variadic args notation in Ruby
1719+ *
1720+ * Due to this, we will always register only one default constructor without arguments
1721+ * which will take all the arguments when invoking 'new' and apply them as variadic.
1722+ */
1723+ constructor ctor = constructor_create (0 , VISIBILITY_PUBLIC );
1724+
1725+ if (class_register_constructor (c , ctor ) != 0 )
1726+ {
1727+ log_write ("metacall" , LOG_LEVEL_ERROR , "Failed to register default constructor in class %s" , class_name_str );
1728+ }
17221729
1723- scope sp = context_scope (ctx );
1724- value v = value_create_class (c );
1730+ scope sp = context_scope (ctx );
1731+ value v = value_create_class (c );
17251732
1726- if (scope_define (sp , class_name_str , v ) != 0 )
1727- {
1728- value_type_destroy (v );
1729- return 1 ;
1730- }
1733+ if (scope_define (sp , class_name_str , v ) != 0 )
1734+ {
1735+ value_type_destroy (v );
1736+ return INT2NUM (1 );
17311737 }
17321738 }
17331739 }
17341740
1735- return 0 ;
1741+ return INT2NUM (0 );
1742+ }
1743+
1744+ int rb_loader_impl_discover_module (loader_impl impl , loader_impl_rb_module rb_module , context ctx )
1745+ {
1746+ struct loader_impl_rb_discover_module_protect_type protect ;
1747+ int state ;
1748+ VALUE result ;
1749+
1750+ log_write ("metacall" , LOG_LEVEL_DEBUG , "Ruby loader discovering:" );
1751+
1752+ if (rb_module -> empty == 0 )
1753+ {
1754+ return 0 ;
1755+ }
1756+
1757+ protect .impl = impl ;
1758+ protect .rb_module = rb_module ;
1759+ protect .ctx = ctx ;
1760+
1761+ result = rb_protect (rb_loader_impl_discover_module_protect , (VALUE )& protect , & state );
1762+
1763+ if (state != 0 )
1764+ {
1765+ log_write ("metacall" , LOG_LEVEL_ERROR , "Ruby module discover failed" );
1766+ rb_loader_impl_print_exception ();
1767+ return 1 ;
1768+ }
1769+
1770+ return NUM2INT (result );
17361771}
17371772
17381773int rb_loader_impl_discover (loader_impl impl , loader_handle handle , context ctx )
0 commit comments