[Ruby 1.9-Feature#4146][Open] Improvement of Symbol and Proc

Feature #4146: Improvement of Symbol and Proc
http://redmine.ruby-lang.org/issues/show/4146

起票者: Nobuyoshi N.
ステータス: Open, 優先度: Normal
カテゴリ: core

現在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”]

$B$^$D$b$H(B $B$f$-$R$m$G$9(B

In message “Re: [ruby-dev:42733] [Ruby 1.9-Feature#4146][Open]
Improvement of Symbol and Proc”
on Fri, 10 Dec 2010 20:04:05 +0900, Nobuyoshi N.
[email protected] writes:

|Feature #4146: Improvement of Symbol and Proc
|http://redmine.ruby-lang.org/issues/show/4146

|$B8=:_(BSymbol#to_proc$B$G(B %w[12 45 32].map(&:to_i)
$B$N$h$&$J$3$H$O$G$-$^$9$,!"(B
|$B0z?t$rIU$1$F%a%=%C%I$r8F$V$3$H$O$G$-$^$;$s!#(BSymbol$B%j%F%i%k$K0z?t$rIU$1(B
|$B$?$i$=$N0z?t$H6&$K%a%=%C%I$r8F$V(BProc$B$r:n$k9=J8$H$$$&$N$O$I$&$G$7$g$&$+!#(B
|
| %w[12 45 32].map(&:to_i(9)).map(&:*(2)) #=> [22, 82, 58]
| %w[abc def ghi].map(&:[1]) #=> [“b”, “e”, “h”]

$B$&!<$s!“$”$^$j;?@.$O$7$^$;$s!#9=J8$,J#;($K$J$k3d$KF@$i$l$k%a(B
$B%j%C%H$,8BDjE*$@$+$i$G$9!#(Bmethod_missing$B$J$I$rAH$_9g$o$;$k$H(B
$B;w$?$h$&$J$b$N$,:n$l$=$&$G$9$7!#(B

(2010/12/10 20:04), Nobuyoshi N. wrote:

$B8=:_(BSymbol#to_proc$B$G(B %w[12 45 32].map(&:to_i)
$B$N$h$&$J$3$H$O$G$-$^$9$,!"(B
$B0z?t$rIU$1$F%a%=%C%I$r8F$V$3$H$O$G$-$^$;$s!#(BSymbol$B%j%F%i%k$K0z?t$rIU$1(B
$B$?$i$=$N0z?t$H6&$K%a%=%C%I$r8F$V(BProc$B$r:n$k9=J8$H$$$&$N$O$I$&$G$7$g$&$+!#(B

%w[12 45 32].map(&:to_i(9)).map(&:*(2)) #=> [22, 82, 58]
%w[abc def ghi].map(&:[1]) #=> [“b”, “e”, “h”]

$B!!%a%=%C%I$@$H!$$d$C$Q$j=q$/$N$,$a$s$I$$$C$9$+$M!)(B

class Symbol
def with *args
lambda{|recv|
recv.send(self, *args)
}
end
end

p %w[12 45 32].map(&:to_i.with(9)).map(&:*.with(2))
p %w[abc def ghi].map(&:[].with(1))

$B!!$3$&$$$&$N$b(B curry $B2=$N0l<o$H8@$($k$s$@$m$&$+!)(B

$B!!(Bmethod_missing $B$r;H$&$N$O$3$s$J46$8$G$7$g$&$+!%(B

class ProcMaker
def method_missing sym, *args
lambda{|recv|
recv.send sym, *args
}
end
end

PM = ProcMaker.new

p %w[12 45 32].map(&PM.to_i(9)).map(&PM * 2)
p %w[abc def ghi].map(&PM[1])

$B!!?7$7$$J8K!$r9M$($k$N$J$i!$(B& $B$KBP$9$k%a%=%C%I8F$S=P$7$r!$(BProc
$B@8@.$XJQ(B
$B49$9$k$C$F$N$O$"$k$+$b$7$l$J$$!%(B

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]})

$B$J$+$@$G$9!#(B

At Sat, 11 Dec 2010 10:31:10 +0900,
SASADA Koichi wrote in [ruby-dev:42750]::

$B8=:_(BSymbol#to_proc$B$G(B %w[12 45 32].map(&:to_i)
$B$N$h$&$J$3$H$O$G$-$^$9$,!"(B

$B0z?t$rIU$1$F%a%=%C%I$r8F$V$3$H$O$G$-$^$;$s!#(BSymbol$B%j%F%i%k$K0z?t$rIU$1(B

$B$?$i$=$N0z?t$H6&$K%a%=%C%I$r8F$V(BProc$B$r:n$k9=J8$H$$$&$N$O$I$&$G$7$g$&$+!#(B

%w[12 45 32].map(&:to_i(9)).map(&:*(2)) #=> [22, 82, 58]
%w[abc def ghi].map(&:[1]) #=> [“b”, “e”, “h”]

$B!!%a%=%C%I$@$H!$$d$C$Q$j=q$/$N$,$a$s$I$$$C$9$+$M!)(B

Symbol#call$B$rDj5A$9$l$P!"$3$&$O=q$1$^$9$,(B

p %w[12 45 32].map(&:to_i.(9)).map(&:*.(2))
p %w[abc def ghi].map(&:[].(1))

$B!!(Bmethod_missing $B$r;H$&$N$O$3$s$J46$8$G$7$g$&$+!%(B

$B$$$:$l$K$;$h0z?t$O(BProc$B$N:[email protected]$K7hDj$5$l$F8GDj$5$l$F$$$^$9!#(B
map(&:to_i.(9))$B$H(Bmap{||.to_i.(9)}$B$OEy2A$G$O$"$j$^$;$s!#(B

$B!!?7$7$$J8K!$r9M$($k$N$J$i!$(B& $B$KBP$9$k%a%=%C%I8F$S=P$7$r!$(BProc
$B@8@.$XJQ(B
$B49$9$k$C$F$N$O$"$k$+$b$7$l$J$$!%(B

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]})

$BC19`1i;;;R$H$+$V$k(B+,-$B$d%j%F%i%k$H$+$V$k(B%,/,[]$B$J$I$O$3$N9=J8$G$bL5M}$G$9(B
$B$,!"$3$l$G$b$$$$$+$b!#(B

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($$, $<num>3);
    
  •  $$ = NEW_BLOCK_PASS($$);
    
  •    /*%
    
  •  $$ = dispatch3(lambda, $4, $5);
    
  •    %*/
    
  •    }
    
  • | tAMPER ‘.’ {$$ = ruby_sourceline;} ‘[’ aref_args ‘]’
  •    {
    
  •    /*%%%*/
    
  •  $$ = symbol_lambda(tAREF, $5);
    
  •  nd_set_line($$, $<num>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