module Crystal::Macros
¶
The Macros
module is a fictitious module used to document macros
and macro methods.
You can invoke a fixed subset of methods on AST nodes at compile-time. These methods
are documented on the classes in this module. Additionally, methods of the
Macros
module are top-level methods that you can invoke, like puts
and run
.
Methods¶
#`(command) : MacroId
¶
(command) : MacroId
Executes a system command and returns the output as a MacroId
.
Gives a compile-time error if the command failed to execute.
#compare_versions(v1 : StringLiteral, v2 : StringLiteral) : NumberLiteral
¶
(v1 : StringLiteral, v2 : StringLiteral) : NumberLiteral
Compares two semantic versions.
Returns -1
, 0
or 1
depending on whether v1 is lower than v2,
equal to v2 or greater than v2.
{{ compare_versions("1.10.0", "1.2.0") }} # => 1
#debug(format = true) : Nop
¶
(format = true) : Nop
Outputs the current macro's buffer to the standard output. Useful for debugging a macro to see what's being generated.
By default, the output is tried to be formatted using Crystal's
formatter, but you can disable this by passing false
to this method.
#env(name) : StringLiteral | NilLiteral
¶
(name) : StringLiteral | NilLiteral
Gets the value of an environment variable at compile-time, or nil
if it doesn't exist.
#flag?(name) : BoolLiteral
¶
(name) : BoolLiteral
Returns whether a compile-time flag is set.
{{ flag?(:x86_64) }} # true or false
#host_flag?(name) : BoolLiteral
¶
(name) : BoolLiteral
Returns whether a compile-time flag
is set for the host platform, which can differ from the target platform
(flag?
) during cross-compilation.
{{ host_flag?(:win32) }} # true or false
#p!(*expressions) : Nop
¶
(*expressions) : Nop
Prints macro expressions together with their values at compile-time. Useful for debugging macros.
#puts(*expressions) : Nop
¶
(*expressions) : Nop
Prints AST nodes at compile-time. Useful for debugging macros.
#read_file(filename) : StringLiteral
¶
(filename) : StringLiteral
Reads a file and returns a StringLiteral
with its contents.
Gives a compile-time error if the file doesn't exist or if reading the file fails.
To read a file relative to where the macro is defined, use:
read_file("#{__DIR__}/some_file.txt")
Note
Relative paths are resolved to the current working directory.
#read_file?(filename) : StringLiteral | NilLiteral
¶
(filename) : StringLiteral | NilLiteral
Same as read_file
, except that nil
is returned on any I/O failure
instead of issuing a compile-time failure.
#run(filename, *args) : MacroId
¶
(filename, *args) : MacroId
Compiles and execute a Crystal program and returns its output
as a MacroId
.
The file denoted by filename must be a valid Crystal program.
This macro invocation passes args to the program as regular
program arguments. The program must output a valid Crystal expression.
This output is the result of this macro invocation, as a MacroId
.
The run
macro is useful when the subset of available macro methods
are not enough for your purposes and you need something more powerful.
With run
you can read files at compile time, connect to the internet
or to a database.
A simple example:
# read.cr
puts File.read(ARGV[0])
# main.cr
macro read_file_at_compile_time(filename)
{{ run("./read", filename).stringify }}
end
puts read_file_at_compile_time("some_file.txt")
The above generates a program that will have the contents of some_file.txt
.
The file, however, is read at compile time and will not be needed at runtime.
Note
the compiler is allowed to cache the executable generated for
filename and only recompile it if any of the files it depends on changes
(their modified time). This is why it's strongly discouraged to use a program
for run
that changes in subsequent compilations (for example, if it executes
shell commands at compile time, or other macro run programs). It's also strongly
discouraged to have a macro run program take a lot of time, because this will
slow down compilation times. Reading files is OK, opening an HTTP connection
at compile-time will most likely result in very slow compilations.
#skip_file : Nop
¶
: Nop
Skips the rest of the file from which it is executed.
Typical usage is to skip files that have platform specific code,
without having to surround the most relevant code in {% if flag?(...) %} ... {% end %}
macro blocks.
Example:
# sth_for_osx.cr
{% skip_file unless flag?(:darwin) %}
# Class FooForMac will only be defined if we're compiling on OS X
class FooForMac
end
#system(command) : MacroId
¶
(command) : MacroId
Executes a system command and returns the output as a MacroId
.
Gives a compile-time error if the command failed to execute.