Index: insns.def =================================================================== --- insns.def (revision 24705) +++ insns.def (working copy) @@ -524,7 +524,7 @@ (VALUE ary) (VALUE obj) { - VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"); + VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "*@"); if (NIL_P(tmp)) { tmp = rb_ary_new3(1, ary); } Index: object.c =================================================================== --- object.c (revision 24705) +++ object.c (working copy) @@ -31,7 +31,7 @@ VALUE rb_cTrueClass; VALUE rb_cFalseClass; -static ID id_eq, id_eql, id_match, id_inspect, id_init_copy; +static ID id_eq, id_eql, id_to_a, id_match, id_inspect, id_init_copy; /* * call-seq: @@ -130,7 +130,27 @@ return RTEST(result) ? Qfalse : Qtrue; } +/* + * call-seq: + * a = *obj => obj.to_a or [obj] + * + * Returns obj.to_a if obj responds_to? to_a, otherwise + * the obj wrapped in an array. + */ + VALUE +rb_obj_splat(VALUE obj) +{ + VALUE ary; + if (rb_respond_to(obj, id_to_a)) + ary = rb_funcall(obj, id_to_a, 0); + else { + ary = rb_ary_new3(1, obj); + } + return ary; +} + +VALUE rb_class_real(VALUE cl) { if (cl == 0) @@ -2530,6 +2550,7 @@ rb_define_method(rb_cBasicObject, "equal?", rb_obj_equal, 1); rb_define_method(rb_cBasicObject, "!", rb_obj_not, 0); rb_define_method(rb_cBasicObject, "!=", rb_obj_not_equal, 1); + rb_define_method(rb_cBasicObject, "*@", rb_obj_splat, 0); rb_define_private_method(rb_cBasicObject, "singleton_method_added", rb_obj_dummy, 1); rb_define_private_method(rb_cBasicObject, "singleton_method_removed", rb_obj_dummy, 1); @@ -2686,6 +2707,7 @@ id_eq = rb_intern("=="); id_eql = rb_intern("eql?"); + id_to_a = rb_intern("to_a"); id_match = rb_intern("=~"); id_inspect = rb_intern("inspect"); id_init_copy = rb_intern("initialize_copy"); Index: parse.y =================================================================== --- parse.y (revision 24705) +++ parse.y (working copy) @@ -753,6 +753,7 @@ %nonassoc id_core_define_singleton_method %nonassoc id_core_set_postexe +%token tUSTAR /* unary* */ %token tLAST_TOKEN %% @@ -1775,6 +1776,7 @@ | '-' { ifndef_ripper($$ = '-'); } | '*' { ifndef_ripper($$ = '*'); } | tSTAR { ifndef_ripper($$ = '*'); } + | tUSTAR { ifndef_ripper($$ = tUSTAR); } | '/' { ifndef_ripper($$ = '/'); } | '%' { ifndef_ripper($$ = '%'); } | tPOW { ifndef_ripper($$ = tPOW); } @@ -6466,6 +6468,11 @@ c = tPOW; } else { + if ((lex_state == EXPR_FNAME || lex_state == EXPR_DOT) && + (c == '@')) { + lex_state = EXPR_ARG; + return tUSTAR; + } if (c == '=') { set_yylval_id('*'); lex_state = EXPR_BEG; @@ -9148,6 +9155,7 @@ {tLSHFT, "<<"}, {tRSHFT, ">>"}, {tCOLON2, "::"}, + {tUSTAR, "*@"}, }; #define op_tbl_count (sizeof(op_tbl) / sizeof(op_tbl[0])) Index: id.h =================================================================== --- id.h (revision 24705) +++ id.h (working copy) @@ -67,7 +67,7 @@ id_core_define_method = 372, id_core_define_singleton_method = 373, id_core_set_postexe = 374, - tLAST_TOKEN = 375, + tLAST_TOKEN = 376, #endif idDot2 = tDOT2, idDot3 = tDOT3, @@ -161,7 +161,7 @@ ruby_method_id_check_for(id_core_define_method, 372); ruby_method_id_check_for(id_core_define_singleton_method, 373); ruby_method_id_check_for(id_core_set_postexe, 374); -ruby_method_id_check_for(tLAST_TOKEN, 375); +ruby_method_id_check_for(tLAST_TOKEN, 376); }; #endif Index: vm_insnhelper.c =================================================================== --- vm_insnhelper.c (revision 24705) +++ vm_insnhelper.c (working copy) @@ -245,7 +245,7 @@ VALUE ary = *(cfp->sp - 1); VALUE *ptr; int i; - VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"); + VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "*@"); if (NIL_P(tmp)) { /* do nothing */