| Class | Fluid |
| In: |
lib/fluid.rb
|
| Parent: | Object |
Fluid (dynamically scoped) variables for Ruby. See README.txt.
| Version | = | "1.0.1" |
A global declaration of a fluid variable. After executing this code:
Fluid.defvar(:global, 5)
Fluid.global will normally everywhere have the value 5, unless it‘s changed by assignment or Fluid.let.
However, Fluid.defvar has effect only the first time it‘s executed. That is, given this sequence:
Fluid.defvar(:global, 5) Fluid.defvar(:global, 6666666)
Fluid.global has value 5. The second Fluid.defvar is ignored. The "a-bit-more-clever-fluid-tracing.rb" example shows how this can be useful.
A Fluid.defvar executed while a Fluid.let block is in effect will have no effect:
Fluid.let(:not_global, 1) {
Fluid.defvar(:not_global, 5555) # Fluid.not_global == 1
}
# The defvar has had no effect, so Fluid.not_global
# has no value after the block.
Fluid.defvar can take a block as an argument:
Fluid.defvar(:var) { long_and_expensive_computation }
The block is only executed if its value would be assigned to the variable.
The first argument to Fluid.defvar may not be the name of a global variable.
Puts the variable specifications in effect, then executes the block, undoes the variable specifications, and returns the block‘s value.
The simplest form of variable specification is a variable name (symbol or string). In this case, the variable starts out with the value nil:
Fluid.let(:will_have_value_nil) {...}
You can also specify the initial value of the variable:
Fluid.let(:will_have_value_1, 1) {...}
Multiple variables can be specified in a single let. Each one must be in an array, even if given no value:
Fluid.let([:will_have_value_1, 1],
[:starts_as_nil]) {...}
From the moment the block begins to execute until the moment it returns, getters and setters for the variables are made class methods of Fluid:
Fluid.let(:var, 1) {
Fluid.var # has value 1
Fluid.var = 2 # change value to 2
}
References to the variable needn‘t be in the lexical scope of the Fluid.let. They can be anywhere in the program. (To be more precise: references can be made whenever the original Fluid.let is on the stack.)
When Fluid.let‘s block exits, the value of the variable is no longer accessible through Fluid.var. An attempt to access it will raise a NameError. If, however, there‘s another Fluid.let binding the same name still on the stack, that version‘s value is back in effect. For example:
Fluid.let(:var, 1) { # Fluid.var => 1
Fluid.var = 2 # Fluid.var => 2
Fluid.let(:var, "hello") { # Fluid.var => "hello"
Fluid.var *= 2 # Fluid.var => "hellohello"
} # Fluid.var => 2
} # Fluid.var => raises NameError
Variable values are undone even if the block exits with a throw or an exception.
If a variable name begins with ’$’, Fluid.let realizes it‘s a global variable and gives that variable a new value. No getters or setters are created. The old value is still restored when the block exits.
There may be an argument past the initial value, the value destructor. It may be either a Proc or the name of a method. If it‘s the name of a method, it‘s sent as a message to the value of the second argument. Like this:
Fluid.let(out, File.open("logfile", "w"), :close)
(You wouldn‘t really do that, though, since File.open does the same thing for you.)
If the third argument is a block, it‘s called with the value of the second argument as its single parameter.
Fluid.let(:out, File.open("logfile", 'w'),
proc {|io| io.close}) {...}