Here's a real-life use case from a rails routes.rb
file.
->(; version_str, content_length_str) do
version_str = File.read(Rails.root.join("VERSION")).strip.freeze
content_length_str = version_str.bytesize.to_s.freeze
get :version, to: proc { [200, { "Content-Length" => content_length_str }, [version_str]] }
end.call
On Rails boot, the lambda is called to install the :version
route by reading the file. The file is only read once per rails instance (to avoid extra IO).
As the app evolves, routes.rb
may grow very large, and another developer (or even my future self) may accidentally assign another variable with the same name (e.g. content_length_str
) in the enclosing scope.
Without the block local variables, the block above will overwrite the values of the enclosing scope, possibly wreaking all kinds of havoc.
So this ruby feature lets you assign variables for temporary calculations without worrying about mutating anything outside.
Of course, there are ways to make this even safer, like performing the calculation in a method instead, but sometimes the logic is simple and you don't want the extra indirection of a method call.