Coming Soon!
Pandita is getting ready for launch. If you'd like to hear more and be first on the waiting list for Founder plans, then leave your email address below.
Pandita is getting ready for launch. If you'd like to hear more and be first on the waiting list for Founder plans, then leave your email address below.
Get early access and a say in shaping the future of Pandita
Complete our surveyThe Indu programming language is what makes Pandita work. Whether you're creating exercises or apps, you're writing Indu programs. Fortunately, this language was designed just for the web, and to be easy to learn.
There are lots of programming languages available. Why does Pandita include an entirely new one? It's a good question: programming languages are a lot of work to create and learn, there better be a good reason to create one.
Indu is for building simple web apps. Apps, not sites: it should be predominantly interactive, it should do things when a user interacts with it, it should probably save some data. It should not just display content. HTML is already a perfectly good language for that. Ideal web apps for Indu are quite simple. Simple is subjective. A short-hand way of describing that is that Indu is not for building the next Gmail or Instagram. It might be a good way to manage your own to do list, and post your own photos though.
But more than anything else, Indu is for non-programmers. People who have not studied programming or computing, who have no interest in studying programming and computing, but do want to have control over what their computing devices do.
Indu is new. It's still finding it's feet. As you can see there is a lot that it doesn't do yet. Feedback, suggestions and ideas are really valuable. But, the goal of Indu won't change: it'll just get better at being the ideal language for non-programmers to create simple web apps.
In the meantime, this guide is for two audiences. It would be great to have a non-programmer use this to write Indu programs. But until Pandita has better tools, a lot of the early users will be professional programmers, who are interested in new programming languages and creating simple web apps. This guide frequently speaks directly to them.
Everything on the web is made up of HTML. Indu programs are no different. Indu supports HTML directly.
Indu
<p>Hello, world!</p>
Output
Hello, world!
begin site $$src$$ end site
HTML can contain other pieces of HTML, and Indu is no different.
Indu
<header>
<h1>Welcome to My Blog</h1>
<p>This is my blog where I write about my food and holidays, as if it is still 2009.</p>
</header>
Output
This is my blog where I write about my food and holidays, as if it is still 2009.
begin site $$src$$ end site
But Indu is not just HTML. Indu is built around the idea of 'objects.' An object is a part of a program. It can hold data, and also do things: usually to that data. Many programming languages feature objects. Indu's objects are quite a bit simpler than other languages. For any programmers reading along, Indu has no class system and no inheritance. Instead, it uses a Ruby-style mixin system.
In an Indu program, the objects make up the structure of the app that users see and interact with. Objects contain HTML, and other objects.
Indu
begin header
<header>
<h1>Welcome to My Blog</h1>
<p>This is my blog where I write about my food and holidays, as if it is still 2009.</p>
</header>
end header
Output
This is my blog where I write about my food and holidays, as if it is still 2009.
begin site $$src$$ end site
That example doesn't seem to add much though, does it? The advantage with Indu objects, however, is that they can take arguments, and then be re-used.
Indu
begin header
tag is "header"
<h1>#{ title }</h1>
<p>#{ subtitle }</p>
end header
begin site
make using header(title: "My Blog",
subtitle: "This is my blog where I write about my food and holidays, as if it is still 2009")
end site
Output
This is my blog where I write about my food and holidays, as if it is still 2009
$$src$$
This example shows how to create structured HTML: set the `tag`
attribute of an object to a string, and that will be used. This is
great for structured HTML like <ol>
.
There are two ways to create objects in Indu: begin
object
and make object
. These both appear in the
examples above. begin
is used when you want to put
things inside the object. make
is used when the object
is already complete. There is no difference in the object created:
make
is just shorter.
But, just using make
on its own will give you an empty
object. It won't do anything. In practice, you'll use
make
when there is an object that you want to copy with
using
. More on this when we get to mixins.
Learning a language like Indu and a platform like Pandita is best done with examples. Right now there is a small number of examples available, but this will grow!
So far we've created a header with a heading and a subtitle. But both look exactly the same. The web is styled with CSS, and like HTML, Indu has direct support for CSS.
Each object can contain a style
block. Inside this
block, set any styling attributes that you'd like to apply to the
object.
Indu
begin header
begin heading-title
style
font-size is "1.5em"
end style
<h1>#{ title }</h1>
end heading-title
begin heading-subtitle
style
font-size is "0.8em"
end style
<p>#{ subtitle }</p>
end heading-subtitle
end header
begin site
make using header(title: "My Blog",
subtitle: "This is my blog where I write about my food and holidays, as if it is still 2009")
end site
Output
This is my blog where I write about my food and holidays, as if it is still 2009
$$src$$
Any CSS property can be set in a style
block like
this. You can also use maths and functions to calculate a value. More on those
later. One of the most common things you'll do is parameterise the
style.
Indu
begin heading-title
style
font-size is "1.5em"
end style
<h1>#{ text }</h1>
end heading-title
begin heading-subtitle
style
font-size is "0.8em"
end style
<p>#{ text }</p>
end heading-subtitle
begin header
style
font-family is font
end style
<header>
#{ make using heading-title(text: title) }
#{ make using heading-subtitle(text: subtitle) }
</header>
end header
begin site
make using header(title: "My Blog",
subtitle: "This is my blog where I write about my food and holidays, as if it is still 2009",
font: "Verdana")
make using header(title: "Article",
subtitle: "An interesting post I have written.",
font: "Times New Roman")
end site
Output
This is my blog where I write about my food and holidays, as if it is still 2009
An interesting post I have written.
$$src$$
If you're looking to understand how to style your apps, we recommend reading the Mozilla Developer Network articles on learning CSS.
By now you've seen the keyword using
appear in a few
samples of code. using
is one of the main ways that
Indu allows authors to re-use code. Anytime you make
or
begin
an object, you can choose to prepare that object
by using another object, with using
.
-- Creates an object called child from an object called example
make child using example
-- Creates an object without a name from an object called example
make using example
-- Creates an object called child, from example and then adds extras
begin child using example
make extras
end child
-- Creates an object without a name, from example and then adds extras
using example
make extras
end example
using
works by copying everything from the source
object to the new object. If you're a programmer, you might be
thinking this is inheritance: it's not. Once the new object has been
created there is no reference to the source object in it, anywhere.
When using
another object, you can provide
arguments. These are values that will be used in the new object,
after the used object has been copied in. There is an example above
with setting title
, subtitle
and
font
.
-- Syntax
make using example(name: <value>, etc...)
The name
is whatever the used object expects to call
this value.
Mixins have been mentioned a couple of times already. Indu has been
inspired by Ruby here. Mixins are the general form of all code
re-use in Indu. They're fundamental and are used in a number of
places, as well as being directly available to authors. Like
using
a mixin is an object copied into another object,
with optional parameters. In fact, using
is just
syntactical sugar for a mixin.
Indu
begin google-font
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=" & font & "&display=swap" rel="stylesheet">
end google-font
begin site
begin header
with google-font(font: "Fuggles")
style
font-family is "Fuggles"
font-size is "2em"
end style
<h1>Tomorrow and tomorrow and tomorrow</h1>
end header
end site
Output
$$src$$
There's a bit here, but the mixin part is the line with
google-font(font: "Fuggles")
. This uses the
google-font
object created at the top of the example to
insert the HTML to connect to Google Fonts, and request the font
name. The font is then used to set the font-family
.
Any object can be used as a mixin. When using a mixin, it is merged
as if the contents of the mixin were written inline in the target
object, at that point. The style
block is treated
specially: anything in the mixins style block is merged into the
target object's style block, as if it were defined there.
As the example shows, mixins can take arguments. Anything defined in the arguments is mixed into the target object, after the mixin itself is mixed in. That is, arguments don't change the mixin, they only effect this specific use of the mixin.
So far we've used objects and HTML to create and style apps. But these apps don't do anything: you could hardly call them apps. Indu is for web apps, not web sites. To make a site into an app, you have to handle events.
Indu
message is "Ready?"
<p>#{ message }</p>
begin button
<button>Click</button>
style
padding is "0.25em 0.75em"
border is "1px solid black"
end style
when click
set message to "Clicked!"
end click
end button
Output
begin site $$src$$ end site
Events can be handled by an object, when generated, with the syntax
when <event-name>
. There are a lot of
events to reflect all the potentially interesting changes can happen
in a web app. These are all supported. As always, the MDN is the
best reference
to the available events you might want to handle.
The when click
event handler above is actually just an
Indu function. If you're a programmer, you know what a function
is. If not, a function is a way of naming some useful behaviour
often because you want to use it in more than one place.
A function can have any name, and is always defined with
when
. Functions can be defined inside objects, like an
event handler, or outside objects if that makes more sense. As event
handlers, functions are called automatically by Indu. When using
functions directly, they are called with
call
. Functions return the last value, automatically.
Indu
when greeting
"Hello, world!"
end greeting
message is "Ready?"
<p>#{ message }</p>
begin button
<button>Click</button>
style
padding is "0.25em 0.75em"
border is "1px solid black"
end style
when click
set message to call greeting
end click
end button
Output
Ready?
begin site $$src$$ end site
Functions that always return the same value aren't as useful as they could be. Functions can take arguments.
Indu
when factorial(n)
if n > 1
n * call factorial with (n: n - 1)
else
1
end if
end factorial
countdown is 5
<p>#{ call factorial with (n: countdown) }</p>
Output
120
begin site $$src$$ end site
Indu uses named arguments. When defining a function, list the
arguments in parentheses after the function name: when
add(left, right)
. When calling the function, provide named
values for each: call add with (left: 4, right:
6)
. Because the arguments are named you don't need to worry
about order: call add with (right: 6, left: 4)
. Though
in this case, that's a little confusing. If there are no arguments,
then the with ...
part is optional.
If your function is especially short, there is a single-line version
of the function syntax: when name(args) => a single
expression
.
The previous example starts to show some of other sorts of things possible in Indu. In general, functions are where more complex operations will end up.
Indu provides a wide range of built-in operators. Indu also has operator precedence: this is the idea that operators should be performed in a certain order, not just left-to-right. That is, Indu will multiply two numbers before it attempts to add them. Here is a full list of operators, in order of increasing precedence.
&
and &&
: string concatenation&
attaches the strings as
written, &&
will insert a single space between. You
can think of "hello" && "world"
as "hello" & "
" & "world"
.
and
and or
: logicand
checks that both sides are true, and
or
checks that at least one side is. and
will return either false, or the right-most
argument. or
will return either false or the first
value that is equivalent to true.
=
, !=
, >
,
>=
, <
and <=
:
comparisons
+
and -
: addition and subtraction*
and /
: multiplication and division*
is multiplication and
/
is division. These aren't technically the maths
symbols (✖️ and ➗ are more correct) but these are both on your
keyboard.
not
: negationnot
has-name
.
is-set?
: is a name set to a value?null
value. This operator is how
a program checks to see if something has already been
set. Anything you can set
, can be checked to see if
it is-set?
: attributes, variables, list indices, data
store keys.
( )
: parenthesesIndu
<p>Simple concatenation: #{ "Hell" & "o" }</p>
<p>Space concatenation: #{ "Hello" && "world" }</p>
<p>and: #{ 6 and 8 }</p>
<p>or: #{ 6 or 9 }</p>
<p>=: #{ 6 = 6 }</p>
<p>!=: #{ 6 != 9 } (not equals)</p>
<p>#{ ">:" } #{ 9 > 6 }</p>
<p>#{ ">=:" } #{ 6 >= 6 }</p>
<p>#{ "<:" } #{ 6 < 9 }</p>
<p>#{ "<=:" } #{ 6 <= 6}</p>
<p>+: #{ 6 + 9 }</p>
<p>-: #{ 9 - 6 }</p>
<p>*: #{ 9 * 6 }</p>
<p>/: #{ 18 / 6 }</p>
<p>not: #{ not true }</p>
<p>is-set: #{ is-set? unset-variable }</p>
<p>(): #{ 4 * (5 + 3) }</p>
Output
Simple concatenation: Hello
Space concatenation: Hello world
and: 8
or: 6
=: true
!=: true (not equals)
>: true
>=: true
<: true
<=: true
+: 15
-: 3
*: 64
/: 3
not: false
is-set?: false
(): 32
begin site $$src$$ end site
Once you're calculating things, it's nice to be able to store those things somewhere. Indu provides variables and attributes for storing stuff.
Variables are names for values inside a function, and attributes are
names for values on an object. You've already seen attributes:
countdown is 5
is declaring an attribute and assigning
it the value 5
.
To assign to a variable, set it to something: set countdown to
6
There is no need for any ceremony about either variables or
attributes: just name it and assign it a value, and off you go. When
assigning to a variable with set
Indu will attempt to
find an existing variable or attribute that the code can 'see', and
assign to that. If no variable or attribute exists, then a new
variable is created within the function. That new variable will not
be visible outside the function.
When assigning to an attribute with is
inside an
object, that will always only assign to an attribute in that
object. You can use multiple is
assignments.
The visibility of a named variable or attribute is called its scope. The structure of an Indu program shows the scope. A variable is visible in the function that sets it. Arguments to a function are variables, visible in that function. Attributes of an object are visible anywhere in that object, including any functions defined in that object, or any objects defined within that object.
Indu
message is "highest level"
begin top-level-object
message is "object level"
begin nested-object
message is "nested level"
when set-message
set message to "visible to the function"
end set-message
begin button
<button>Update Message</button>
style
padding is "0.25em 0.75em"
border is "1px solid black"
end style
when click
call set-message
end click
end button
<p>The nested message is #{ message }</p>
end nested-object
<p>The top-level message is #{ message }</p>
end top-level-object
<p>The highest level message is #{ message }</p>
Output
The nested message is nested level
The top-level message is object level
the highest level message is highest level
begin site $$src$$ end site
By now you've seen quite a few names of things in Indu: objects,
functions, attributes, named arguments and varialbes. The rules for
each are the same. The words me
, list
,
true
and false
are used by Indu and can't
be used for your own names. Names can contain any character on your
keyboard except for " / ( ) = < > # : ; , [
]
. Names can not start with a number, a -
or an
@
.
The operators above refer to values of true
and
false
. These are called boolean values, from Boolean
algebra. Indu supports these directly, most commonly in
if
expressions, as illustrated above in the definition
of factorial
Anywhere a boolean value is expected, Indu will treat
false
or 0
as boolean false, and anything
else as boolean true.
An if
expression consists of a test expression (which
is treated as a boolean value), a list of expressions to evaluate if
the test is true, and a list of expressions to evaluate if it is not
true.
-- Syntax
if test-expr
true expressions
else
false expressions
end if
-- Example
if count > 0
call accumulate with (items: count)
count
else
"No items found"
end
The if
expression returns the value of the last
expression in which ever of the two branches was chosen by the test
expression.
Boolean values can be converted into numbers with as
number
. This will convert true
to 1, and
false
to 0.
'String' is the accepted term in programming for lists of letters and other characters. The words you are reading, right now, really. These are very common in programming and therefore are fully supported in Indu. In Indu, strings support the full range of Unicode characters. So feel free to stick emojis or flags or animals or non-Latin characters directly into your strings.
You've already seen strings in the above examples. Strings are
created with "
and "
. For example,
"Hello, world!"
is a string of the characters Hello,
world!. The "
characters are not part of the
string. Strings can be stored and returned anywhere other values are
used.
Two strings can be joined together with the concatenation operators
&
or &&
. See operators above for the difference.
Sometimes, probably because you've asked your user for something,
you might end up with a string that should contain a
number, possibly a number that you want to do maths with. Indu lets
you convert a string to a nubmer with as number
. This
assumes that the string only contains digits, and is in decimal.
Indu programs can convert between strings, numbers and booleans. Most often, you will have a number from a user in a string and want to get to the actual number. This might also happen with booleans.
Convert a string or a boolean to a number with as
number
. The boolean true
will become
1
and the boolean false
will become
0
.
Indu
<p>#{ true as number }</p>
<p>#{ false as number }</p>
<p>#{ ("5" as number) + ("20" as number) }</p>
<p>#{ "14" as number + true as number + false as number }</p>
Output
1
0
25
15
begin site $$src$$ end site
Convert a string or a number to a boolean with as
boolean
. The number 0
becomes the boolean
false
. All other numbers become the boolean
true
. The string "false"
becomes the
boolean false
. The conversion doesn't care about
case. All other strings become the boolean true
.
Indu
<p>#{ 1 as boolean }</p>
<p>#{ 0 as boolean }</p>
<p>#{ 42 as boolean }</p>
<p>#{ "true" as boolean }</p>
<p>#{ "false" as boolean }</p>
<p>#{ "FALSE" as boolean }</p>
<p>#{ "False" as boolean }</p>
<p>#{ "fAlSe" as boolean }</p>
<p>#{ "hello" as boolean }</p>
<p>#{ "world" as boolean }</p>
Output
true
false
true
true
false
false
false
false
true
true
begin site $$src$$ end site
Convert a number or a boolean to a string with as boolean
. Numbers are converted in base-10 (otherwise known as the decimal numbers you use everyday — there's not yet a way to specify the base). The boolean true
becomes the string "true"
; the boolean false
becomes the string "false"
. Numbers and booleans are automatically converted to strings when concatenating, and when inserting into HTML.
Indu
<p>#{ true as string }</p>
<p>#{ false as string }</p>
<p>#{ "fAlSe" as boolean as string }</p>
<p>#{ (10 * 10) as string }</p>
Output
true
false
false
100
begin site $$src$$ end site
Indu doesn't otherwise attempt to convert numbers to strings or in
any other combination. If you attempt 6 > "5"
you'll
get a runtime error, because it doesn't make any sense. There have
been languages that attempted to smooth over that. Experience has
taught us that that was largely a mistake. It's possible that those
languages just did it really badly, however.
Indu provides a native list. A list is simply a collection of values, in an order. Indu lists can contain anything: numbers, booleans, strings, objects, other lists. Each list can contain different types of value, at the same time.
To create a list: list with (1; 2; 3)
. To create an
empty list: list with ()
. To get one specific item out
of a list: item 2 of a-list
. To change one specific
item in a list: set item 2 of a-list to 4
. To insert a
new item into the middle of a list: insert 25 at item 3 of
a-list
. This will make the list longer. To add a new item to
the end of a list append 4 to a-list
. To find out how
many items are in a list: length of a-list
. To remove
an item from a list: remove item 2 of a-list
. Removing
an item will make the list shorter.
Indu
begin button
<button>#{ label }</button>
style
margin is "0 0.125em"
padding is "0.25em 0.75em"
border is "1px solid black"
end style
end button
begin site
a-list is list with (100; 150; 200)
<p>first item: #{ item 1 of a-list }</p>
<p>last item: #{ item (length of a-list) of a-list }</p>
<p>length: #{ length of a-list }</p>
using button(label: "Update First Item")
when click
set item 1 of a-list to 400
set a-list to a-list -- See sidebar below
end click
end button
using button(label: "Add an Item")
when click
append 500 to a-list
set a-list to a-list -- See sidebar below
end click
end button
using button(label: "Remove an Item")
when click
remove item 2 of a-list
set a-list to a-list -- See sidebar below
end click
end button
using button(label: "Insert an Item")
when click
insert 175 at item 3 of a-list
set a-list to a-list -- See sidebar below
end click
end button
end site
Output
first item: 100
last item: 200
length: 3
$$src$$
Alongside conditional (if
) expressions, loops are the
other major way of controlling what your program does. The idea is
that programs often want to do the same set of things a number of
times. Indu has a number of loops. All use repeat
.
-- Loop while a condition remains true
repeat while boolean-expression
expression actions...
end repeat
-- Loop until a condition becomes true
repeat until boolean-expression
expression actions...
end repeat
-- Loop a specific number of times
repeat number-expression times
expression actions...
end repeat
-- Loop over all the items in a list
repeat with ident in a-list
expression actions...
end repeat
repeat while
and repeat until
are
opposites of each other. But boolean logic is surprisingly difficult
to get right. Sometimes waiting for something to become false is
clearer than waiting for something to become not
true.
repeat ... times
is shorthand for the standard loop
where you want your code to count up. It's common enough to warrant
its own syntax.
Indu
a-list is list with (100; 200; 300)
total is "--"
<p>Total: #{ total }</p>
begin button
<button>Add it Up</button>
style
padding is "0.25em 0.75em"
border is "1px solid black"
end style
when click
set total to 0
repeat with value in a-list
set total to total + value
end repeat
end click
end button
Output
Total: --
begin site $$src$$ end site
Inside the body of repeat ... times
and repeat
with ... in ...
loops there are three variables available to
help processing.
is-first?
: is this the first time through the loop?true
, after that it becomes false
and
stays false
. This is useful if your loop requires
special handling on the first item.
is-last?
: is this the last time through the loop?true
. On every previous iteration, this variable will
be false
. This is useful if special handling is
required for the last item in a list, for example.
index
: the iteration count of the loop1
before the beginning of the loop. Increments
before the beginning of each loop.
This variables are only available inside the loop. If you have a variable in the function with the same name, that variable will not be updated, but that other variable will no longer be visible inside the loop.
Indu
a-list is list with (100; 200; 300; 400; 500)
total is "--"
<p>Total: #{ total }</p>
<p>This button will only add half the first item, will skip the last item, and will add the index each time.</p>
begin button
<button>Add it Up</button>
style
padding is "0.25em 0.75em"
border is "1px solid black"
end style
when click
set total to 0
repeat with value in a-list
set total to total + index
if is-first?
set total to total + (value / 2)
else
if not is-last?
set total to total + value
end if
end if
end repeat
end click
end button
Output
Total: --
This button will only add half the first item, will skip the last item, and will add the index each time.
begin site $$src$$ end site
Indu programs are built up of objects, and we've already seen hwo to define objects. As well as giving programs structure, objects are also useful for holding data. Typically, you'd use objects when storing it as a list doesn't feel right. Exactly how and when to use lists or objects is the subject of a lot of study, and is left (for now) as an exercise for the reader.
To use Indu objects to store data, you can create objects inside
functions, just like any other value such as numbers or
lists. Objects can be created with the same syntax as you've already
seen. If the object is simple, it can also be created using
make
syntax.
-- Root object
begin an-object
data is ...
end an-object
-- Object using another object to get started
begin an-object using parent
data is ...
end an-object
-- Object using another object, and overriding parts
begin an-object using parent(data: ...)
other-attribute is ...
end an-object
-- Object without a name using another object to get started
using parent
data is ...
end parent
-- Object without a name using another object, and overriding parts
using parent(data: ...)
other-attribute is ...
end parent
-- Single line versions of those
make an-object
make an-object using parent
make an-object using parent(data: ...)
make using parent(data: ...)
Objects defined using make
are defined in a single
line, and can't have any attributes or event handlers defined
inside. Those can always be added later using set name of
object to ...
, of course. When an object is defined with
begin a-name
or make a-name
that object is
automatically assigned to either a variable in the current function,
or as an attribute of the current object called a-name
.
Objects are also implicitly a list: a list of all the children (either chunks of HTML or other objects) embedded within that object. This list can be appended to, by appending to the object.
Indu
begin todo-item
text is ""
style
display is "block"
width is "100%"
font-size is "1.1em"
end style
<article>
<input type="checkbox" name=text />
<label for=text>#{ text }</label>
</article>
end todo-item
begin site
begin title
style
font-size is "2em"
margin is "0.5em 0em"
end style
<h1>Todo</h1>
end title
make todo-list
begin item-form
text is ""
style
display is "block"
margin is "0.25em 0em"
width is "100%"
border-bottom is "dashed 1px black"
font-size is "1.1em"
end style
<input type="text" value=text>
when change(value) => set text to value
end item-form
begin button
<button>Add</button>
style
padding is "0.25em 0.75em"
border is "1px solid black"
end style
when click
set new-item to text of item-form
append make using todo-item(text: new-item) to todo-list
set text of item-form to ""
end click
end button
end site
Output
$$src$$
Indu is what's called a 'dynamically-typed' language. This means that Indu doesn't require the 'type' to be determined before a value is used: Indu will work out what the type is based on how it's used. It also means that the type of a name can change. If you assign a number to an attribute the type of that attribute will be number. If you then assign a boolean to the same attribute, the type will become boolean.
There are only a few types in Indu: numbers, booleans, functions, lists and objects. Strings are actually a special kind of list.
It's pretty common to want to do different processing based on the
type. This is most common with attributes, and particularly in
objects that have been created to be re-used. Indu has six operators
to let you check the type: is-number?
,
is-boolean?
, is-function?
,
is-list?
, is-object?
and
is-string?
. Even though strings are just lists, they're
special enough to want to check.
Indu
begin an-object
when greeting => "Hello!"
end an-object
<p>is-number? 42: #{ is-number? 42 }</p>
<p>is-boolean? true: #{ is-boolean? true }</p>
<p>is-function? greeting of an-object: #{ is-function? greeting of an-object }</p>
<p>is-object? an-object: #{ is-object? an-object }</p>
<p>is-list? list with (1; 2; 3): #{ is-list? list with (1; 2; 3) }</p>
<p>is-string? "hello": #{ is-string? "hello" }</p>
Output
is-number? 42: true
is-boolean? true: true
is-function? greeting of an-object: true
is-object? an-object: true
is-list? list with (1; 2; 3): true
is-string? "hello": true
begin site $$src$$ end site
Strings are special. Strings are lists, and they're lists of one letter long strings. But, Indu is smart enough to distinguish between a string (that is internally a list of one letter long strings) and a list of longer strings.
Indu
<p>is-list? "hello": #{ is-list? "hello" }</p>
<p>is-string? "hello": #{ is-string? "hello" }</p>
<p>item 1 of "hello": #{ item 1 of "hello" }</p>
<p>is-string? item 1 of "hello": #{ is-string? item 1 of "hello" }</p>
<p>is-list? list with ("hello"; "world"): #{ is-list? list with ("hello"; "world") }</p>
<p>is-string? list with ("hello"; "world"): #{ is-string? list with ("hello"; "world") }</p>
Output
is-list? "hello": true
is-string? "hello": true
item 1 of "hello": h
is-string? item 1 of "hello": true
is-list? list with ("hello"; "world"): true
is-string? list with ("hello"; "world"): false
begin site $$src$$ end site
Indu directly supports databases to store data, permanently. An Indu program can have one or more databases. Each database has a name, and can store items under 'keys'. A key is just a string. Each key can only have a single value, so if you set a key that already exists, then the previous value will be replaced. However, each key can store numbers, booleans, strings and lists: which is a way of storing multiple items under a single key.
A database is created with database
. All that's
required is a name, and therefore make database name
will work. A database is a special kind of Indu object and can
contain attributes and functions, like other objects. If you want to
create a database with functions and attributes use database
name ... end name
To read from an object use key key-val of database-name
and to write to a database use set key key-val of
database-name
.
Indu
make database counter
begin site
click-count is (key "click-count" of counter) or 0
<p>Count: #{ click-count }</p>
begin button
<button>Count a Click!</button>
style
padding is "0.25em 0.75em"
border is "1px solid black"
end style
when click
set click-count to click-count + 1
set key "click-count" of counter to click-count
end click
end button
end site
Output
Count: 0
$$src$$
The pattern (key ... of ...) or 0
is a standard Indu
pattern for checking if a value has been set, and providing a
default (in this case, 0
) if it has not been set.
Try clicking the button a few times, and then reloading the page. The value will remain stored. This guide uses your browser's session store to simulate a database. If you close the tab, the database will be cleared.
Important! Attributes are entirely optional on
databases. However, the Pandita platform understands a special
scope
attribute. While this attribute is optional, and
is safe to leave it out, it is important and you should read about
it. It's described in more detail as part of the Pandita Platform.
Indu also supports accessing JSON-based APIs over the web. To use an
API, define an api
in your program. This is another
kind of object, similiar to a database
that describes
how Indu should make requests.
An api
object contains up to three important
attributes: url
, path
and
body
. An api
object can also contain other
api
objects. These child APIs can selectively override
parts of their parent. This allows you to define a single
api
with multiple 'endpoints'. Each api
object can also accept arguments, like a function call.
Of course, just like all Indu objects, an api
object
can also contain other attributes and functions.
To consume an api
Indu adds a get
and
post
function to each api
. Each function
can be called as any other function, passing any arguments for that
API as arguments to the function. post
will include the
body
attribute as well, if available.
This code is a working example of an Indu api
to work
with TV shows described in the Open
Movie Database. To use this example you will need to get hold of
your own OMDb API key. To use a simple app built with this
api
, try Frasier.
-- The top-level API doesn't take any arguments
api omdb
-- The URL is defined here as all endpoints share this part
url is "http://www.omdbapi.com"
-- Your API key would go here. This attribute is not special to Indu
api-key is "xxx"
-- The title API takes an IMDb id as an argument
api title(imdb-id)
-- And uses that argument and the api-key attribute to build the path
-- Indu combines this path with the url defined above
path is "/?apikey=" & api-key & "&i=" & imdb-id
end title
-- The season API is similar, but it now has two arguments
api season(imdb-id, season)
path is "/?apikey=" & api-key & "&i=" & imdb-id & "&season=" & season
end season
-- And the episode API has three
api episode(imdb-id, season, episode)
path is "/?apikey=" & api-key & "&i=" & imdb-id & "&season=" & season & "&episode=" & episode
end episode
end api
-- To use this API:
set show to call get of title of omdb with (imdb-id: "tt0106004")
set season to call get of season of omdb with (imdb-id: "tt0106004", season: 4)
As you write Indu programs you will find other programs that you want to use to help. You will also probably write your own programs. To re-use code, Indu offers libraries. Libraries are sets of objects (including databases and apis) and functions that can be included into a program, and then used as if they were part of that program.
Libraries are included with include
. The included
library becomes an object (called a module) that is then used to get
access to functions and objects.
include module from /author/library
call function of module
begin site using root of module
...
end site
Libraries are just another Indu program; there's nothing special
that you need to do. Because the library is also made into a module
object, you can include libraries that have objects or functions
with the same name as your program. If you're writing an Indu
program that is intended to be used as a library, you should add a
site
object that explains the interesting parts of the
library, and how to use it. Libraries can include other libraries.
Libraries, as objects, can also take arguments when being
included: include module from /author/library with
(arg: new-val)
.
Library: buttons-lib
begin google-font
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=" & font & "&display=swap" rel="stylesheet">
end google-font
begin button
with google-font
<button>#{ label }</button>
style
padding is "0.25em 0.75em"
border is "1px solid black"
font-family is font
end style
end button
begin heading
with google-font
<h1>#{ text }</h1>
style
font-size is "2em"
font-family is font
end style
end heading
begin site
<p>
This library includes three useful objects for creating sites:
heading, button and google-font. When including this library
specify the Google Font to use with font.
</p>
end site
Indu
include button from buttons-lib
begin site
click-count is 0
make using heading of button(font: "Lora", text: "Counting")
<p>#{ click-count }</p>
using button of button(font: "Lora", label: "Update")
when click
set click-count to click-count + 1
end click
end button
end site
Output
$$src$$
The Indu Standard Library is a collection of objects and functions to be used in all Indu programs. There are typical maths functions, typical functions for programs that run in a browser, and re-usable objects. All for building your own programs.
The standard library is currently quite small. It will grow, however. We're particularly interested in areas that you find it lacking.
Like all good Indu libraries, the documentation for the contents of the library are part of the library, and can be read by browsing to it.
Indu programs don't run in isolation. Each program runs here, on the Pandita platform. This platform provides a set of features and behaviour that Indu authors need to be aware of.
site
objectsite
and
renders that. The site
object is responsible for
providing the first UI. In many cases, it'll be the only UI. Other
objects can provide the UI, see the standard
library for how to move between objects.
window
object, for all
events it declares. When an event is handled, Pandita searches for
the nearest Indu object and sends the event to that. It passes
attributes of the event object as arguments to the event function,
except for any attributes that are vendor-specific (eg. webkit or
moz), are entirely upper-case, null
, don't have a
defined type (which means they are native objects), are the
window
object, or are JavaScript objects or
functions. It sounds like a lot are excluded, but actually it
mostly just trims down to the event attributes defined in the
standard. If the event has a target
attribute,
Pandita will inspect that object and if it has a
value
object it will pass that to the event
handler. Because Indu uses named arguments, if you're not
interested in an event attribute, just ignore it in your argument
list. If you are interested, just name it. The event
mapping process is very likely to change!.
render
function that returns an Indu representation
of an HTML element. Pandita then converts that representation to
actual HTML. As mentioned in the standard library, every element
has an id
. This id
is set to the
caddr
of the object that generated the element. If an
element does not have an id
it is because it was
generated by an HTML literal. A caddr
is an Indu
thing that allows constant-time look-up of the Indu object. It is
not persistent! It will change! Do not rely on specific values!
Pandita uses an Indu feature to know when to re-render an object
because it has changed. Every time an object attribute is set, and
Indu event is raised. Pandita handles these events for any objects
that appear in the displayed HTML. When the handler is invoked it
will call render
on that object, and then re-display
just that part of the UI. If your program is re-rendering at
inopportune times, try using temporary local
variables. This is a poor imitation of data-flow
analysis. Indu will likely improve rendering and other behaviour
with proper data-flow analysis in the future.
scope
attribute of database objects was mentioned
in passing above. This attribute controls who can read or write to
keys in the database. There are four values Pandita understands.
app
For values that the app should use no matter
which author is running the app. Can be read by anyone, can
only be written by the author of the app. Users must be logged
in to Pandita to write, but not to read.
user
For values that the app needs to make
available only to the user of the app. Can be read and written
by anyone, however each user gets their own value and
can't see anyone elses. Users must be logged in to write and
read. This is the default scope
if none is
supplied.
private
Like user
but there are only
values for the author of the app, not anyone else. Users must
be logged in to write and read.
anonymous
Anyone can write, but only the author
can read. Useful for analytics. Users must be logged in to
read, but not to write.
If you've been reading the sidebars throughout this guide, you'll have noticed that there are few things that are missing from Indu. In general, things on this list are things that will be added or fixed in the future. It'd be great to hear which missing feature really gets in your way, so we can prioritise fixing that. Most of the items in this list are features, but there are some bugs.
children
list for objects, but
it doesn't understand other lists, or database keys. Data-flow
analysis may be able to solve more of these areas.
children
element of an object gives all the objects and HTML that are
children. However, you can't walk back up the graph. The object
graph is such a fundamental part of an Indu program that it should
be possible to work with it directly.