How to make block local variables the default in ruby 1.9?
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/
Syntax for Block Local Variables
Choice B is not valid. As @matt indicated - it is a valid (though obscure) syntax (see here: How to write an inline block to contain local variable scope in Ruby?)
Choice C gives a default value to w
, which is a regular value, while Choice D is a syntax for default keyword argument.
What is the purpose of setting Ruby block local variables when blocks have their own scope already?
Block scopes nest inside their lexically enclosing scope:
foo = :outerfoo
bar = :outerbar
1.times do |;bar|
foo = :innerfoo
bar = :innerbar
baz = :innerbaz
end
foo #=> :innerfoo
bar #=> :outerbar
baz # NameError
You need a way to tell Ruby: "I don't want this variable from the outer scope, I want a fresh one." That's what block local variables do.
Do block-local variables exist just to enhance readability?
The block parameter is a real parameter, while a block local variable is not.
If you give yield
two parameters like this:
def foo
yield("hello", "world")
end
Calling
x = 10
foo do |y; x|
puts x
end
x
is nil
inside the function because only the first argument is assigned to y
, the second argument is discarded.
Calling
x = 10
foo do |y, x|
puts x
end
#=>world
x
gets the parameter correctly as "world"
.
Ruby Blocks, Procs and Local Variables
The Proc.new
call creates a closure for the block that it's given. In creating a closure for the block, the block is bound to the original variables in the scope of the Proc.new
call.
Why is this done?
It allows Ruby blocks to function as closures. Closures are extremely useful, and the Wikipedia entry (linked above) does an excellent job of explaining some of their applications.
How is this done?
This is done in the Ruby VM (in C code) by copying the Ruby control frame that exists before entering the Proc.new
method. The block is then run in the context of this control frame. This effectively copies all of the bindings that are present in this frame. In Ruby 1.8, you can find the code for this in the proc_alloc
function in eval.c
. In Ruby 1.9, you can find this in the proc_new
function in proc.c
.
Ruby struct creation block cannot access variable outside the block
It's because def
keyword starts new local variables scope, so default
local variable isn't visible inside of it. The workaround is to use define_method
, because the block you pass into it is closure:
default = 'test'
A = Struct.new(:a, :b) do
define_method(:initialize) do |*args|
super(*args)
self.b ||= default
end
end
a = A.new
a.b
# => "test"
Ruby 1.9.2: How to change scope/binding of a block
Looks like a GMail issue to me. Inside the blocks, self
will be some object from the GMail gem so that you can have to
, from
, and similar DSL niceties available. You should be able to put self.trial_email
into a local variable and then access that inside the blocks:
email_address = self.trial_email
@email = ::Gmail.connect!(gmail_name, gmail_password) do |gmail|
email = gmail.compose do
to 'trial@domain.com'
from email_address
subject email_address
#...
Related Topics
How to Use Fiddle to Pass or Return a Struct to Native Code
Result.Credit_Card_Verification Is Returning Nil Even on Error in Braintree
How to Programmatically Take Snapshot of Crawled Webpages (In Ruby)
Setting the Environment in Gemfile for Bundling Install/Update Based on a Customize File
How to Trigger Mouse Event in Capybara Test
Why Does Using '-Webkit-Appearance: None' on a Select Option in Osx Make The Text Disappear
Access Localhost on MAC from Xcode? Phonegap Communicating with Ajax to a Local Rails App
An Error Occurred While Installing Curb (0.8.5)
Testing Rake Task with Rspec with Rails Environment
How to Read an Ini File in Ruby
Changing Type of Activerecord Class in Rails with Single Table Inheritance
How to Split a Directory String in Ruby
Get Table Name from Activerecord
Require File Without Executing Code
Ruby Array Concat Versus + Speed
What's The Most Efficient Way Get The First Day of The Current Month