From: Nobuyoshi Nakada Date: 2010-12-18T13:47:58+09:00 Subject: [ruby-dev:42787] Re: [Ruby 1.9-Feature#4146][Open] Improvement of Symbol and Proc なかだです。 At Sat, 11 Dec 2010 10:31:10 +0900, SASADA Koichi wrote in [ruby-dev:42750]:: >> 現在Symbol#to_procで %w[12 45 32].map(&:to_i) のようなことはできますが、 >> 引数を付けてメソッドを呼ぶことはできません。Symbolリテラルに引数を付け >> たらその引数と共にメソッドを呼ぶProcを作る構文というのはどうでしょうか。 >> >> %w[12 45 32].map(&:to_i(9)).map(&:*(2)) #=> [22, 82, 58] >> %w[abc def ghi].map(&:[1]) #=> ["b", "e", "h"] > >  メソッドだと,やっぱり書くのがめんどいっすかね? Symbol#callを定義すれば、こうは書けますが p %w[12 45 32].map(&:to_i.(9)).map(&:*.(2)) p %w[abc def ghi].map(&:[].(1)) >  method_missing を使うのはこんな感じでしょうか. いずれにせよ引数はProcの作成前に決定されて固定されています。 map(&:to_i.(9))とmap{|_|_.to_i.(9)}は等価ではありません。 >  新しい文法を考えるのなら,& に対するメソッド呼び出しを,Proc 生成へ変 > 換するってのはあるかもしれない. > > p %w[12 45 32].map(&.to_i(9)).map(& * 2) > p %w[abc def ghi].map(&[1]) > #=> > p %w[12 45 32].map(&lambda{|recv| recv.to_i(9)}).map(&lambda{|recv| recv > * 2}) > p %w[abc def ghi].map(&lambda{|recv| recv[1]}) 単項演算子とかぶる+,-やリテラルとかぶる%,/,[]などはこの構文でも無理です が、これでもいいかも。 diff --git i/parse.y w/parse.y index f2a556a..bd615e5 100644 --- i/parse.y +++ w/parse.y @@ -401,6 +401,9 @@ static NODE *match_op_gen(struct parser_params*,NODE*,NODE*); static ID *local_tbl_gen(struct parser_params*); #define local_tbl() local_tbl_gen(parser) +static NODE *symbol_lambda_gen(struct parser_params *, ID, NODE *); +#define symbol_lambda(mid, args) symbol_lambda_gen(parser, mid, args) + static void fixup_nodes(NODE **); extern int rb_dvar_defined(ID); @@ -2474,6 +2477,27 @@ block_arg : tAMPER arg_value $$ = $2; %*/ } + | tAMPER '.' {$$ = ruby_sourceline;} + operation2 opt_paren_args + { + /*%%%*/ + $$ = symbol_lambda($4, $5); + nd_set_line($$, $3); + $$ = NEW_BLOCK_PASS($$); + /*% + $$ = dispatch3(lambda, $4, $5); + %*/ + } + | tAMPER '.' {$$ = ruby_sourceline;} '[' aref_args ']' + { + /*%%%*/ + $$ = symbol_lambda(tAREF, $5); + nd_set_line($$, $3); + $$ = NEW_BLOCK_PASS($$); + /*% + $$ = dispatch3(lambda, tAREF, $5); + %*/ + } ; opt_block_arg : ',' block_arg @@ -8387,6 +8411,19 @@ arg_append_gen(struct parser_params *parser, NODE *node1, NODE *node2) } static NODE * +symbol_lambda_gen(struct parser_params *parser, ID mid, NODE *args) +{ + const struct vtable *vars = dyna_push(); + ID tid = internal_id(); + NODE *lambda = NEW_LAMBDA(0); + arg_var(tid); + lambda->nd_body = NEW_SCOPE(new_args(NEW_ARGS_AUX(tid, 1), 0, 0, 0, 0), + NEW_CALL(NEW_DVAR(tid), mid, args)); + dyna_pop(vars); + return lambda; +} + +static NODE * splat_array(NODE* node) { if (nd_type(node) == NODE_SPLAT) node = node->nd_head; diff --git i/test/ruby/test_symbol.rb w/test/ruby/test_symbol.rb index 9061f19..443885d 100644 --- i/test/ruby/test_symbol.rb +++ w/test/ruby/test_symbol.rb @@ -88,6 +88,10 @@ class TestSymbol < Test::Unit::TestCase ary_ids = ary.collect{|x| x.object_id } assert_equal ary_ids, ary.collect(&:object_id) end + + assert_equal [2, 4, 6], (1..3).map(&.*(2)) + assert_equal %w(b e h), %w[abc def ghi].map(&.[1]) + assert_equal [11, 41, 29], %w[12 45 32].map(&.to_i(9)) end def test_call -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦