How would I achieve something like below so that when I set the s
variable within the block, it also sets the @subject
instance variable in my Topic class?
class Topic
def subject(&blk)
blk.call(@subject) if block_given?
@subject unless block_given?
end
end
my_topic = Topic.new
p my_topic.subject #=> nil
my_topic.subject do |s|
s = ['one', 'two', 'three']
s.pop
p s #=> ['one', 'two']
end
p my_topic.subject #=> nil... want it to be ['one, 'two']
You can't do it the way you want. The block argument references the same object as the instance variable, but they are completely different variables and setting one will never set the other. There are two options:
Set the variable to the result of the block, so it would be like:
class Topic
def subject
@subject = yield if block_given?
@subject unless block_given?
end
end
and inside the block:
my_topic.subject do
s = ['one', 'two', 'three']
s.pop
p s #=> ['one', 'two']
s
end
Have the subject
method instance_eval
the block so the block can set the instance variable explicitly
What you want to do is called pass-by-reference. That's not possible in ruby. You have two alternatives:
a) Do @subject = blk.call
and return s from the block. Usually the simplest and cleanest option.
b) Instead of s =
do @subject =
in the block and then use instance_eval(&blk)
instead of blk.call
. This will set the @subject
variable, however it requires the user of the subject method to know about the @subject
variable and it doesn't allow you to call the block multiple times to set different variables.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With