Ruby 2.0 Ϊģ¿éÌí¼ÓÁËÒ»¸ö Module#prepend ·½·¨£¬¸ù¾Ý
API ÎĵµµÄÃèÊö£¬ËüÒÔÏà·´µÄ˳Ðò¶Ô²ÎÊýÖðÒ»µ÷Óà prepend_features ·½·¨¡£ºÍÄ£¿é°üº¬ÀàËÆ£¬»á°ÑÒ»¸öÄ£¿éµÄ׿ÏÈÁ´²åÈëµ½ÁíÒ»¸öÄ£¿éµÄ׿ÏÈÁ´ÖУ¬µ«¸úÄ£¿é°üº¬°Ñ׿ÏÈÁ´²åµ½¸ÃÄ£¿éÖ®ºó²»Ò»Ñù£¬Ëü»á°Ñ׿ÏÈÁ´²åµ½¸ÃÄ£¿é֮ǰ¡£ÎÒϲ»¶°ÑÕâ¸öÌØÐÔ½Ð×öÄ£¿éǰÖá£
ÏȾٸöÀý×ÓÀ´ËµÃ÷Ä£¿éǰÖõÄ×÷Ó㬲¢ºÍÄ£¿é°üº¬×÷Á˶Աȡ£ÔÚÕâ¸öÀý×ÓÖУ¬Àà
C ǰÖÃÁËÄ£¿é A ºÍ B£»Àà D °üº¬ÁËÄ£¿é A ºÍ B¡£
module A def foo; 'A' end end module B def foo; 'B' end end class C prepend A, B # Prepending is done by this line def foo; 'C' end end class D include A, B def foo; 'D' end end C.ancestors # => [A, B, C, Object, Kernel, BasicObject] D.ancestors # => [D, A, B, Object, Kernel, BasicObject] C.new.foo # => 'A' D.new.foo # => 'D' |
µÚ 10 ÐУ¬ÎÒÃÇÔÚ C ÖÐǰÖÃÁËÄ£¿é A ºÍ B£¬ÕâÑù A ºÍ B ¾Í²åÈëµ½ C µÄ׿ÏÈÁ´ÖÐÁË¡£´Ó
21 ºÍ 22 ÐÐÖеÄ×¢ÊÍÖУ¬ÎÒÃÇ¿ÉÒÔ¿´µ½£¬ÔÚ C µÄ׿ÏÈÁ´ÖУ¬A ºÍ B λÓÚ C ֮ǰ¡£¶øÔÚ D µÄ׿ÏÈÁ´ÖУ¬A
ºÍ B λÓÚ D Ö®ºó¡£
Õâ¾ÍÊÇΪʲôµÚ 24 ÐУ¬C.new.foo µÄ·µ»ØÖµÊÇ 'A'£¬ÒòΪģ¿é A ǰÖÃÓÚ C£¬Î»ÓÚ׿ÏÈÁ´µÄ×îÇ°Ãæ£¬·½·¨²éÕÒ»áÓÅÏÈÕÒµ½
A ÖÐµÄ foo ·½·¨¡£
ÎÒÃÇ¿´µ½ÁËÄ£¿éǰÖõÄÇ¿´óµÄÌØÐÔ£¬µ«ÒÉÎÊÒ²ËæÖ®¶øÀ´¡£×îÏÔ¶øÒ×¼ûµÄÎÊÌâÊÇ£¬C.ancestors Ϊʲô²»ÊÇ´ÓÀà
C ¿ªÊ¼¡£Òª½â¿ªÕâ¸öÒÉÎÊ£¬Ê×ÏÈÓ¦¸ÃŪÇå³þ prepend ·½·¨¶¼×öÁËÄÄЩ¹¤×÷¡£ÎÒÃǸúµ½Ô´´úÂëÖÐȥһ̽¾¿¾¹£¬ÏÂÃæÊÇ
prepend µÄĬÈÏʵÏÖ Module#prepend ¶ÔÓ¦µÄÔ´´úÂ룺
static VALUE rb_mod_prepend(int argc, VALUE *argv, VALUE module) { int i; ID id_prepend_features, id_prepended; CONST_ID(id_prepend_features, "prepend_features"); CONST_ID(id_prepended, "prepended"); for (i = 0; i < argc; i++) Check_Type(argv[i], T_MODULE); while (argc--) { rb_funcall(argv[argc], id_prepend_features, 1, module); rb_funcall(argv[argc], id_prepended, 1, module); } return module; } |
¿ÉÒÔ¿´µ½£¬ËüµÄÐÐΪºÍ Module#include ·½·¨¼¸ºõÒ»Ñù£¬Ö»²»¹ý»Øµ÷µÄ·½·¨²»Ò»Ñù¡£ÕâÀËü»Øµ÷Á˲ÎÊýÄ£¿éµÄ
prepend_features ·½·¨ºÍ prepended ·½·¨¡£Í¬Ñù£¬Module#prepend_features
²ÅÊÇÕæÕý¸É»îµÄµØ·½£¬ËùÒÔ¸ú½øÈ¥¿´¿´¡£
static VALUE rb_mod_prepend_features(VALUE module, VALUE prepend) { switch (TYPE(prepend)) { case T_CLASS: case T_MODULE: break; default: Check_Type(prepend, T_CLASS); break; } rb_prepend_module(prepend, module); return module; } ¡¡¡¡Ëü×öÁËһЩÀàÐÍ·½ÃæµÄ¼ì²é£¬
È»ºó°Ñ¹¤×÷½»¸øÁË rb_prepend_module º¯Êý£¬ÎÒÃÇ¿´¿´ rb_prepend_module º¯Êý×öÁËʲô¡£ void rb_prepend_module(VALUE klass, VALUE module) { void rb_vm_check_redefinition_by_prepend(VALUE klass); VALUE origin; int changed = 0; rb_frozen_class_p(klass); if (!OBJ_UNTRUSTED(klass)) { rb_secure(4); } Check_Type(module, T_MODULE); OBJ_INFECT(klass, module); origin = RCLASS_ORIGIN(klass); if (origin == klass) { origin = class_alloc(T_ICLASS, klass); RCLASS_SUPER(origin) = RCLASS_SUPER(klass); RCLASS_SUPER(klass) = origin; RCLASS_ORIGIN(klass) = origin; RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass); RCLASS_M_TBL(klass) = st_init_numtable(); st_foreach(RCLASS_M_TBL(origin), move_refined_method, (st_data_t) RCLASS_M_TBL(klass)); } changed = include_modules_at(klass, klass, module); if (changed < 0) rb_raise(rb_eArgError, "cyclic prepend detected"); if (changed) { rb_clear_cache(); rb_vm_check_redefinition_by_prepend(klass); } } |
Õâ¸öº¯Êý×öÁËһЩ¹¤×÷£¬ÎÒÃÇÀ´·ÖÎöһϡ£Ç° 16 Ðж¼ÊÇÔÚ×öһЩÀàÐͼì²éµÈ¹¤×÷£¬ÎÒÃÇÌø¹ý¡£´ÓµÚ 17 ÐпªÊ¼·ÖÎö¡£
Ê×ÏÈ£¬ºê RCLASS_ORIGIN »ñÈ¡ klass µÄ origin ³ÉÔ±£¬²¢ÇÒ°ÑËüºÍ klass
±È½Ï¡£ÎÒÃDz»ÖªµÀ origin ×Ö¶ÎÓÐʲô×÷Óã¬ÎÒÃÇÏȼÙÉè²âÊÔÌõ¼þÎªÕæ£¬¼´ klass µÄ origin
³ÉÔ±Ö¸Ïò×ÔÉí¡£ÎÒÃÇÀ´·ÖÎöһϠif Óï¾äÖеÄÂß¼£º
19 ÐÐΪ klass ´´½¨ÁËÒ»¸öеİüº¬À࣬ÎÒÃǰÑËü³ÆÎªÔʼÀࣻ
20 ~ 21 ÐаÑд´½¨µÄ°üº¬Àà²åÈëµ½ klass ºÍ klass µÄ¸¸ÀàÖм䣻
22 Ðн« klass µÄ origin ³ÉÔ±Ö¸ÏòÁËÐÂÀࣻ
½ÓÏÂÀ´£¬23 ~ 24 ÐÐ°Ñ klass µÄ·½·¨±í×ªÒÆµ½ÐÂÀàÖУ¬²¢Çå¿Õ klass µÄ·½·¨±í£»
×îºó£¬25 ÐÐÓÖ°Ñ klass ÔÏȵķ½·¨±íÖÐµÄ Refined ·½·¨ÒÆÁË»ØÀ´¡£
·ÖÎöÍê if Óï¾ä£¬ÎÒÃǼÌÐøÇ°½ø£¬À´µ½µÚ 28 ÐС£µÈµÈ£¬ÄãºÃÏñ¿´µ½ÁËÊìϤµÄ¶«Î÷¡£Ã»´í£¬ÄǾÍÊÇ include_modules_at
·½·¨¡£ÔÚǰһƪÎÄÕÂÖУ¬ÎÒÃÇÌÖÂÛÁËÕâ¸öº¯Êý£¬ËüÓÃÀ´°üº¬Ä³¸öÄ£¿é¡£Äã¼òÖ±²»¸ÒÏàÐÅ×Ô¼ºµÄÑÛ¾¦£¬Ã÷Ã÷ÊÇÔÚǰÖÃÄ£¿é£¬ÔõôͻȻÓÖ±ä³É°üº¬Ä£¿éÁË£¿
Êǵģ¬Ã»´í£¬Ëü¾ÍÊÇÔÚ°üº¬Ä£¿é¡£±»°üº¬µÄÄ£¿éµÄ׿ÏÈÁ´²åÈëµ½ÁË klass ºÍ klass µÄÔʼÀàÖ®¼ä¡£ÓÉÓÚ
klass ÄÚ²¿µÄ·½·¨±íÒÑ¾×ªÒÆµ½ÉÏÓεÄÔʼÀàÖУ¬ËùÒÔ²åÈëµÄλÖÃÕýºÃºÏÊÊ¡£Ruby ͨ¹ýÕâÖֱ任£¬ÇÉÃîµØ½«Ç°ÖÃÄ£¿éת»¯Îª°üº¬Ä£¿é£¬Ì«°ôÁË¡£
ÏÂÃæÕâ¸öͼÃèÊöÁËÎÄÕ¿ªÍ·µÄÄǸöÀý×ÓÖУ¬Àà C ÖÐ prepend A, B Óï¾äÖ´ÐÐǰºóµÄ״̬£º
¡¡+-----+ +--------+ ¡¡¡¡Before: | C |----->| Object | ¡¡¡¡+-----+ +--------+ ¡¡¡¡+--------------- klass ----------------+ ¡¡¡¡| | ¡¡¡¡v | ¡¡¡¡+-----+ +-----+ +-----+ +-----+ +--------+ ¡¡¡¡After: | C |----->| A |----->| B |----->| C' |+---->| Object | ¡¡¡¡+-----+ +-----+ +-----+ +-----+ +--------+ ¡¡¡¡| ^ ¡¡¡¡| | ¡¡¡¡+--------------- origin ---------------+ |
ÕýÈç֮ǰ·ÖÎöµÄÄÇÑù£¬C' ¾ÍÊÇÄǸöд´½¨µÄ°üº¬À࣬ËüÊÇ C µÄÔʼÀà¡£µ«Èç¹ûÊÇÕâÑùµÄ»°£¬»¹ÊÇÎÞ·¨½âÊÍ֮ǰµÄÒÉÎÊ£ºÎªÊ²Ã´
C.ancestors ²»ÊÇ´ÓÀà C ¿ªÊ¼£¿Òª¸ãÇå³þÕâ¸öÎÊÌ⣬ÎÒÃÇÀ´¿´¿´ C.ancestors ÊÇÈçºÎ¹¤×÷µÄ¡£
ÎÒÃÇÕÒµ½ÁË Module#ancestors µÄÔ´´úÂ룬Ëü¿´ÆðÀ´±È½Ï¼òµ¥£º
VALUE rb_mod_ancestors(VALUE mod) { VALUE p, ary = rb_ary_new(); for (p = mod; p; p = RCLASS_SUPER(p)) { if (FL_TEST(p, FL_SINGLETON)) continue; if (BUILTIN_TYPE(p) == T_ICLASS) { rb_ary_push(ary, RBASIC(p)->klass); } else if (p == RCLASS_ORIGIN(p)) { rb_ary_push(ary, p); } } return ary; } |
¸Ãº¯ÊýÊ×ÏÈ´´½¨ÁËÒ»¸öÊý×飬Ȼºó¶Ô±éÀúÄ£¿éµÄ׿ÏÈÁ´£¬¶Ôÿ¸ö׿ÏÈ£¬Èç¹ûÊǰüº¬Àà»òÕßÔʼÀàÖ¸Ïò×ÔÉí£¬¾Í·ÅÔÚ·µ»ØµÄÊý×éÀïÃæ¡£ÁíÍ⣬Ëü»¹»áÌø¹ýµ¥ÀýÀà¡£
ÖÁ´Ë£¬Ö®Ç°µÄÒÉÎÊÒ²µÃµ½Á˽âÊÍ£¬C.ancestors ²¢Ã»ÓÐ°Ñ C ×ÔÉí°üº¬½øÈ¥£¬ÒòΪËü¼È²»Êǰüº¬À࣬Ҳ²»ÊÇ
origin Ö¸Ïò×ÔÉíµÄÀà¡£¶ø C.ancestors ·µ»ØµÄÊý×éÖÐµÄ C ÆäʵÊÇ C µÄÔʼÀ࣬ͬʱҲÊÇ
C µÄ°üº¬À࣬ËùÒÔËü²ÅÓÐ C Õâ¸öÃû×Ö¡£
Ä£¿éǰÖÃÆäʵҲÊÇͨ¹ýÄ£¿é°üº¬À´Íê³ÉµÄ£¬Ö»²»¹ýÔÚ°üº¬Ö®Ç°×öÁËÒ»Ð©ÌØÊâ´¦Àí£º´´½¨ÁËÒ»¸öÔʼÀ࣬ȻºóÔÚÔʼÀà֮ǰ°üº¬Ä£¿é¡£µ«ÓÉÓÚÔʼÀàÒ²ÊÇÒ»¸ö°üº¬À࣬Òò´Ë±»Ç°ÖÃÄ£¿éµÄij¸ö׿ÏÈ¿ÉÄÜ»áÔ½¹ýÔʼÀ࣬±ÈÈçÏÂÃæÕâ¸öÀý×Ó£º
A = Module.new module B def bar; 'B' end end module C include A, B end class D include A prepend C def bar; 'D' end end D.new.bar # => 'D' |
Àà D ÔÚǰÖÃÄ£¿é C ֮ǰ£¬°üº¬ÁËÄ£¿é A¡£ÏÂͼÖУ¬Ç°Á½¸öÊÇ D ǰÖÃÄ£¿é C ֮ǰ£¬D ºÍ C µÄ׿ÏÈÁ´£¬µÚÈý¸öÊÇ
D ǰÖÃÄ£¿é C Ö®ºó£¬D µÄ׿ÏÈÁ´¡£
+---+ +---+ +--------+ ¡¡¡¡| D |--->| A |--->| Object | ¡¡¡¡+---+ +---+ +--------+ ¡¡¡¡+---+ +---+ +---+ +--------+ ¡¡¡¡| C |--->| A |--->| B |--->| Object | ¡¡¡¡+---+ +---+ +---+ +--------+ ¡¡¡¡| ¡¡¡¡+-----------------+ A ʹµÃ²åÈëµãÒÆµ½ÁË D' µÄºóÃæ ¡¡¡¡| ¡¡¡¡v ¡¡¡¡+---+ +---+ +---+ +---+ +---+ +--------+ ¡¡¡¡| D |--->| C |--->| D'|--->| A |--->| B |+-->| Object | ¡¡¡¡+---+ +---+ +---+ +---+ +---+ +--------+ |
ÕýÈçͼÖбê×¢µÄÄÇÑù£¬Ä£¿é A µÄ´æÔÚʹµÃ²åÈëµãÒÆµ½ÁË D' µÄºóÃæ£¬ËùÒÔ B λÓÚ D' µÄºóÃæ¡£ËùÒÔ
D.new.bar µÄÖµÊÇ 'D' ¶ø²»ÊÇ 'B'¡£
ÏÖÔÚ£¬ÎÒÃÇÀí½âÁËÄ£¿éǰÖÃÔÚ Ruby ÄÚ²¿ÊÇÈçºÎʵÏֵġ£Ä£¿éǰÖ÷dz£ÓÐÓã¬Ö»ÒªÃ÷°×ÁËËüÊÇÈçºÎ¹¤×÷µÄ£¬ÄãÒ»¶¨ÄÜÏëµ½ËüµÄÓÃÎäÖ®µØ¡£
|