I know that Crystal has its macro system for defining code at compile time but is it possible to run code apart from that?
For example, can we do this so that it runs during compilation?
puts "foobar"
Or for a more serious example, can we read from and write to the file system where the compiler is running?
Yes we can! With the help of the run macro method or the system macro method.
Let's have an example that compiles a random greeting into the program each time it is build:
greetings.txt:
Hello
Hey
Hi
greeting.cr:
puts File.read_lines("#{__DIR__}/greetings.txt").sample
greeter.cr:
puts {{run("./greeting").stringify}}
Compile with crystal build greeter.cr, you'll notice that the output stays the same for the compiled binary but is random for each time your recompile it.
As an additional answer to what Jonne said, you can output something at compile time using puts, but inside a macro. For example:
{{ puts "foobar" }}
You'll notice that "foobar" is printed during compilation but the executable does nothing (try it with crystal build foo.cr; ./foo)
Of course just outputting something at compile time isn't very useful, but it's useful when you want to debug some macros in a quick way.
The puts macro method is documented here: http://crystal-lang.org/api/Macros.html#puts%28expression%29%3ANop-instance-method
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With