From: David Flanagan Date: 2007-12-21T07:14:40+09:00 Subject: Re: named captures assigning to local variables This is a multi-part message in MIME format. --------------060803040705000101050709 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Attached is a variation on my patch that makes it return $~ instead of an array of values. In testing this I remembered that $~[0] is the entire string on the right-hand side, rather than the first captured value, so this return value doesn't actually masquerade as an array of the assigned values. So I'm a little less enthusiastic about this return value. (Shouldn't MatchData be Enumerable, by the way?) David David Flanagan wrote: > Tanaka Akira wrote: >> In article >> , >> David Flanagan writes: >> >>> How about making the return value an array of the captured strings, >>> or nil if there was no match? >> >> Another idea is $~, which is a MatchData or nil. > > That's simpler to implement than what I had done. And in the simple > case when all capturing groups have names, $~ behaves like an array of > the captured values, doesn't it? I think I like this. > > Another option is to raise an exception if the match fails. I can > almost convince myself that this is the right thing to do for this kind > of assignment... But Ruby is usually more forgiving, so probably not. > > Another option is to return an empty array when the pattern fails to > match, indicating that no values were assigned. This follows the > example of: > > x,y = [] > > But then you'd have to test the return value with empty? and would have > to surround the assignment with parentheses, so the syntax becomes much > less pleasant. > > David > > --------------060803040705000101050709 Content-Type: text/plain; name="diffs2" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="diffs2" Index: parse.y =================================================================== --- parse.y (revision 14373) +++ parse.y (working copy) @@ -1781,6 +1781,25 @@ $$ = dispatch2(assign, $1, $3); %*/ } + | regexp '=' arg + { + /*%%%*/ + if (!RTEST($1->nd_lit)) { + /* If the regexp has a syntax error, + just pass it up so the error gets reported. + Otherwise we get a segfault in + reg_named_capture_assign */ + $$ = $1; + } + else { + $$ = reg_named_capture_assign($1->nd_lit, + match_op($3, $1)); + } + /* what's the right thing below? */ + /*% + $$ = dispatch3(binary, $1, ripper_intern("="), $3); + %*/ + } | lhs '=' arg modifier_rescue arg { /*%%%*/ @@ -2131,9 +2150,6 @@ { /*%%%*/ $$ = match_op($1, $3); - if (nd_type($1) == NODE_LIT && TYPE($1->nd_lit) == T_REGEXP) { - $$ = reg_named_capture_assign($1->nd_lit, $$); - } /*% $$ = dispatch3(binary, $1, ripper_intern("=~"), $3); %*/ @@ -8526,6 +8542,7 @@ ))); arg->fail_block = block_append(arg->fail_block, newline_node(node_assign(assignable(var,0), NEW_LIT(Qnil)))); + return ST_CONTINUE; } @@ -8542,23 +8559,15 @@ onig_foreach_name(RREGEXP(regexp)->ptr, reg_named_capture_assign_iter, (void*)&arg); if (arg.num == 0) - return match; + compile_error(PARSER_ARG "regular expression on left of destructuring assignment has no named captures"); return - block_append( - newline_node(match), - NEW_IF(gettable(rb_intern("$~")), - block_append( - newline_node(arg.succ_block), - newline_node( - NEW_CALL( - gettable(rb_intern("$~")), - rb_intern("begin"), - NEW_LIST(NEW_LIT(INT2FIX(0)))))), - block_append( - newline_node(arg.fail_block), - newline_node( - NEW_LIT(Qnil))))); + block_append( + block_append(newline_node(match), + NEW_IF(gettable(rb_intern("$~")), + newline_node(arg.succ_block), + newline_node(arg.fail_block))), + newline_node(gettable(rb_intern("$~")))); } static VALUE --------------060803040705000101050709--