If you're unfamiliar with Ruby's
DATA constant don't feel too bad, it's an easy one to miss. Not only is it rare to see in the wild but out of the 9 Ruby books I own (and have actually read) only 2 of them even mention this global constant, "Programming Ruby" by Dave Thomas, commonly known as the pickaxe book, and "The Ruby Programming Language" by David Flanagan and Yukihiro Matsumoto (you know, the guy who created the language).
To understand the
DATA constant we first must understand the
__END__ token. If the Ruby interpreter finds an
__END__ token it will stop running the program code. The first time I heard about this the presenter said that the interpreter will "ignore" anything after the token and demoed it by using it to "comment" out a chunk of code at the end of the file. This was a neat trick but unfortunately inaccurate and completely ignored the coolest part of the
I had all but forgotten about
__END__ until @schwad brought it up at his awesome RubyConf talk (I'll post a link once the videos are publicly available). I wont spoil his talk but Nick gave me enough additional information to spark my curiosity and send me down a rabbit hole of Ruby Archaeology.
Turns out the ruby interpreter does just "ignore" anything after the token but will actually treat any after the
__END__ token as data and will take the content and assign it to the
DATA constant. Armed with this information, the DATA constant becomes a lot easier to understand.
DATA is an IO steam. Just like opening a file and reading its contents, you can do the same thing with
So what does this look like in practice? Something like this:
# end_data_demo.rb puts DATA.read.tr("\n", " ") __END__ Look at this data
If you run
ruby end_data_demo.rb in your terminal you'll get "Look at this data" returned.
Pretty cool, right? No? Well I think it is. Look, you can even store YAML in there:
Now you may be thinking, "Ok fine, that kinda cool, but why or when would I actually use this?". Well given the time of the year let me give you a more practical demo.
Many of you are doing Advent of Code. If you're doing it or have done it in Ruby you've probably done something like this to get your puzzles input:
input = File.readlines('.puzzle_input.txt') # Your logic here
this works but requires a separate file for you input. Here's how I'm doing AoC this year:
input = DATA.readlines # My logic here __END__ My puzzle input
One day, one file.
DATA is a pretty cool trick but unfortunately isn't set in a multi-file application... BUT all is not lost. There are still some cool things we can do with
__END__ stay tuned for the post where we'll abuse
__END__ for fun and profit.