views:

261

answers:

2

Hi,

Ruby 1.9 gives the ability to define variables that are just local to a block and do not close over variables of the same name in an outer scope:

x = 10
proc { |;x|
    x = 20
}.call
x #=> 10

I would like to have this behaviour as default for some blocks i define - without having to use the |;x, y, z| syntax (note the semicolon).

I do not think Ruby allows this natively but is it possible to hack this functionality in ? I have one solution currently but it's quite ugly as it requires checking to see which locals have changed at the end of a block and then reverting them to their values prior to the block. I do not mind if your solution requires specifying which variables are block-local at the start of the block i.e scope(:x) { x = 20 }

thanks!

+2  A: 

x = 10; proc{ |x| x = 20 }.call(0)

bobbywilson0
This is a clever idea, but i don't think i can use it for what i have in mind
banister
could you please clarify the question
bobbywilson0
take a look at this, he talks about doing exactly what you want to http://www.daniel-azuma.com/blog/view/z3bqa0t01uugg1/implementing_dsl_blocks
bobbywilson0
bobbywilson, not quite what i want as `instance_eval` and `mix_eval` still close over local variables. Interesting article though, thanks :)
banister
in the end i made use of your idea, thanks! :)
banister
+3  A: 

The solution I am choosing is based on bobbywilson0's idea. Here is how it works:

x = 99
y = 98

scope { |x, y|
    x = 20
    y = 30
}

x #=> 99
y #=> 98 

This is useful as the variables used in the scope are created at the start of the scope and do not close over any variables defined outside it, they are also GC'd at the end of the scope.

Here is the implementation:

def scope(&block)
    num_required = block.arity >= 0 ? block.arity : ~block.arity
    yield *([nil] * num_required)
end

This solution also takes default values into account making it functionally equivalent to a let* in lisp.

scope { |x = 20, z = (x * 3)| 
    x #=> 20
    z #=> 60
}

I blogged on it here: http://banisterfiend.wordpress.com/2010/01/07/controlling-object-scope-in-ruby-1-9/

banister