I have a conundrum involving blocks and passing them around, need help solving it

62 Views Asked by At

Ok, so I've build a DSL and part of it requires the user of the DSL to define what I called a 'writer block'

  writer do |data_block|
    CSV.open("data.csv", "wb") do |csv|
      headers_written = false
      data_block do |hash|
        (csv << headers_written && headers_written = true) unless headers_written
        csv << hash.values
      end
    end
  end

The writer block gets called like this:

  def pull_and_store
    raise "No writer detected" unless @writer
    @writer.call( -> (&block) {
      pull(pull_initial,&block)
    })
  end

The problem is two fold, first, is this the best way to handle this kind of thing and second I'm getting a strange error:

undefined method data_block' for Servo_City:Class (NoMethodError)

It's strange becuase I can see data_block right there, or at least it exists before the CSV block at any rate.

What I'm trying to create is a way for the user to write a wrapper block that both wraps around a block and yields a block to the block that is being wrapped, wow that's a mouthful.

2

There are 2 best solutions below

7
On BEST ANSWER

Inner me does not want to write an answer before the question is clarified.
Other me wagers that code examples will help to clarify the problem.


I assume that the writer block has the task of persisting some data. Could you pass the data into the block in an enumerable form? That would allow the DSL user to write something like this:

writer do |data|
  CSV.open("data.csv", "wb") do |csv|
    csv << header_row
    data.each do |hash|
      data_row = hash.values
      csv << data_row
    end
  end
end

No block passing required.

Note that you can pass in a lazy collection if dealing with hugely huge data sets.

Does this solve your problem?

0
On

Trying to open the CSV file every time you want to write a record seems overly complex and likely to cause bad performance (unless writing is intermittent). It will also overwrite the CSV file each time unless you change the file mode from wb to ab.

I think something simple like:

csv = CSV.open('data.csv', 'wb')
csv << headers
writer do |hash|
  csv << hash.values
end

would be something more understandable.