#! This is a bang path (this won't appear). @# Bangpaths are handled properly. #! This is not a bang path (this will appear). @# This is a comment. This should not appear in the processed output. This is text. It should appear in the processed output. This is a literal at sign: @@. This is a line continuation; @ this will appear on the same line. Note that it will actually eat any white@ space. @# Escape codes. This will appear on one line.@\nThis will appear on a separate line. This is separated by a tab:@\tSee? These are uppercase As (presuming ASCII): A, @\d065, @\x41, @\o101, @('A'). @{ import sys # This is just a normal Python comment. print "This is more text." }@ @# Note the @{ ... }@ convention to suppress the newline following the }. @# Also note that comments are completely tossed: This is not expanded: @(x). @# Examples of manipulating basic variables, also showcasing empy's @# parsing of "simple expressions." @{ import sys, math, string x = 4 s = 'alpha' word = "book" l = [3, 2, 1] def square(n): return n**2 friends = ['Albert', 'Betty', 'Charles', 'Donald'] }@ The basics: The square of @(x) is @(x**2), or @(square(x)). Internal whitespace is fine: @( x ) squared is @( square(x) ). Statements: @{sys.stdout.write("%d**2 = %d" % (x, square(x)))}. Whitespace too: @{ sys.stdout.write("%d**2 = %d (still)" % (x, square(x))) }. @{ print "But only on single-line statement expansions." if 1: print "Internal whitespace on multi-line statements is significant." for i in range(2): print "Normal Python indentation rules must be followed here." }@ Simple expressions: x is @x, l is @l, s is "@s," and @x squared is @square(x). Literals too: x is @x, but would be written @@x. Trailing dots are ignored: The value of x is @x. Quotes outside of expansions are also ignored: This is quoted: "x is @x." @# Whitespace is important in simple expressions. Array subscription: The first element of l is @l[0]. But this is not: The first element of l is not @l [0]. That was equivalent to: @(l) and then [0], not @l[0]. But whitespace can go inside the brackets: @l[0] is @l[ 0 ]. Same with functions: @square(x) is @square( x ). The same applies to the other forms. Involved: The legal digits are @string.digits. More involved: The names of my friends are @string.join(friends, ', '). Following expressions: Pluralize "@word" as "@(word)s," or maybe "@word@ s." By default str is used (@s), but you can use repr if you want (@`s`). Conditional expressions: @(x ? "x is true" : "x is false"). Pluralization: How many words? @x word@(x != 1 ? 's'). Protected expressions: @(foo $ "foo is not defined"). Also here, whitespace isn't important: @(bar$"bar isn't defined either"). The math module has @(math ? "been imported" $ "not been imported"). The re module has @(re ? "been imported" $ "not been imported"). The square root of -1 is @(math.sqrt(-1) $ "not a real number"). To swallow errors, use None: @(buh $ None) [two spaces]. This is self-expanding: @:2 + 2:(this will get replaced with 4): You can expand multiple times: @ @empy.expand("@empy.expand('@:2 + 2:hugalugahglughalug:')") @# Substitutions. Conditional substitution: x is @[if x > 0:greater than zero (@x)]. The same, with spacing: x is @[if x > 0:@ greater than zero (@x)]. First ten squares:@ @[for i in range(10): @(i**2)]. Some digits from the Champernowne constant: 0.@[for i in range(1, 13):@ @i]... Some of my friends: @[for name in friends:@ @name is my friend.@\n]@ Note variables persist just as in Python: My last friend was @name. Some cubes: @[for i in range(5):@ The cube of @i is @(i**3).@\n]@ Using while:@ @{i = 0}@[while i < 10: @(i**2)@{i = i + 1}]. @[macro mak(x, y, z=None):@ x is @x, y is @y@[if z is not None:@ , z is @z]]@ For example: @mak(1, 2); or @mak(1, 2, 'asdf'). @# More complex examples, including classes. @{ class C: def __init__(self, name): self.name = name def greetString(self): return "Hello, %s" % self.name def printGreeting(self): sys.stdout.write("Hello, %s" % self.name) # implicit None return c = C("empy") }@ c's class is @c.__class__.__name__. c's name is @c.name. Method call: @c.greetString(). Note that None is not expanded: @(None) [two spaces]. But the string 'None' is, of course, printed fine: @('None'). So a function can return None for side effects only: @c.printGreeting(). @# Contexts, metaoperations. @{ def context(): return "%s:%d" % empy.identify() import StringIO stringFile = StringIO.StringIO("2 + 2 = @(2 + 2) [@context()].\n") }@ The current context is @context(). File inclusion [@context()]: @empy.include(stringFile)@ Expansion [@context()]: @ @empy.expand("This should be appear [@context()]") @ on the same line as this [@context()]. More expansion [@context()]: @ @{sys.stdout.write(empy.expand("Another expansion [@context()]"))}. This is the next line [@context()]. Quoting: @empy.quote("x when quoted would be '@x' or @x"). More quoting: @empy.quote("This will be @doubled but '''@this is not'''"). @# Diversions. Again, a trailing @ is used to suppress the following newline. A. This text is undiverted. @empy.startDiversion(1)@ C. This text is diverted. @empy.stopDiverting()@ B. This text is also undiverted. @empy.playDiversion(1)@ D. Again, this text is undiverted. @empy.startDiversion('a')@ E. This text is diverted and then undiverted@ @empy.stopDiverting()@ @empy.replayDiversion('a'). @empy.playDiversion('a') (this should appear twice). @empy.startDiversion('q')@ F. This text is diverted and then cancelled. @empy.playDiversion('q')@ G. This text is again undiverted. @empy.startDiversion('x')@ X. This text will be purged and should not appear! @empy.stopDiverting()@ H. There should be one remaining diversion: @empy.getAllDiversions(). @empy.purgeDiversion('x')@ I. But not after purging it: @empy.getAllDiversions(). @{ # Finally, make a manual diversion and manipulate it. empy.createDiversion('z') zDiversion = empy.retrieveDiversion('z') zDiversion.write("J. This should be the final diversion, created manually.\n") empy.playDiversion('z') }@ @# Parsing checks. Blanks: @(''), @(""), @(''''''), @(""""""). Single quotes: @('\''), @("'"), @("""'"""). Double quotes: @("\""), @('"'), @('''"'''). Triple quotes: @("\"\"\""), @('"""'), @('\'\'\''), @("'''"). Quotes surrounded by spaces: @(""" " """), @(''' ' '''). At signs: @('@'), @("@"), @('''@'''), @("""@"""). Close parentheses: @(')'), @(")"), @((")")), @((')')). Close parentheses in quotes: @("')'"), @('\')\''). Close braces with an intervening space: @ @{sys.stdout.write("}")} @{sys.stdout.write('}')}. Repr of a backquote: @`'`'`. Exes: @("?"?'x'), @(0?":":'x'), @("]"?'x'), @(1?"x":"]"). Dollar signs: @("$"$None), @(asdf?"$"$"$"), @(1?asdf$"$"). @# Significators. @%a @%b @%c "x" @%d "x" @%e "x y" @%f "x y" Encountered significators: a and b should be None: @`__a__`, @`__b__` c and d should be 'x': @`__c__`, @`__d__` e and f should be 'x y': @`__e__`, @`__f__` @# Filters. @{import string}@ This line should be in mixed case. @empy.setFilter(string.lower)@ This line should be all lowercase. @empy.setFilter(string.upper)@ This line should be all uppercase (how gauche). @empy.setFilter([empy.LineBufferedFilter(), lambda x: '[%s]\n' % x[:-1]])@ This line should be bracketed. So should this line. @empy.setFilter([empy.SizeBufferedFilter(5), lambda x: '*' + x])@ There should be stars every five characters on this line. @empy.nullFilter()@ This line should not appear at all! @empy.resetFilter()@ This line should be back to mixed case. @# Embedded interpreters. @{ q = 1 }@ Interpreter's q is @q. @{ # The em.py script has to be somewhere in sys.path import em try: i = em.Interpreter() i.string("@{q = 10}") i.string("Embedded interpreter's q is @q.\n") finally: i.shutdown() }@ Interpreter's q is still @q; the embedded interpreter had no effect. @# Finals. @empy.atExit(lambda: empy.string("Version: @empy.VERSION.\n"))@ @empy.atExit(lambda: empy.interpreter.write("This is the second to last line.\n"))@