1

I have a class that stores blocks, and I would like to run a block later. How can I run it?

class StoreBlocks
  @@blockarray = []
  def initialize
    @storedblock = yield
    @@blockarray << self
  end
  attr_reader :storedblock
  def self.getblock
    @@blockarray
  end
end

StoreBlocks.new do
  # cool codey stuff
end

# do other things

How would I run StoreBlocks.getblock[0].storedblock?

sawa
  • 165,429
  • 45
  • 277
  • 381
thesecretmaster
  • 1,950
  • 1
  • 27
  • 39
  • What do you mean by "stored blocks"? Blocks aren't objects, you can't store them. And what do you mean by "run `StoreBlocks.getBlock[0]`? Also, what's the purpose of dereferencing `@@blockarray` but completely ignoring its value on line 2? That's just a no-op and will probably be eliminated by a good optimizing compiler anyway. – Jörg W Mittag Aug 31 '15 at 21:38
  • Line 2 was a typo I have corrected it, and if I am not storing a block, what is `StoreBlocks.getblock[0].storedblock`? – thesecretmaster Aug 31 '15 at 21:40
  • On line 4, you are `yield`ing to the block and storing its return value in `@storedblock`. – Jörg W Mittag Aug 31 '15 at 21:41
  • I don't see reason to downvote, OP probably could do more research himself, but this is legitimate question for me. – Borsunho Aug 31 '15 at 21:43
  • 1
    Class instance variables (e.g., `@blockarray = []`) are generally preferred to class variables. Some Rubiests would never use a class variable. [Here's](http://stackoverflow.com/questions/15773552/ruby-class-instance-variable-vs-class-variable) a good discussion of the differences. – Cary Swoveland Aug 31 '15 at 22:11
  • @CarySwoveland Thanks, thats really interesting – thesecretmaster Aug 31 '15 at 23:32

2 Answers2

1

= yield would assign the return value of passed block, not the block itself. You would need to change your class to something like this:

class StoreBlocks
  attr_accessor :storedblock
  @@blockarray
  def initialize &block
    @storedblock = block
    @@blockarray << self
  end
  def self.getblock
    @@blockarray
  end
end

& means that block passed to initialize will be converted to Proc and assigned to argument named block, and than you can store it in instance variable. You could than call it like:

StoreBlocks.getblock[0].storedblock.call()
Borsunho
  • 1,127
  • 7
  • 21
  • Could be a reader, yes, if you don't want to assign it anymore. When I wrote the answer there wasn't any in your code, so I just wanted to remind you. – Borsunho Aug 31 '15 at 21:47
1

yield will imediately call the block passed to initalize. This means that @storeblock will contain the result of calling yield not the block itself. FYI, you are not putting @storedblock into @@blockarray

If you want to store a block you can do something like this -

class BlockStore
  def initialize
    @blocks ||= []
  end

  def add_block(&block)
    @blocks << block
  end

  def run_all_blocks
    @blocks.each do |block|
      block.call
    end
  end
end

block_store = BlockStore.new
block_store.add_block do
  puts 'Hello!'
end
block_store.add_block do
  puts 'World!'
end
puts 'About to run all blocks'
block_store.run_all_blocks

This gives you an output like the below. I've output 'About to run all blocks' before running the blocks to show that they are stored and then run later -

➜  ruby blocks.rb 
About to run all blocks
Hello!
World!
Chris Wilding
  • 551
  • 3
  • 10