Wednesday, November 16, 2011

Ruby Heredocs in Array Constants

While writing a spec that uses different chunks of csv and txt data I was wondering about the best way to define multi-line strings in array constants.

Normally, I would use Heredoc to define a single multi-line string like this:

CSV_CHUNK = <<-CSV
10, "a", "b"
20, "c", "d"
30, "e", "e"
CSV

Perfect. The unattractiveness starts when adding more chunk definitions. It usually ends up with having CSV_CHUNK_0, CSV_CHUNK_1, CSV_CHUNK_3 and so on in place. Thats a bit unfortunately. For example this hinders to use normal array iteration like each and friends.

So, my question was if there is a way to simply add chunk after chunk to an array. Sure its possible:

chunks = []
chunks <<<<-CSV
10, "a", "b"
20, "c", "d"
30, "e", "f"
CSV
chunks <<<<-CSV
40, "a", "b"
50, "c", "d"
60, "e", "f"
CSV

This is valid Ruby syntax. Actually its just the << method of Array plus the Heredoc syntax. ( Yes, you can add a space inbetween :) )

But, since we are altering a variable we can't use a constant here. To use a constant, we have to do the Heredoc definition inline in the Array declaration:

CHUNKS = [
  <<-CSV ,
10, "a", "b"
20, "c", "d"
30, "e", "f"
  CSV
  <<-CSV ]
40, "a", "b"
50, "c", "d"
60, "e", "f"
   CSV

Although, this looks pretty scary, its again valid Ruby syntax. As many other languages Ruby allows a comma in front of the closing square bracket. We can use this to pretty up this construct and to make it more readable:

CHUNKS = [
  <<-CSV ,
10, "a", "b"
20, "c", "d"
30, "e", "f"
  CSV
  <<-CSV ,
40, "a", "b"
50, "c", "d"
60, "e", "f"
   CSV
]