Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 24177)
+++ include/ruby/intern.h	(working copy)
@@ -491,6 +491,7 @@
 VALUE rb_lastline_get(void);
 void rb_lastline_set(VALUE);
 VALUE rb_sym_all_symbols(void);
+void rb_default_implicit_scope_set(int);
 /* process.c */
 void rb_last_status_set(int status, rb_pid_t pid);
 VALUE rb_last_status_get(void);
Index: eval.c
===================================================================
--- eval.c	(revision 24177)
+++ eval.c	(working copy)
@@ -1024,6 +1024,28 @@
     }
 }
 
+/*
+ *  call-seq:
+ *     let {|x, y, z, ...| block }
+ *
+ *  Invokes the block once.
+ *
+ *     x, y = 0, 1
+ *     let {|x, y = 2|
+ *       x = 3
+ *       p y   #=> 2
+ *     }
+ *     p x     #=> 0
+ *     p y     #=> 1
+ */
+
+static VALUE
+rb_f_let()
+{
+    rb_yield(Qundef);
+    return Qnil;
+}
+
 void
 Init_eval(void)
 {
@@ -1034,6 +1056,7 @@
     rb_define_global_function("fail", rb_f_raise, -1);
 
     rb_define_global_function("global_variables", rb_f_global_variables, 0);	/* in variable.c */
+    rb_define_global_function("let", rb_f_let, 0);
 
     rb_define_global_function("__method__", rb_f_method_name, 0);
     rb_define_global_function("__callee__", rb_f_method_name, 0);
Index: parse.y
===================================================================
--- parse.y	(revision 24177)
+++ parse.y	(working copy)
@@ -231,6 +231,7 @@
     int parser_ruby_sourceline;	/* current line no. */
     rb_encoding *enc;
     rb_encoding *utf8;
+    int implicit_scope;
 
     int parser_yydebug;
 
@@ -407,6 +408,8 @@
 #define local_pop() local_pop_gen(parser)
 static int local_var_gen(struct parser_params*, ID);
 #define local_var(id) local_var_gen(parser, id);
+static int local_var2_gen(struct parser_params*, ID, int*);
+#define local_var2(id, is_dvar) local_var2_gen(parser, id, is_dvar);
 static int arg_var_gen(struct parser_params*, ID);
 #define arg_var(id) arg_var_gen(parser, id)
 static int  local_id_gen(struct parser_params*, ID);
@@ -6113,6 +6116,39 @@
     parser_set_encode(parser, val);
 }
 
+static int
+parser_implicit_scope_length(struct parser_params *parser, const char *name, int len)
+{
+    return len;
+}
+
+static void
+magic_comment_implicit_scope(struct parser_params *parser, const char *name, const char *val)
+{
+    if (!comment_at_top(parser)) {
+	return;
+    }
+    if (rb_memcicmp(val, "on", 2) == 0 ||
+        rb_memcicmp(val, "t", 1) == 0) {
+	parser->implicit_scope = 1;
+    }
+    else if (rb_memcicmp(val, "off", 3) == 0 ||
+             rb_memcicmp(val, "nil", 3) == 0) {
+	parser->implicit_scope = 0;
+    }
+    else {
+	VALUE excargs[3];
+	VALUE rb_make_backtrace(void);
+	VALUE rb_make_exception(int, VALUE*);
+
+	excargs[0] = rb_eArgError;
+	excargs[1] = rb_sprintf("implicit-scope should be on or off: %s", val);
+	excargs[2] = rb_make_backtrace();
+	rb_ary_unshift(excargs[2], rb_sprintf("%s:%d", ruby_sourcefile, ruby_sourceline));
+	rb_exc_raise(rb_make_exception(3, excargs));
+    }
+}
+
 struct magic_comment {
     const char *name;
     rb_magic_comment_setter_t func;
@@ -6122,6 +6158,8 @@
 static const struct magic_comment magic_comments[] = {
     {"coding", magic_comment_encoding, parser_encode_length},
     {"encoding", magic_comment_encoding, parser_encode_length},
+    {"implicit-scope", magic_comment_implicit_scope, parser_implicit_scope_length},
+    {"ruby-implicit-scope-p", magic_comment_implicit_scope, parser_implicit_scope_length},
 };
 #endif
 
@@ -8010,8 +8048,20 @@
 		return NEW_LASGN(id, val);
 	    }
 	    else{
-		dyna_var(id);
-		return NEW_DASGN_CURR(id, val);
+		if (parser->implicit_scope) {
+		    dyna_var(id);
+		    return NEW_DASGN_CURR(id, val);
+		}
+		else {
+		    int is_dvar;
+		    local_var2(id, &is_dvar);
+		    if (is_dvar) {
+			return NEW_DASGN(id, val);
+		    }
+		    else {
+			return NEW_LASGN(id, val);
+		    }
+		}
 	    }
 	}
 	else {
@@ -8789,6 +8839,21 @@
 }
 
 static int
+local_var2_gen(struct parser_params *parser, ID id, int *is_dvar)
+{
+    struct vtable *vars;
+
+    vars = lvtbl->vars;
+    while (vars && POINTER_P(vars->prev)) {
+	vars = vars->prev;
+    }
+
+    *is_dvar = (vars && vars->prev == DVARS_INHERIT);
+    vtable_add(vars, id);
+    return vtable_size(vars) - 1;
+}
+
+static int
 local_id_gen(struct parser_params *parser, ID id)
 {
     struct vtable *vars, *args;
@@ -9619,6 +9684,14 @@
 
 #endif /* !RIPPER */
 
+static int default_implicit_scope = 1;
+
+void
+rb_default_implicit_scope_set(int val)
+{
+    default_implicit_scope = val;
+}
+
 static void
 parser_initialize(struct parser_params *parser)
 {
@@ -9664,6 +9737,7 @@
     parser->heap = NULL;
 #endif
     parser->enc = rb_usascii_encoding();
+    parser->implicit_scope = default_implicit_scope;
 }
 
 #ifdef RIPPER
Index: ruby.c
===================================================================
--- ruby.c	(revision 24177)
+++ ruby.c	(working copy)
@@ -1020,6 +1020,9 @@
 		if (envopt) goto noenvopt_long;
 		opt->dump |= DUMP_BIT(yydebug);
 	    }
+	    else if (strcmp("no-implicit-scope", s) == 0) {
+		rb_default_implicit_scope_set(0);
+	    }
 	    else if (is_option_with_arg("dump", Qfalse, Qfalse)) {
 		ruby_each_words(s, dump_option, &opt->dump);
 	    }
