Macros and Syntactic Attributes¶
By default some macros are made automatically available for their use in Boo without importing any namespace. Some of them are equivalent to standard Boo while others are only available when using the BooJs compiler.
Note
Macros, Meta-Methods and AST Attributes are resolved at compile-time, this means that they are executed as part of the compilation and thus not part of the generated JavaScript code. They work by transforming the program syntax tree, refer to the standard Boo documentation to learn more about them.
Macros¶
assert¶
Use this macro to ensure some condition applies when compiling in debug mode. If the
given condition fails it will raise a Boo.AssertionError
exception. When compiling
without the debug switch the assertion is removed from the generated source code.
assert arg > 10
# Raises Boo.AssertionError('arg > 10')
assert arg < 100, 'Argument must be less than 100'
# Raises Boo.AssertionError('Argument must be less than 100')
const¶
Boo’s syntax doesn’t allow to define variables at the module level, the compiler will interpret such declarations as the start of the module entry point. This macro allows to work around this issue and bind static variables to the current module.
namespace MyNS
const foo = 10
# Declares MyNS.foo as an int with a value of 10
const foo as string = 'foo'
# Declares MyNS.foo as a string with a value of 'foo'
global¶
Unlike JavaScript, Boo’s compiler will complain if you reference a symbol that hasn’t
been previously declared either in the current module or imported from another namespace.
In order to integrate Boo code with external symbols defined somewhere else in your
execution environment, the global
macro provides the means to make those symbols
available in the code.
global jQuery # jQuery is available with a type of duck
jQuery('#foo').html('Hi there!')
global MY_FLAG as int # MY_FLAG is available with a type of int
print MY_FLAG + 10
ifdef¶
Allows to define blocks for conditional compilation by evaluating the condition against the compiler defined symbols. You can use your own defined symbols with the ``-D:symbol`.
If the condition evaluates to false the contents of the block are removed from the compilation unit.
ifdef DEBUG:
print "Debug mode enabled"
ifdef not WINDOWS and DEBUG:
print "Compiling on a non-windows system"
js¶
Every now an then there is the odd case where we can’t map some JavaScript code to
BooJs, or perhaps we are just prototyping something and we want to copy-paste some
snippet of code. The js
meta method will include any literal string given as
argument without modifying it. Any other expression will be wrapped in a call to
eval
.
a = 100 + js('10')
js `alert(a)`
# generates:
# var a = 100 + 10
# alert(a)
# We can include multi line snippets too
a = js(`
[ 'foo',
'bar'
]
`)
# Anything other than a string literal is generated with a call to eval
a = 'alert("foo")'
js a
# generates:
# var a = 'alert("foo")';
# eval(a);
match¶
BooJs automatically exposes the match
macro from Boo.Lang.PatternMatching. This
macro allows to use pattern matching in your code completely at compile time. You can
learn a few of the basics from this mailing list message.
new¶
JavaScript allows to instantiate new objects in a variety of ways, when interfacing external code without using type definitions for it we may need to indicate the compiler how it should call a constructor function.
The new
symbol is not actually a macro but a meta-method, the syntax for
applying it is the same as for functions but it’s resolved at compile-time, so it
doesn’t appears in the generate JavaScript code.
Since Boo already has a new
keyword, used to define members with the same name
as one in the inherited type, we can’t use it directly to flag a constructor. To use
it we have to prefix new
with @
to tell the compiler that we are referencing
the meta-method instead of the keyword.
global Coords
obj = Coords(10, 20)
# js: obj = Coords(10, 20);
obj = @new( Coords(10, 20) )
# js: obj = new Coords(10, 20);
preserving¶
Solves the common problem of temporally backing up some variables to perform an action.
x = 'foo'
y = [10, 20]
preserving x, y[1]:
x = 'bar'
y[0] = 50
y[1] = 60
print x # 'foo'
print y # [50, 20]
print¶
The print
macro outputs the given arguments using the console.log
function if
available in your environment.
foo = 'DrSlump'
print "Hello", foo # Hello Drslump
trace¶
Very similar to print
but only outputs when in debug mode. The message is
prefixed with the filename and line number where the macro was used.
trace 'hello there' # filename.boo:11 hello there
with¶
Even though the with
statement is considered evil in modern JavaScript, this macro
serves a similar purpose avoiding the drawbacks of its JavaScript sibling. It sets a
value as default target for expressions without one but does so explicitly by prefixing
the expressions with a dot.
with jQuery:
.each({x| print x}) # Converted to jQuery.each()
each() # Looks for a method named "each"
with foo = jQuery('#foo'):
.html('Hi there!') # Converted to foo.html('Hi there!')
Attributes¶
Extension¶
Like in C# it’s possible to extend a type with new methods without modifying the type’s hierarchy chain. The first argument of the method defined as a extension is the type to which that method should be attached. If the compiler doesn’t find a proper method defined in the extended type it will check the extensions for a proper match.
[extension]
def toISO(date as Date):
return date.getFullYear() + date.getMonth() + date.getDate()
[extension]
def incr(date as Date, seconds as int):
date.setTime( date.getTime() + seconds*1000 )
d = Date()
print d.toISO() # Converted to: print toISO(d)
d.incr(3600) # Converted to: incr(d, 3600)