[#5563] Non-overridable and non-redefinable methods — Eric Mahurin <eric_mahurin@...>

Lately, I've been thinking about the future of ruby

44 messages 2005/08/19
[#5564] Re: Non-overridable and non-redefinable methods — Austin Ziegler <halostatue@...> 2005/08/19

On 8/19/05, Eric Mahurin <eric_mahurin@yahoo.com> wrote:

[#5571] Re: Non-overridable and non-redefinable methods — Eric Mahurin <eric_mahurin@...> 2005/08/19

--- Austin Ziegler <halostatue@gmail.com> wrote:

[#5574] Re: Non-overridable and non-redefinable methods — TRANS <transfire@...> 2005/08/20

Just wanted to add a few things.

[#5581] Re: Non-overridable and non-redefinable methods — Austin Ziegler <halostatue@...> 2005/08/20

On 8/19/05, TRANS <transfire@gmail.com> wrote:

[#5583] Re: Non-overridable and non-redefinable methods — "David A. Black" <dblack@...> 2005/08/20

Hi --

[#5585] Re: Non-overridable and non-redefinable methods — Eric Mahurin <eric_mahurin@...> 2005/08/20

--- "David A. Black" <dblack@wobblini.net> wrote:

[#5609] Pathname#walk for traversing path nodes (patch) — ES <ruby-ml@...>

Here is a small addition to Pathname against 1.9, probably suited

20 messages 2005/08/22

Re: [BUG] bug in variable assignment

From: Mauricio Fernandez <mfp@...>
Date: 2005-08-08 22:26:11 UTC
List: ruby-core #5540
On Mon, Aug 08, 2005 at 11:36:22AM +0900, nobuyoshi nakada wrote:
> At Mon, 8 Aug 2005 01:42:38 +0900,
> Mauricio Fern疣dez wrote in [ruby-core:05536]:
> > $ ~/ruby1.9/bin/ruby -e "->(&b){}.call(1); p 1 " -e:1: [BUG]
> > bug in variable assignment ruby 1.9.0 (2005-08-06)
> > [i686-linux]
> Does this fix it?
> 
> --- eval.c 5 Aug 2005 00:50:46 -0000 1.811
> +++ eval.c 8 Aug 2005 02:34:27 -0000
> @@ -5270,4 +5270,11 @@ assign(self, lhs, val, pcall)
>  	break;
>  
> + case NODE_BLOCK:
> + lhs = lhs->nd_head;
> + if (nd_type(lhs) == NODE_ARGS) {
> + formal_assign(self, lhs, 1, &val, 0);
> + break;
> + }
> +
>        default:
>  	rb_bug("bug in variable assignment");

Not quite:

$ ./ruby -v -e "->(&b){b.call(1)}.call{|x| puts x}"
ruby 1.9.0 (2005-08-08) [i686-linux]
-e:1: warning: multiple values for a block parameter (0 for 1)
        from -e:1
-e:1: wrong number of arguments (1 for 0) (ArgumentError)
        from -e:1


Here's my attempt to fix it:

Index: parse.y
===================================================================
RCS file: /src/ruby/parse.y,v
retrieving revision 1.400
diff -u -b -p -r1.400 parse.y
--- parse.y	8 Aug 2005 01:21:47 -0000	1.400
+++ parse.y	8 Aug 2005 22:15:07 -0000
@@ -4192,7 +4192,11 @@ f_block_arg	: blkarg_mark tIDENTIFIER
 			    yyerror("block argument must be local variable");
 			else if (!dyna_in_block() && local_id($2))
 			    yyerror("duplicated block argument name");
+			if (dyna_in_block())
+			    $$ = assignable($2, 0);
+			else
 			$$ = NEW_BLOCK_ARG($2);
+			
 		    /*%
 			$$ = $2;
 		    %*/
Index: eval.c
===================================================================
RCS file: /src/ruby/eval.c,v
retrieving revision 1.812
diff -u -b -p -r1.812 eval.c
--- eval.c	8 Aug 2005 13:14:08 -0000	1.812
+++ eval.c	8 Aug 2005 22:15:13 -0000
@@ -4893,6 +4893,13 @@ rb_yield_0(val, self, klass, flags, aval
 		}
 		formal_assign(self, var, RARRAY(val)->len, RARRAY(val)->ptr, 0);
 	    }
+	    else if (nd_type(var) == NODE_BLOCK) {
+		if (var->nd_next) {
+		    bvar = var->nd_next->nd_head;
+		}
+		var = var->nd_head;
+		goto block_var;
+	    }
 	    else {
 		int len = 0;
 		if (avalue) {
@@ -5269,13 +5276,6 @@ assign(self, lhs, val, pcall)
 	}
 	break;
 
-      case NODE_BLOCK:
-	lhs = lhs->nd_head;
-	if (nd_type(lhs) == NODE_ARGS) {
-	    formal_assign(self, lhs, 1, &val, 0);
-	    break;
-	}
-
       default:
 	rb_bug("bug in variable assignment");
 	break;


After applying:
$ ./ruby -v -e "->(&b){b.call(1)}.call{|x| puts x}"
ruby 1.9.0 (2005-08-08) [i686-linux]
1
$ ./ruby -v -e "->(a,&b){b.call(a)}.call(2){|x| puts x}"
ruby 1.9.0 (2005-08-08) [i686-linux]
2


I also wrote some tests to make sure the fix is sane enough:


$ cat tester.rb

require 'test/unit'

class Test_Lambda_Parameters < Test::Unit::TestCase
    def test_call_simple
        assert_equal(1, ->(a){ a }.call(1))
        assert_equal([1,2], ->(a,b){ [a,b] }.call(1,2))
        assert_raises(ArgumentError) { ->(a){ }.call(1,2) }
        assert_raises(ArgumentError) { ->(a){ }.call() }
        assert_raises(ArgumentError) { ->(){ }.call(1) }
        assert_raises(ArgumentError) { ->(a,b){ }.call(1,2,3) }
    end

    def test_call_rest_args
        assert_equal([1,2], ->(*a){ a }.call(1,2))
        assert_equal([1,2,[]], ->(a,b,*c){ [a,b,c] }.call(1,2))
        assert_raises(ArgumentError){ ->(a,*b){ }.call() }
    end

    def test_call_opt_args
        assert_equal([1,2,3,4], ->(a,b,c=3,d=4){ [a,b,c,d] }.call(1,2))
        assert_equal([1,2,3,4], ->(a,b,c=0,d=4){ [a,b,c,d] }.call(1,2,3))
        assert_raises(ArgumentError){ ->(a,b=1){ }.call() }
        assert_raises(ArgumentError){ ->(a,b=1){ }.call(1,2,3) }
    end

    def test_call_rest_and_opt
        assert_equal([1,2,3,[]], ->(a,b=2,c=3,*d){ [a,b,c,d] }.call(1))
        assert_equal([1,2,3,[]], ->(a,b=0,c=3,*d){ [a,b,c,d] }.call(1,2))
        assert_equal([1,2,3,[4,5,6]], ->(a,b=0,c=0,*d){ [a,b,c,d] }.call(1,2,3,4,5,6))
        assert_raises(ArgumentError){ ->(a,b=1,*c){ }.call() }
    end

    def test_call_with_block
        f = ->(a,b,c=3,*d,&e){ [a,b,c,d,e.call(d + [a,b,c])] }
        assert_equal([1,2,3,[],6], f.call(1,2){|z| z.inject{|s,x| s+x} } )
        assert_equal(nil, ->(&b){ b }.call)
        foo { puts "bogus block " }
        assert_equal(1, ->(&b){ b.call }.call { 1 })
        b = nil
        assert_equal(1, ->(&b){ b.call }.call { 1 })
        assert_not_nil(b)
    end

    def foo
        assert_equal(nil, ->(&b){ b }.call)
    end

    def test_lambda_as_iterator
        a = 0
        2.times ->(_){ a += 1 }
        assert_equal(a, 2)
    end
end

batsman@tux-chan:/tmp/ruby1.9/ruby.fixed-head$ ./ruby tester.rb
Loaded suite tester
Started
......
Finished in 0.004576 seconds.

6 tests, 24 assertions, 0 failures, 0 errors


-- 
Mauricio Fernandez

In This Thread