18
The Curious Case of the DATA Constant
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 __END__
token.
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 DATA
.
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.
18