Alphabetical listing by Path
The XML syntax for CDATA is supported to allow for the creation of strings with weird sets of characters in them such as unbalanced quotes. A CDATA 'call' is bounded by open and close angle brackets. Inside the open angle bracket is the character sequence ![CDATA[ Inside the close angle bracket is the character sequence ]] Between those delimiters you can have any character sequence except ]] followed by a close angle bracket. The result of executing a CDATA call is to return a string of the characters between the CDATA delimiters. Note that for a CDATA call the ending is not slash close-angle nor a full closing tag named CDATA. See also <string>foo</>
When Water looks up a field in an object and doesn't find it in the object or any of its
ancestors, it calls the method "_if_missing_method" with the object as "_subject"
and the field name as the first argument (named "the_key").
If _if_missing_method is itself not found, execute_expr returns null.
The method _if_missing_method is looked up just like a regular field reference
For example, if we have a hierarchy of:
thing
vehicle
boat
and we execute boat.anchor, and there is no anchor field in boat, vehicle or thing,
then execute calls boat._if_missing_method.
If there is no such field in boat but there is one in vehicle, then
the one in vehicle will be called with the name of the missing field
as "_subject" like so: "anchor".<thing.vehicle._if_missing_method/>
Whatever this call returns is the returned value of our original boat.anchor.
Example:
<defmethod _if_missing_method the_key>
"big_hairy_missing_field"
</defmethod>
Take care to define your versions of _if_missing_method all with an argument
named "the_key".
The original caller of boat.anchor is never aware that anchor isn't actually
a field in boat. If you really want to tell, you can call container_of or 'has'.
Most of the time you attempt to access a non-existent field, you probably want
the system to error so you can find out about and fix typos as soon as possible.
So if you do define _if_missing_method, be sure to remove it when you're done
or it will continue to "not error".
Example: thing.<remove "_if_missing_method"/> will set Water back to its
default, "error upon non-existent field" behavior.
See xml_and_water for an extended example.<active_value />
You can set a variable such that instead of just returning the value in the field, it will execute arbitrary code instead. The documentation for "set_value" has an extensive description of active_value.
<and rest="unnamed"='ek_expression' />
Returns true if its subject and all of its args execute to true. You may call and with or without a left-hand subject. Examples: true.<and true true/> returns true true.<and false true/> returns false <and true true/> returns true.
<append rest=required />
Returns a new vector containing all the elements of "_subject" and
each vector in rest.
_subject defaults to the empty vector.
Does not modify any arguments.
Examples:
<vector 3 5/>.<append <vector 7 9/>/> returns <vector 3 5 7 9/>
<append <vector 3 5/> <vector 7 9/>/> returns <vector 3 5 7 9/>
See also: concat,
file.append which extends the content of an existing file.<assert a_type= name=null if_failure=<get_type_checking/> />
If '_subject' is of type "a_type" then return '_subject' otherwise, indicate the failure based on the arg: 'if_failure'. "error" means error. "warning" means print a warning but still return '_subject'. "off" means don't even do the type check, just return '_subject'. The default value is <get_type_checking/> which will be one of the above three options, which itself is "off" by default. See also: get_type_checking
An attributes tag is a way to encode flexible attributes like tohse of ConciseXML
in a pure XML 1 syntax. ConciseXML is more convenient syntactically,
but when you must have XML syyntax, use the 'attributes' tag.
Note that 'attributes' is not a method, it is a syntax handle specially by the
Water parser.
Examples:
<defmethod> <attributes>foo myarg=required=number="ek_code"</attributes>
myarg
</defmethod>
<foo> <attributes> 291 </attributes> </foo> returns 291
<foo> <attributes> myarg=291 </attributes> </foo> returns 291
Concise XML for the above is:
<defmethod foo myarg=required=number="ek_code"> myarg </defmethod>
<foo 291/> returns 291
<foo myarg=291/>
The to_xml formatter puts out strings that contain calls to 'attributes'.
See also: to_xmlboolean.<random_instance />
Returns true or false with equal probability, just like flipping a coin. Example: boolean.<random_instance/> returns true or false. See also: integer.random_number, integer.random_instance, thing.random_instance
<cache_instance add_vector_key=false if_exists="set" />
cache_instance is a method typically used in an init method of a defclass.
It stores an instance in the "of" field of the class.
First cache_instance looks up the 'primary_key' of the parent of the
_subject to cache_instance. The primary_key of 'thing' is "id" so
that is used if there is no other primary_key found.
Then the _subject is examined for a field with the key of the primary_key,
i.e. "id". If the _subject as no primary key in it (no lookup is performed here),
then no further action is taken and the _subject will not be cached.
Otherwise, if there is no "of" field in the parent of subject then
it is created using <thing/> as its value (making an object with parent 'thing').
Then the name of the _subject is retrieved by getting the value of the field
within subject whose key is the value of 'primary_key'.
Then the field of the primary key name is set within the value of "of"
to the _subject.
Here's how it works;
<defclass boat>
<defmethod init> _new_object.<cache_instance/> </defmethod>
</defclass>
<boat id="bluebelle"/>
The above call returns our new instance since the init method is called
and its last expression is a call to cache_instance which returns
its subject, in this case the '_new_object' which is our new instance
of boat named "bluebelle".
But the important thing is the side-effect. Now
boat.of.bluebelle returns our new object.
Note that since there was no primary_key in boat, the primary_key
defaulted to 'id'. Since our new instance has an id of "bluebelle",
the instance was cached.
We can create an instance WITHOUT caching it if we like by not giving it
an id such as <boat/> or <boat weight=123/>. We might do this if we were
creating a temporary boat.
Caching an instance makes it convenient to reference the object via
a path of its class name, followed by "of" followed by the name of the
instance.
Should we want our "name" field to be called something other than 'id':
<defclass boat primary_key="licence_plate">
<defmethod init> _new_object.<cache_instance/> </defmethod>
</defclass>
<boat licence_plate="bluebelle"/>
boat.of.bluebelle.licence_plate returns "bluebelle"
cache_instance takes one argument, add_vector_key (default false).
If this argument is true, an additional key is added to the "of" object which
is the next highest integer key available in the "of" object.
This makes it easy to count the number of instances, maintain the
order they were created in and reference them by an integer like so:
<defclass boat>
<defmethod init> _new_object.<cache_instance true/> </defmethod>
</defclass>
<boat id="bluebelle"/>
<boat id="old paint"/>
boat.of.<length/> returns 2
boat.of.0.id returns "bluebelle"
boat.of.1.id returns "old paint"
The formatting method to_h2o has special support for cached instances.
boat.<to_h2o only_print_instances=true/> turns off the printing of the
call to defclass and the printing of all its attributes.
It does however leave on the printing of the "of" field and all the "of" fields
of all the subclasses of the class you are printing.
Use only_print_instances=true when you want to save the instances of a
class in a file but not the classes that they came from since you probably
load them as part of the loading of your application.
See also: defclass, init, to_h2o<call a_object=required args=<thing/> a_context=<context/> />
Call is a method to perform calls programmatically.
It is an advanced feature not needed for most uses.
The subject of the call can be passed in either as an explicit argument of _subject,
or as the left hand subject to the call of 'call' itself.
The first argument is the "method" or the class of the object to be constructed.
If it is a string, it is taken to be the name of the method or object within
the subject.
The second argument is an object containing the args to pass to the method.
This can be a vector, in which case all arguments are "by position".
You can also use a record as the value of the second argument.
The unnumbered non-system fields will be used to pass args by key,
with the key being the key of the field and the value being the value passed in.
the numbered field of the record (in which case you'll have a 'supervector'),
will be the by-position arguments.
With call you can pass arguments by-position as well as by key.
All of the arguments to call are executed, then the actual call
is made with those values.
Examples:
Given a definition of thing.<defmethod foo boo bar baz> boo.<concat " " bar " " baz/> </>
<call "foo" <vector 10 20 30/> _subject=thing/> returns "10 20 30"
and is equivalent to thing.<foo 10 20 30/>
thing.<call thing.foo <thing boo=10 bar=20 baz=30/> /> returns "10 20 30"
and is equivalent to thing.<foo boo=10 bar=20 baz=30/>
<call thing.foo <thing 0=10 1=20 baz=30 _subject=thing/> /> returns "10 20 30"
and is equivalent to thing.<foo 10 20 baz=30/>
If the method takes rest arguments, then the same rules apply as to how the
arguments are mapped to the parameters as will normal calls, i.e.
First all the keyed arguments are mapped to the same-named parameters,
then the first arguments are applied to all the required arguments of the
method, finally the remainder of the by-position arguments are used
for rest args. As usual in calls, if rest args are permitted, then
no by_position args get mapped to optional parameters.
Constructing new instances of a class works similarly:
<call thing.<defclass boat weight/> <vector 241/> /> returns <thing.boat weight=241/>
The context arg can take a record or a context just like execute_string
See also execute, execute_string.<char rest=false />
The way to make a character literal is <char "a"/>
You can use the escape sequences on strings to get non-printing characters.
Example:
<char "\n"/> for newline
<char "\t"/> for tab
See the documentation on "string" for more escaped characters.
Note that unlike the Java type "char", the Water "char" is
a real object.char.<less a_char=required />
Returns true if "_subject" is alphabetically less than the argument. The ascii numerical equivalent of the character is used in sorting.
char.<less_or_equal a_char=required />
Returns true if "_subject" is alphabetically less than or equal to the argument. The ascii numerical equivalent of the character is used in sorting.
char.<more a_char=required />
Returns true if "_subject" is alphabetically more than the argument. The ascii numerical equivalent of the character is used in sorting.
char.<more_or_equal a_char=required />
Returns true if "_subject" is alphabetically more than or equal to the argument. The ascii numerical equivalent of the character is used in sorting.
char.<to_lowercase />
If "_subject" is an upper case letter, returns the corresponding lower case letter otherwise returns "_subject". Example: <char "A"/>.<to_lowercase/> returns <char "a"/> See also char.to_uppercase, string.to_lowercase
char.<to_uppercase />
If "_subject" is a lower case letter, returns the corresponding upper case letter otherwise returns "_subject". Example: <char "a"/>.<to_lowercase/> returns <char "A"/> See also char.to_lowercase, string.to_uppercase
from and two can be any combination of one character strings,
characters, or integers. If integers, the ascii character of
that integer will be used.Creates a string whose first char is a open square braket and whose last char is a close square bracket.
Each of the rest arguments may be a string, a character or an integer.
The arguments are concatenated together, wrapped in square brackets and returnd as a string.
String-valued arguments have their outer square-brackets stripped off if any and used as is.
Chars are used as chras in the resulting string.
Integers are converted to their ascii equivalent chars and used in the resulting string.
Args of the format that are generated by not_char_set ie [^abc] are not allowed and will cause an error.
The content is not evaluated during the call. Each char in the content source is inserted into
the resulting string.
Example:
<char_set abc def>ghi</> returns [abcdefghi]
<char_set abc <char_set def/>/> returns [abcdef]
An open square bracket can be inserted into a char_set as is but a close
square bracket must be escaped.
Example:
<char_set "a[\\]"/> Includes three characters, a, open square bracket and close square bracket.<char_vector_to_string />
Converts a vector of chars into a string. If an item in the vector is not a char, error. Example: <vector <char "w"/> <char "e"/> <char "r"/>/>.<char_vector_to_string/> returns "wer" See also: string_to_char_vector, from
<
Creates a color from components red, green and blue each of which can be an integer from 0 through 255. Examples: <color 255 0 0/> makes pure red <color 0 255 0/> makes pure green <color 0 0 255/> makes pure blue <color red=0 green=0 blue=255/> same as above <color 1 2 3/>.green returns 2, the integer value of green
<combine a_method=concat first_value=optional />
"_subject" is a vector. a_method is called with first_value as "_subject" and the first element of the vector as the first argument. The result is stored and used as "_subject" for a second call to a_method with the 2nd element of the vector as the new first argument and so on until the end of the vector is reached. Using just the default arguments, to_html is called on each of the elements in the vector and concatenated together to yield one big string. Examples: <vector 2 3 4/>.<combine number.plus 0/> returns 9 <vector 2 3 4/>.<combine number.plus 1/> returns 10 If first_value is not passed, then it is as if the first_value is the first element of the vector and we process the 2nd through nth vector elements the same as above. Example: <vector 2 3 4/>.<combine number.plus/> returns 9 See also: is_sorted
<compute_file_path_for_field the_key=null dir_to_start="logical://system/" />
Warning: this method probably busted due to the switch
away from the field "subobjects".
"_subject" must be a subobject of its parent and have an "_id".
Examples:
With an object hierarchy of:
thing
color
size
number
plus
minus
integer
thing.number.integer.<compute_file_path_for_field/>
returns D:somedir/com/glueworks/glue/thing/number/subobjects/integer.h2o
thing.number.integer.<compute_file_path_from_field "plus"/>
returns D:somedir/com/glueworks/glue/thing/number/integer/plus.h2o<concat rest=required />
Returns a string of the concatenation of calling to_html on "_subject" plus each of the rest arguments. _subject defaults to "". Examples: "abc".<concat "def" "ghi"/> returns "abcdefhi" <concat "def" "ghi"/> returns "defghi"
<container_of key=required />
Returns the object that key was found in or false if key isn't in any ancestor. Note: if "_subject" is false, and key is "_parent" then this method will return "the object in which the field was found" which happens to be the "false" object, so that's misleading. But note that all objects (except thing) have a parent, so normally container_of isn't called with key of _parent anyway and rarely on the false object. See also 'has'.
Returns the current execution context. Context is used as an optional argument to execute_expr and execute_string to describe the execution context for the code to be executed. The context contains the stack of local environments being called as well as the fluid variables currently defined. See also: environment_of_call.
<copy include=return_true=defmethod limit=optional include_limit=true other_named_args=true />
Returns a copy of _subject.
If subject is a literal (string, number, boolean, char, null), just return it.
include is a method that is called for each field key that may be copied.
if it returns true, the field is included in the copy, otherwise it isn't.
Copy uses two attributes to determine how many ancestors to go up from '_subject'
and grab field values from.
'limit' is an object that is presumably an ancestor that sets the limit of how
far up copy will go looking for fields.
If include_limit is true, include the fields of the limit object,
otherwise don't, only include fields below the limit object.
Never are fields above the limit considered for copying.
Only the value of the first field of a given key that is found on the way up
is used in the copy.
By default, include is 'return_true',
limit is '_subject' and
include_limit is true
so that all the fields immediately in '_subject' are copied and no more.
If additional named arguments are passed to copy, those fields are added to the
result. If an additional arg has the same name as a field in the original,
then the passed in value will override the original's value for the field.
See also: for_each for a more complete description of 'include'.
merge_down_into for a way to copy fields into an existing object.
defmethod.copy which is very similar but does a few special things for methods.<copy_down />
Used within an 'init' method to easily copy down all the data
fields of the class into the instance. It returns the modified _subject.
<defclass foo x=5>
<defmethod init>
_new_object.<copy_down/>
</>
</defclass>
Now all the instances of foo will have their own version of the field x.
foo.<set x=99/> will not be seen by the foo instances since they
now shadow the value in their parent.
Note this is similar to class_instance object systems wherein the instances
always have their own copies of the instance variables.
In Water, if an instance doesn't have a variable it looks up into its parent
to get the value.
Only the field keys in the _field_order of the parent are copied down.
Fields that already exist in the subject are not copied down.
See also: init<count predicate=required />
count returns the number of specified items in "_subject" which is expected to be a vector.
If "_subject" has no integer numbered fields, zero is returned.
If predicate is a method, then that method is called with "_subject" equal to each
element of the original "_subject". If a predicate call returns non-false,
then that counts as one for the result.
If predicate is NOT a method, then compare each element in "_subject" with the
predicate via "is" and if that returns true, then that counts as one.
Examples:
<vector 1 2 3 4 5 6/>.<count <defmethod more2> _subject.<more 2/></> /> returns 4
<vector 1 2 4 1 7 8 1/>.<count <defmethod is_one> _subject.<is 1/></> /> returns 3 i.e.
the method is_one is called for each element of the vector and returns true for 3 of them.
A simpler (but less general) way to write the same thing is:
<vector 1 2 4 1 7 8 1/>.<count 1/> returns 3
"line one\nlinetwo\n".<count <char "\n"/>/> returns 2 , i.e. finds the 2 newline chars in "_subject".Processes the header of a csv string just like csv_to_objects with keys="from_header" and returns the header as a vector of strings. Does not look at the non-header portion of the csv string.
Very similar to the method 'to_objects' using the default value for field_separator ( comma ) and the default value for object_separator ( newline ), however, fields may be double-quoted strings that can contain commas and newlines. If a line has no fields, no object is created for it. By default, the maker is called with by-posiiton arguments from the fields of each row. However, you can specify calling the maker using keyed arguments using the 'keys' parameter. This defaults to null meaning pass arguments by-position. If it is a vector, that will be a vector of the argument keys to call the maker with. You can automatically get the keys to use from the csv data by specifying a row to get the keys from as an integer. Usually this will be one of the rows specified for the header (see below). Alternatively, you can specify to get the rows from the header by passing in "from_header". (see below) A header is declared by passing in the header_first_row and header_length. header_first_row defaults to 0 meaning the first row in the csv data. header_length defaults to 0 meaning there are no rows in the header. If the header_length is positive, there is a header. The rows in the header will NOT be used for data and no output objects will be generated from them. Data will come only from rows after the header. Rows before the header will be ignored. If you simply want to skip say, the first 5 rows at the top of the csv data, declare a header_first_row of the first row of actual data, ie 5, and leave the header_length defaulting to 0. This acts as if rows 0 through 4 did not exist in the data at all. If you have a multi-lined header, and you specify a 'keys' value of 'from_header' then each field will be a concatenation of each field in the header for that column. An underscore is placed between the fields. Each key from the header is "trimmed" to get rid of whitespace before or after a header field. When calling a maker with keys, if the number of data items is less than the number of keys, the extra keys will not be used in the call. If the number of data items is greater than the number of keys, then they will be passed by-position to the maker. A maker that cannot handle the arguments it is passed will error in the usual way that any method or object constructor would error if it was passed too many arguments. See also: to_objects
<data />
Takes a string in XML syntax and returns a "data" representation of it Parses the XML and converts tagnames (other than <ex thing/> or <ex vector/>) to a symbol instance. The string of XML can be given as the subject or the content. <Example <data><foo><bar>10</bar></foo></data> <<symbol "foo"/>><<symbol "bar"/>>10</></> /> <Example "100".<data/> 100 />
<datetime year=null month=null day=null hour=null minute=null second=null millisecond=null base=null date_separator="-" time_separator=":" />
datetimes are constructed by passing in a base datetime and the overriding particular
attributes of the base datetime. Once a datetime is created, it is considered to be immutable and
cannot be changed. To get a slightly different datetime, you must create a new one.
The base datetime defaults to year 1, month 1, day 1, hour 0, minute 0 second 0, millisecond 0.
Thus the call <datetime/> returns a datetime with those defaults.
A base datetime can be any one of:
A string such as "Mon Feb 18 20:21:00 EST 2002", "3/22/2002", or "3/24/02"
A Water datetime object
A java date object.
If base datetime is a string, any format acceptable by Java's Date constructor that takes a
string argument is legal. Note that any string returned by some_water_datetime.<to_html/>
is acceptable.
year Must be a full year integer ie 2002. If you say 2 that means 2 years after 0 AD.
month an integer between 1 and 12 inclusive
day an integer between 1 and 31 inclusive
hour an integer between 0 and 23 inclusive
minute an integer between 0 and 59 inclusive
second an integer between 0 and 59 inclusive
millisecond an integer between 0 and 999 inclusive
Examples:
<datetime>3/22/2002</> March 22, 2002
<datetime base="3/22/2002"/> March 22, 2002
<datetime base="3/24/02"/> March 24, 2002
<datetime 2002 3 24/> March 24, 2002 at 0:0:0
<datetime 2002 3 24 14 45 46 555/> March 24, 2002 2:45:46 PM and 555 milliseconds
<datetime year=1999 base="3/22/2002"/> March 22, 1999
datetime.current returns a datetime of the current day and time.
date.current returns current date (time of 0:0:0)
time.current returns current time
datetime.time is a method that takes 4 arguments, hour, minute, second and millisecond.
The default for each is 0. It constructs a datetime with year=1, month=1, day=1.
Examples:
<time 14 20/>.<to_html/>
14:20:00
There are many ways to print a datetime.
a_datetime.<to_html/> returns string of format: "Sun Mar 24 21:05:41 EST 2002"
a_datetime.<m_d_yy/> returns string of format: "3/24/02"
a_datetime.<mm_dd_yy/> returns string of format: "03/24/02"
a_datetime.<mmm_d_yyyy/> returns string of format: "Mar 24, 2002"
or roll your own by accessing different fields of datetimes:
a_datetime.yy a two digit string
a_datetime.mm a two digit string representing the month
a_datetime.mmm a three letter month abrieviation
a_datetime.month_name a string with a full month name
a_datetime.h24 a two digit string representing the hour from 0 to 23
a_datetime.hh a two digit string representing the hour from 0 to 11
a_datetime.am_pm either "am" or "pm"
a_datetime.nn a two digit string representing the minute
a_datetime.ss a two digit string representing the second
a_datetime.ww a two letter string representing the day of the week.
a_datetime.www a three letter string representing the day of the week.
a_datetime.day_of_week_name The day of the week in full English.
a_datetime.day_of_week Returns an integer for the day of the week, 0 for Sunday, 6 for Saturday.
Datetimes have comparators: equal, less, more less_or_equal, more_or_equal
and arithimetic: plus that takes an argument of a duration and
minus that takes an argument of a duration or a datetime.
See also: duration, datetime_interval.
<db_resource
a_uri=required=
db_resource contains the classes and methods for
Water Database. Water Database is the standard Water
library for connecting Water programs to relational
databases.
Water Database uses standard JDBC drivers. Below are
instructions for how to configure different databases.
To setup databases with specific drivers: (Example: MySQL)
1. Download a JDBC driver. It should be packaged as a .jar file.
2. Put the JDBC .jar file into the 'jre/lib/ext' folder of your
Java Runtime Environment.
(Example: C:/jdk1.4/jre/lib/ext or C:\Program Files\Java\j2re1.4.1_02\lib\ext)
3. Configure the database for local and/or remote access
(Example: for MySQL, use the MySQL Control Center (mysqlcc) program)
Enter usernames and passwords (or leave empty)
4. Start the database
(Example: D:/mysql/bin/mysqld )
5. Execute Water Database commands (see examples below)
To setup a local Access 97 database under Windows:
1. Under the Control Panel, setup the ODBC settings and
2. Add a System DSN
3. Choose a type of "Microsoft Access Driver"
4. Enter a Data Source name (Example: my_db)
5. Click "Select..." button to select an mdb file (Example: my_db.mdb)
6. Choose "Advanced..." and setup the Default Dir (Example: C:\my documents)
7. Enter user and password fields (or leave blank)
8. Start the database
9. Execute Water Database commands (see examples below)
Create a new database repository. A single repository can
hold one or more databases. Note: repository is a subclass of
db_resource, but it is promoted.
<Example
<repository
a_uri="jdbc:mysql://localhost/"
protocol="com.mysql.jdbc.Driver"
/>
result=repository.of."jdbc:mysql://localhost/"
/>
Any SQL query can be executed on a repository using
<ex execute_sql/>. <ex execute_sql/> takes an SQL statement
in the hypertext content area. An ending semi-colon is not
required.
<Example
repository.of."jdbc:mysql://localhost/".
<execute_sql> SHOW DATABASES </>
result=
<vector>
<thing Database="primary_db"/>
<thing Database="mysql"/>
</vector>
/>
The database connection can be found in field named
"a_connection", although you typically do not need to
access it. The connection gets created on the first
database request.
<Example
repository.of."jdbc:mysql://localhost/".a_connection
/>
CREATING A NEW DATABASE
<ex database/> Creates a new database within the repository.
If no connection is given, it will reuse the connection
from the repository. The database can be accessed as a field
in the repository. The following example shows creating a
new database named "test_db":
<Example
repository.of."jdbc:mysql://localhost/".<database "test_db"/>
result=repository.of."jdbc:mysql://localhost/".test_db
/>
Alternatively, you can create a database connection that
is separate from the database connection for the repository.
Set the database resource to the local variable "my_db"
<Example
<set my_db=repository.of."jdbc:mysql://localhost/".test_db />
/>
Create a new database table named 'book' using SQL:
<Example
my_db.<execute_sql> CREATE TABLE book(isbn VARCHAR(255),
title VARCHAR(255),
author VARCHAR(255),
publisher VARCHAR(255))
</execute_sql>
/>
Use SQL to look at the newly created table:
<Example
my_db.<execute_sql> SHOW TABLES </>
result=<vector <thing Tables_in_test_db="book"/> />
/>
Use 'execute_sql' to insert two rows into the table:
<Example result=1>
my_db.<execute_sql> INSERT INTO book VALUES
("283223","Water","Plusch","Wiley")
</execute_sql>
my_db.<execute_sql> INSERT INTO book VALUES
("458328","Water Programming","Fry","Clear Methods")
</execute_sql>
</Example>
Perform a SQL SELECT query on the new table to retrieve the
data. Notice that the instances are generic things, and are
not of type 'book'.
<Example
my_db.<execute_sql> SELECT * FROM book </>
result=<vector>
<thing "283223" "Water" "Plusch" "Wiley"/>
<thing "458328" "Water Programming" "Fry" "Clear Methods"/>
</vector>
/>
If you have a Water Contract (defclass) for the corresponding
database table, you can specify that the returned instances
should be of that class. <ex execute_sql/> takes an argument
named 'class'.
<Example
<defclass book isbn title author publisher/>
/>
<Example
my_db.<execute_sql class=book> SELECT * FROM book </>
result=<thing
<book "283223" "Water" "Plusch" "Wiley"/>
<book "458328" "Water Programming" "Fry" "Clear Methods"/>
/>
/>
The following example shows how the first instance can be retrived
using a simple Water Path:
<Example
my_db.<execute_sql class=book> SELECT * FROM book WHERE isbn="283223" </>.0
result=<thing.book isbn=283223 title="Water"
author="Plusch" publisher="Wiley"
/>
/>
<ex a_connection/> can be explicitly created and passed into a database
in the <ex a_connection/> field.
<Example>
<set a_db=
<database "test_db"
a_connection=db_resource.<connection "jdbc:mysql://localhost/"
"com.mysql.jdbc.Driver"
username="" password=""
/>
/>
/>
</Example>
<Example
a_db.<execute_sql> SHOW TABLES </>.<length/>
result=1
/>
CONNECTING TO EXISTING DATA
A very common scenario is that data already exists in
a database, and Water is used to access and manipulate
that data.
If you have an existing database named "test_db" and
an existing table named "book", then the following will
create a Water Database object that represents the
relational database, and assign it to the <ex my_store/>
local variable. If the database already exists, use the
path to the database instead.
<Example
<repository "jdbc:mysql://localhost/"
protocol="com.mysql.jdbc.Driver"
username=""
password=""
/>
/>
<set my_store=repository.of."jdbc:mysql://localhost/".<database "primary_db"/>/>
Any SQL command can be called using <ex execute_sql/>:
<Example
my_store.<execute_sql> SELECT * FROM book </>
result=<vector>
<thing "283223" "Water" "Plusch" "Wiley"/>
<thing "458328" "Water Programming" "Fry" "Clear Methods"/>
</vector>
/>
A Water Contract 'defclass' can be created automatically from the
database table definitions using <ex derive_classes/>.
<Example
my_store.<derive_classes/>
/>
It is possible to create custom mappings of SQL datatypes
to Water types. <ex db_resource.map_sql_type_to_water/> and
<ex db_resource.map_water_type_to_sql/> are the mapping tables.
The use of these maps has yet to be documented.
The <ex defclass/> for book is now defined in <ex thing.book/>
and can be used as a class in <ex execute_sql/> to return
objects of the appropriate class.
<Example
my_store.<execute_sql class=book> SELECT * FROM book </>
result=<vector>
<book "283223" "Water" "Plusch" "Wiley"/>
<book "458328" "Water Programming" "Fry" "Clear Methods"/>
</vector>
/>Debugging tools are continually being improved. This describes the basic ones.
Expressions
If you get a syntax error, it is likely due to an incomplete expression.
Most of these are unbalanced angle brackets, double, or single quotes.
Double click on the beginning or end of what you think is a complete expression,
and the parser will be run on the expression, highlighting the complete expression.
Double click just before an open angle bracket or the first of a pair of quotes or
double click just after a close angle bracket or second of a pair of quotes.
If there is no complete expression, only the first character will be highlighted.
Execution
Select any source code in the editor and hit the Execute button.
If you get a syntax error, double click on nested expressions until you
find the problem.
Note that in selecting source to execute, if it is, say an expression in
the body of a defmethod and that expression contains parameters or local variables,
execution will error if those are unbound (which will usually be the case).
Make a call to the method supplying the proper arguments to test it.
If you have a lot of top level expressions in a file and you're not sure which one is
failing, use the Options menu to turn on the "Execute makes results vector" flag.
Then get rid of any selection and hit Execute. The entire buffer will be executed
and a vector of the result of each of the top level expressions will be returned.
Stepping
If execution fails, try stepping through an expression to see exactly which part
of it fails. Start by using the Step button instead of the Execute button.
Use the other buttons in the bottom of the IDE to control stepping.
Print Statements
Sometimes stepping is too slow as the problem is very deeply nested.
In such cases, print statements can come in handy.
Use the method "echo" to make print statements to the Java console.
Echo can take any number of arguments of any type. It will print all of them out
and return the value of the last one.
Inspect
If you want to be able to interactively inspect and navigate into fields of objects,
use the inspector.
There are four different ways to inspect objects.
First, from the development environment, use the tools menu to inspect various important
object in Water. "thing" is the root object. From it you can get to all classes
as well as documentation on classes and methods. Note that the item "Inspect Latest Result"
lets you inspect the value of the last expression you have executed. You can usually
do this by clicking on the upper right window, but if that fails, use the menu item.
Clicking on the lower right pane (where the HTML is rendered) will show you the
string of html source code in the inspector.
Second ii is an "active value" that you can stick in a path to see intermediate values
Example: thing.number.ii.integer
Third iip is a method that gives you the option of pausing execution at the point of the call
Example: thing.number.<iip p/>.integer
When the above is executed, after "number" is evaluated, the result is shown in
the inspector, then execution pauses until the developer clicks on the "Execute"
button in the development environment.
A particularly easy way to use iip is via the edit pane right click menu item
named "Inspect Breakpoint".
Fourth inspect is a method used to inspect an object where inspection is part of the normal
operation of the program.
Both ii and iip are meant to be temporary, debugging tools whereas inspect is
intended to be a permanent part of the program being developed.
By searching for the string "ii" you can easily find and remove all calls to ii and iip
from your source code.
Extended Example:
<defmethod foo a=1 b=2>
<bar 33/>
</>
<defmethod bar c=3 d=4>
_environment.ii
5
</>
<foo/>
When the above is executed, the call to foo, calls bar then
the local variable _environment is inspected. The value of _environment
is the current local environment containing all the local variables
which includes the arguments passed to the method.
The inspect window that comes up will show you the values of the variables
c, d, _subject and the name of the current method in the variable "_this_method".
Note that calling ii does not halt processing so the computation will
continue until its natural completion, perhaps modifying the values of
the local variables to new values after the lexical position of the call to
ii.
If you want to look at the entire stack of environments and stack variables,
call <error "some error message"/>
Type Checking
By declaring parameter types and return_types for methods and turning
type_checking on, you can catch bad arguments or returned values.
Example:
<defmethod foo a_num=required=integer return_type=string> true </>
<set_type_checking "error"/> This may also be done via the Steam window Options menu,
Type Checking submenu.
<foo 3.2/> errors because the parameter is declared to be of type integer but a float was passed in.
<foo 1/> errors because the method returned true, a boolean but was declared to return a string.
Note that changing the setting for Type Checking does not affect other causes of errors.
Development Strategy
Water and the development environment lends itself well to highly incremental development.
Write just a line or two before verifying that it works. Do lots of little
test cases to methods. Using the method "test" to make formal test cases
will help out. Select an expression, click right and choose <test /> to
wrap a call to test around your expression.
Using the Tools menu item Execute Next Expression (or typing Alt+N) lets
you very easily execute successive expressions. This is especially useful for
quickly executing a bunch of calls to "test" and seeing which ones fail.
See also: stepping, set_type_checking, get_type_checking, echo, error, iip, inspect, try<defclass _id="defclass"='ek_expression' rest="all"='ek_expression' other_named_args=true='ek_code' />
When you want to make a new object you can just create one at random a la
<thing />
But if you want it to act like a "class" and link it into the type hierarchy, i.e.
have its parent contain a field with the name of the new object and a value of the new object,
then it is easier to say
par.<defclass kid color="red" />
In this case, the value of par.kid will be your new kid object created by the call to defclass.
All expressions in the content of a defclass get executed during the defclass call
with "_new_object" bound to the new object.
It is common to use "_new_object" to initialize stuff within the new object.
The value returned from defclass will be the new object being defined,
which is not necessarily the value of the last expression in the body of a defclass call.
The syntax and functionality of the arguments you pass to defclass to define each field
is very similar to the parameters of a method. Read the documentation about defmethod
for a complete description.
See also: thing.init "subject and new_object", cache_instance,
inherit_field_order, defmethod.<defmethod _method_name=null='ek_expression' rest="all"='ek_expression' other_named_args=true='ek_expression' />
A call to defmethod creates a new method, binds it to a field in the _subject,
and returns the new method object.
The first argument is the name of the method. It becomes a field key in
_subject whose value is the new method object. The rest of the attributes name parameters
to the new method. The content of the call to defmethod contains the code that describes
the behavior of the method.
The name parameter:
<defmethod foo /> will create a method with a name of foo. The new method will be
the value of a field named "foo" in the subject of this call which at top level will be thing.
You may create a method in an object, say the string object with:
thing.string.<defmethod foo />
You can make an "anonymous" method if you really don't care about naming the method.
Example: <defmethod> 123</>
This call to defmethod returns a method that, when called, returns the number 123.
If you want to use this method you must save it away in some variable or
use it immediately in a call such as: <<defmethod> 123</>/> returns 123.
Parameter Names
<defmethod foo p1 /> designates a parameter named "p1" which is required,
can be of any type, and is of execution kind "ek_code".
Parameter Default Values
<defmethod foo p1=78 /> designates that p1 is optional and that its default
value is 78. The default value is given as code that is executed when the
method is called without the specified argument. The code is executed in the
environment of the method definition. It may not contain references to other
parameters of the same method call.
You may also use required or null to indicate required and optional explicitly.
Example:
<defmethod foo arg1=junk />
junk is an expression indicating a default value.
If your call does not pass that arg, i.e. <foo/>, then the default expression, in this case
"junk" will be executed in the outer lexical environment of each call to <foo/>.
Parameter Types
To indicate a type to a parameter you must specify a default value like so:
<defmethod foo p1=78=integer />
This indicates that the value passed in for this parameter must be an integer.
As of April 2001, the parameter type is for documentation only. No actual checking
is done to verify that passed in arguments conform to the specified type.
Parameter Execution Kind
How the argument is processed at the time of the method call is determined by
the execution kind of the parameter.
There are four execution kinds:
- "ek_code" (the default) The source code of the argument is read and executed
before being passed to the method.
-"ek_expression" The source code of the argument is read but not executed
before being passed to the method. An expression such as
a variable, a path, a call, a number, a string, or a boolean will
be passed.
-"ek_string" The source code is not read or executed but is just passed in as a string.
When using "ek_string" for an execution kind, be aware that for
an "attribute" arg i.e. any arg that is not the content arg,
when passing in a value, the actual source code string for the
arg must be a valid Water expression. For example, in calling the method
<defmethod foo arg=required="ek_string"> </>
you can not pass in an arg that contains a single quote
because the single-quote is an invalid char. You can however have:
<defmethod foo content=required="ek_string"> </> <foo> don't</>
-"ek_hypertext" A vector is created of strings and other objects.
All the text before the first open angle bracket will become the
first element of the vector. It is not read or executed.
The source from the first open angle to its closing angle will be read and executed.
The result will become the next element of the vector.
Each successive string or call will be treated as a string or code to be executed.
Example:
<defmethod foo p1=78=integer="ek_code" p2=79="ek_string">
1.<plus p1/>
</defmethod>
Rest is a special arg that, if a defmethod id defined to take it, collects all the
args after the last defined named parameter into one vector.
Example:
2.<plus 3 4/> returns 9
If a rest arg is allowed we can also pass it in as a vector by naming
the arg in the call like so:
Example:
2.<plus rest=<vector 3 4/> /> returns 9
And we can combine both techniques.
Example:
2.<plus rest=<vector 3 4/> 5 6/> returns 20
To define a method that takes "rest" arguments, just make one of its
arguments "rest".
<defmethod foo weight rest>
rest.1
</>
<foo 32 42 52 62/> returns 52 because while executing the code of foo, the
local variable "rest" is bound to an object that has fields of:
0=42, 1=52, 2=62. So rest.1 returns 52.
Note that 32 is bound to "weight".
When there are both required parameters and rest, the position-passed arguments map to
the required arguments. If there are any additional position-passed arguments,
then they will be put in the "rest" object.
Methods that take optional arguments as well as rest arguments will bind
the non-required position-passed arguments to rest, not to the optional args.
To pass an optional arg to a method that takes rest, you must pass it by keyword.
Example:
<defmethod foo weight height=22 width=33 rest>
<vector weight height width rest.0 rest.1/>
</defmethod>
<foo 100 200 300 400 500 600/> returns <vector 100 22 33 200 300/>
because height and width use their default values whereas
<foo 100 height=200 width=300 400 500 600/> returns <vector 100 200 300 400 500/>
Content is a special arg that's passed in the body of an element.
Example:
<thing> 3 5 7</> gives thing a field named "content" with a value of a vector
of items 3 5 and 7.
We can do the same thing via:
<thing content=<vector 3 5 7/>/>
To access the 2nd item of the vector that's the value of content:
<thing content=<vector 3 5 7/>/>.content.1 returns 5
Defclass is very similar to defmethod with the treatment of its parameters.
It has required, optional, rest, pass by keyword, default values, types and
execution kinds.
Return Type
You can declare the return type of a method with a special "parameter" named "return_type".
Example:
<defmethod foo a_num=required=integer return_type=string> true </>
<set_type_checking "error"/>
<foo 2.3/> errors because the parameter expected an integer but was passed a float
<foo 1/> errors because the returned value was 'true', a boolean but was declared to
be a string.
Execution of a Call:
Take the call 1.<plus 2/> for example:
1 is the subject.
plus is the method name
2 is the argument.
1 is executed and returns 1 (numbers are self-evaluating).
plus is looked up in 1. 1 has no fields so we look up plus in the parent of 1,
which is integer. Integer may not have a plus field so we look in its parent,
number. Number has a plus field so we get its value, the plus method.
You can see this by executing 1.plus, often useful in debugging.
2 is executed and returns 2.
Since the value of plus is a method, we now call the method.
(If plus were not a method, we would make an instance of it.
See the doc on defclass.)
In calling, first local variables are made of each parameter of the method.
In this case, plus has only one parameter, but it is "rest" which means it will
be bound to a vector of the arguments passed to plus. We also bind the local variable
'_subject' to the subject of the call, in this case 1.
With all of our parameters and '_subject' bound to the values passed in, we now execute the
'implementation of 'plus'. If there are any local variable references,
they execute to the values that have been passed in.
In this case, _subject will execute to 1 and
rest.0 will execute to 2.
The last expression executed in the method implementation has its value returned.
You can explicitly call 'return' to make an early return,
but usually that's not necessary.
See also: "subject and new_object", optional, defclass, return, debugging,defmethod.<copy include=return_true=defmethod limit=optional include_limit=true other_named_args=true />
Creates (and returns) a new method that is the same as the '_subject' method, but with either new arguments, new default values, and/or a new implementation. The new implementation should be put in the content of call to copy. New or changed arguments should be passed as attributes in the call to copy. This only works for default values. It does not yet support types and execution_kinds for a parameter. Similar to: <foo.<copy/>.<set bar=20/> /> Also known as 'currying'. After copy has copied the fields to copy, if a field of other_named_args exists in the original, it is copied into the new copy. Thus you may not add a field to the copy named "other_named_args" if that field is not in the original. <defmethod foo bar=10> "hello".<concat bar/> </> <test <foo/> "hello10"/> <test <foo.<copy bar=20 baz="aaa"/>/> "hello20"/> <test <foo.<copy> "bye" </> /> "bye"/> <test <foo/> "hello10"/> <defmethod foo bar=10> "hello".<concat bar/> </defmethod>. <copy bar=20/> Will give same result as: <defmethod foo_copy bar=20> "hello".<concat bar/> </defmethod> <defmethod foo bar=10 other_named_args=true> "hello".<concat bar/> </defmethod>. <copy bar=20/> Will give same result as: <defmethod foo_copy bar=20 other_named_args=true> "hello".<concat bar/> </defmethod>
Removes the email of the given index from host of user.
An index of 0 (the default) removes the oldest email.
An index of 'latest' means remove the newest one.
If their are email messages in '_subject', then we will removed
the email message with the highest number on '_subject', which is
not necessarily the highest one on the server since email may have
come in to the server since we last retrieved messages.
An index of 'all' removes all the email for user.
If there are email messages in '_subject' then just remove all of those,
which are not necessissarily all those on the server as more may have
come in since we retrieved messages.
'where' tells where messages will be deleted from, client, server, or both.
client means just the email messages in '_subject'.
server means leave '_subject' alone and just delete messages on the server.
both means delete the messages in both. 'both' will always remove the
same numbered message (or messages, if index="all") from both client
and server. Thus if there are 3 messages on the client, then only nessages
0, 1 and 2 from the server will be deleted.
It is recommended that either you delete mail from the server using
<get_email index='all' delete=true/> and use
<delete_email index=0 where="client"/> or use
only the server via
<get_email index=0 delete=false/>
<delete_email index=0 where="server"/>
or, living dangerously,
<get_email index=0 delete=true/>
or,
<get_email index="all" delete=false/>
<delete_email index=0 where="both"/>
Returns true if successful, false otherwise.To do: show example of environment setup in startup.sh
showing correct system folder when using a .jar file
A Steam Engine may be deployed in a Servlet Engine as a Java Servlet.
You can configure a Servlet Engine (for example, Apache Tomcat)
to route requests to a Steam Engine which routes requests to
the appropriate Water Server. The Water Server executes
the request and returns the result.
A Water Server can directly listen for a connection on a port,
or Apache can be configured to listen and route requests to
a Water Server.
For a standard Apache:
TOMCAT_HOME/conf/server.xml
TOMCAT_HOME/conf/web.xml
<Example name="server.xml configuration file">
<Server port="8005" shutdown="SHUTDOWN" debug="0">
<Service name="Tomcat-Standalone">
<Connector className="org.apache.catalina.connector.http.HttpConnector"
port="8080" minProcessors="5" maxProcessors="75"
enableLookups="true" redirectPort="8443"
acceptCount="10" debug="0" connectionTimeout="60000"
/>
<Engine name="Standalone" defaultHost="localhost" debug="0">
<Logger className="org.apache.catalina.logger.FileLogger"
prefix="catalina_log." suffix=".txt"
timestamp="true" />
<Realm className="org.apache.catalina.realm.MemoryRealm"/>
<Host name="localhost" debug="0" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" prefix="localhost_access_log." suffix=".txt"
pattern="common"/>
<Logger className="org.apache.catalina.logger.FileLogger"
directory="logs" prefix="localhost_log." suffix=".txt"
timestamp="true"/>
</Host>
</Engine>
</Service>
</Server>
</Example>
<Example name="web.xml configuration file">
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>Clear Methods Steam Engine</servlet-name>
<servlet-class>org.waterlang.SteamEngineServlet</servlet-class>
<init-param>
<param-name>execute_water_source</param-name>
<param-value>(server root_object=thing port=8080 host_name='localhost' listen_on_port=false/)</param-value>
</init-param>
<init-param>
<param-name>starting_uri</param-name>
<param-value>logical://user/</param-value>
</init-param>
<init-param>
<param-name>license_key</param-name>
<param-value>930583372304105</param-value>
</init-param>
<init-param>
<param-name>system_folder</param-name>
<param-value>file:///D:/jakarta-tomcat-4.1.18_test/common/classes/</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>org.apache.catalina.servlets.InvokerServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Clear Methods Steam Engine</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<session-config> <session-timeout>30</session-timeout></session-config>
</web-app>
</Example>Running Water: Deploying a Pure Water Program
If you have a Water program that is running in your IDE, and you want to deploy
it, this document will describe how to do it.
The deployment of a Water program is actually quite simple and
can be done without any Wizards or GUI tools.
==========================
Step 1: Prepare your Water program
Your program should be stored in an .h2o file that is the name of your
program. For this example, we will assume your program is stored in a
file named "my_app.h2o". The content of the file is Water source that
creates Water objects. If your program consists of multiple files,
your main program file, my_app.h2o, needs to load those files.
Your application should have been tested through a standard Web browser.
Executing your my_app.h2o file will define your program objects, and
then creating a Water server for your application would look like:
<server root_object=my_app/>
To prepare your Water program for deployment, you should not
create any Water servers in your program files. Comment out any
Water expressions in your program that create servers.
The last expression of your main program file (my_app.h2o) should return
the root_object that will be served.
For a simple "Hello World" application the contents of the file would be:
--------------------------
"Hello World"
--------------------------
==========================
Step 2: Choose a computer
The computer for deploying your Water program will need to be accessible
to the users of the program through a standard HTTP port. For this example,
we will assume that the address "www.my_server.com" will point to your
"server box".
==========================
Step 3: Store your Water program
Your Water program will usually be stored in one or more .h2o files.
You need to upload this file (via FTP or other means) to a folder on
your server box. This file should not be accessible to end users -- only
to people who are releasing or managing your systems.
Let's say that you saved your program file on the server box at:
C:/water_apps/my_app.h2o
==========================
Step 4: Create a JNLP file
The JNLP file is used by Java Web Start to start a Java program. The
JNLP file will contain the information to load the Steam Engine, load
your Water program, and create one or more Water servers.
Create and store a JNLP file at some location that is only accessible
to system administrators of the machine. By convention, the JNLP file
will be either in the folder containing the Water program files or in
a folder parallel to it.
The example below is the entire contents of a default JNLP file.
Any value between the double-hash marks (##) needs to be changed for
your application.
Contents of my_app.jnlp:
------------------------
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="##file:///C:/apps##" href="##my_app.jnlp##">
<information>
<title>My App</title>
<vendor>My Company</vendor>
</information>
<security> <all-permissions/> </security>
<resources>
<j2se version="1.4"/>
<jar href="http://www.waterlanguage.org/product/steam_engine.jar" main="true"/>
<jar href="http://www.waterlanguage.org/product/steam_ide.jar"/>
<extension name="regex" href="http://www.waterlanguage.org/product/regex.jnlp" download="lazy"/>
</resources>
<application-desc main-class="org.waterlang.Start">
<argument>
execute_water_source="
(server root_object='##file:///C:/apps/my_app.h2o##'.(execute_file/)
port=8080/)
"
starting_uri="logical://user/"
license_key="##0583372304105##"
system_folder="webstart"
</argument>
</application-desc>
</jnlp>
------------------------
The following files should now be on your server box.
C:/water_apps/my_app.h2o
C:/water_apps/my_app.jnlp
The typical JNLP file will load the main program file and start a
single Water server on a particular port. The Water code for this
action is the value of the "execute_water_source" attribute above.
It can contain any Water source, but any angle-brackets
need to be replaced by parentheses. Also, only single-quotes are
allowed in the source -- no double-quotes.
The default Water expression in the above JNLP file creates a server
with a root object. The root object is returned from executing
your main Water program file.
==========================
Step 5: Start the Water Server
Double-click on the "C:/water_apps/my_app.jnlp" file to load your application
and create a server for it.
To start your program from the command line, call "javaws" with the URI to
your JNLP file:
"C:/Program Files/Java Web Start/javaws" "file:///C:/water_apps/my_app.jnlp"
You might want to configure your server to automatically start your Water
program.
==========================
Step 6: Test the Water program
Once your Water program successfully loads, you can hit the server
with a Web browser at: http://localhost:8080/
...or use the name of your server:
http://www.my_server.com:8080/Derives a class from example instance data.
The 'parent_class' argument is an existing class
object or the string name of a new class to create.
<Example
<data> <person first="Mike" age=28/> </data>.
<derive_class parent_class="HQ"/>
<!-- RETURNS: -->
<defclass HQ>
<defclass person first=required=string
age=required=integer
/>
</defclass>
/>
The instance data can represent multiple classes. Each new
class will be a subclass of the parent_class. The example
below shows how the 'person' and 'address' classes were
created under the parent_class named 'HQ2'.
<Example
<data>
<person name="Mike" mail=<address street="33 Park"/> />
</data>.<derive_class parent_class=<defclass HQ2/> />
<!-- RETURNS: -->
<defclass HQ>
<defclass person first=required=string
mail=required=address
/>
<defclass address street=required=string/>
</defclass>
/>
The data is assumed to be "normalized"
ConciseXML data. See 'normalize' for how to
automatically convert XML 1.0 data to ConciseXML
data.
See also: normalize, data<do repeat=optional=number.integer rest="unnamed"='ek_expression' />
'do' executes all its arguments (it has rest arguments) and all the expressions in the content,
and returns the value of the last one.
Examples:
<do 2 3 4/> returns 4
<do 2> 3 4 </do> returns 4
If there is a call to 'while' and/or 'until' in the content of a do call, then do will loop.
Here's the order of execution.
First each rest argument is executed in order. You may not have a call to 'while'
in the rest arguments. The rest arguments are executed only once, at the beginning of the call.
Next each expression in the content is executed.
If a call to while is encountered, then 'do' will loop through its content until
a first argument in a call to while returns false. When that happens the
content of the while call is executed once. The value of the last expression in the while content
is returned from the 'do'.
'until' is very much like 'while' except that it "hits" when its first argument executes to 'true'.
'while' hits when its first argument executes to 'false'.
The content of a 'do' call may have any number of calls to 'while' at top level within the content.
A call to 'while' may be at the top of the loop, at the bottom of the loop, in the middle,
or all three places if you like.
The first one whose first argument executes to false will be the one that halts looping
and has its content executed to make the value to return from this call to 'do'.
If there is no content, then the value of the last rest argument is returned.
If there are no expressions in do, then null is returned.
Example:
<do <echo "one"/> <set count=0/> >
<echo "two"/>
<while count.<less 2/> > <echo "in while" count/> </while>
<set count=count.<plus 1/> />
<echo "three"/>
</do>
This call prints out 7 lines: "one", "two", "three", "two", "three", "two", "in while 2",
then returns 2.
Here's the execution flow:
First the call <echo "one"/> is executed, then the call <set count=0/> .
We then enter the content and execute <echo "two"/> .
Next the call to while is encountered.
The expression count.<less 2/> is executed. Since 'count' is 0, it returns true
and execution proceeds to <set count=count.<plus 1/> /> and <echo "three"/> .
We are now at the bottom of the do content but since we encountered a call to 'while',
we continue by executing the first expression in the content, <echo "two"/> .
Next the condition of while returns true again since 'count' is 1.
We proceed on to executing <set count=count.<plus 1/> /> and <echo "three"/>
then back to the top of the content.
After executing <echo "two"/>, the call to count.<less 2/> returns false since
count is now 2. Now the content of the call to while is executed.
Here it is just a single expression (but could be many) of <echo "in while" count/> .
After printing to the console, echo returns the value of its last argument, count,
which is 2. That 2 is returned from the entire call to 'do'.
In addition to while and until calls in the content, 'do' may have a 'repeat' attribute.
The value is the number of times to execute the content.
Example:
<do repeat=3 "hi".<print/>> "hello".<print/> </do>
This call to do prints out to the console:
hi
hello
hello
hello
and returns the value of the last call to print which is "hello".
When do has a content, it maintains the number of the iteration in a local variable
whose name is 'counter'.
Example:
<do repeat=3> counter.<print/> </>
print to the console:
0
1
2
and returns the value of the last expression which is 2.
The counter variable is maintained whether you use repeat, while, until or any combination
of those including none.
Example:
<do> counter </> returns 0.
The counter is not available in the rest args, i.e. <do counter/> will error because
counter is not in the content and therefore not bound.
If you use both repeat and while and/or until, whichever one would stop the looping first
does stop the looping. Thus you might have tricky logic using 'while' but just to make sure
you don't write an infinite loop, you may set 'repeat' to a number higher than you
ever expect to go say, 1000, just to be sure to stop runaway code.
If repeat is set to null, then it will not stop a while or until loop. However,
if no while or until is used in the content, then the content will be executed just once.
If repeat is set to 0 then the content will never be executed, but, as usual
the 'rest' args to 'do' will be executed and the value of the last will be returned.
<do> <while true/> </> and <do repeat=null> <while true/> </> have the
same behavior, i.e. they loop infinetly.
If an error is encountered while executing the expressions in the content of a do
then a call to 'if_error' is looked for in the top level of the content of the do,
below the expression that errored. If such a call to 'if_error' is encountered,
then the expressions in the content of the call to 'if_error' are executed.
Example:
<do> <error "errors happen"/> <if_error> 992.<plus 1/> </if_error> </do> returns 993.
In the content of the if_error call, you may reference the local variable 'error_object'.
It is bound to the string of the error message.
If the last cause in the content of a call to do is a call to 'finally', then the
expressions in the content of the call to finally are always executed exactly once
and they are the last expressions executed in the call to 'do'.
Example:
<do repeat=3> <print counter/> <finally> <print "done"/> </finally> </do>
The numbers 0, 1 and 2 are printed, then "done" is printed.
There can be at most one call to finally in a call to 'do' and it must be
the last expression in the content.
Returned Value
In general 'do' returns the value of the last expression it executes.
This means that:
- If there is no content, the value of the last rest arg is returned.
- If there is a content and there are no errors, no while, until or finally calls,
then the value of the last expression in the content is returned.
- If there is a while, until or if_error call that is executed and no finally, the
value of the last expression in the content of the executed while, until or if_error
is returned.
- If there is a finally call, then the value of the last expression in the content of the finally
is returned except:
If the last expression executed before the finally happens to be a return
that returns from the 'do' or above, then the finally expressions will be executed
for side effect only, and the return will be processed as it normally is.
Examples:
<do 2 3> 4 <while counter.<less 3/>> 5 </while> <finally> 6 </finally> </do> returns 6
<do 2 3> 4 <error/> <if_error> 5 </if_error> <finally> 6 </finally> </do> returns 6
<do 2 3> 4 <while counter.<less 3/>> <return 5 "do"/> </while> <finally> <print "done"/> </finally> </do>
returns 5 but still prints "done".
<doc
name=optional='ek_string' fields=optional precond=optional=
Water supports the ability to add documentation to any object. The following code first creates documentation for book and then defines the book class. <Example> <doc book> This is the documentation for book. </doc> <defclass book isbn title/> </> In the IDE, to retrieve the documentation for an object, just double-click on the name of the object in the editor to show its contract in the HTML viewer. Click on the link to open the documentation window. The documentation is stored in the 'doc' meta-field. The following example shows how to programmatically get the doc string for book: thing.<get <field_key "book" "doc"/> /> In some cases, the documentation for an object might exist in another file. For that case, the documentation will likely be loaded after the object is defined. <Example> <defclass book isbn title/> book.<doc> This is another way to add doc for book. </doc> </> You can add documentation to any subclass or individual methods. <Example integer.number.<doc plus> This is documentation for 'plus' </doc> /> Examples can be included in the documentation. <Example book.<doc> Examples can be included in the documentation. <Example 1.<plus 1/> result=2 /> </doc> />
<doc_field key=required='ek_string' />
Set the documentation string for the field named in the first argument to
the string in the content.
Example: thing.boat.<doc_field rudder> The steering mechanism</doc_field>
thing.boat.rudder_f_doc returns " The steering mechanism"<duration years=0 months=0 days=0 hours=0 minutes=0 seconds=0 milliseconds=0 />
A duration is a time interval. You create one by passing in any number of
years, months, days, hours, minutes seconds, milliseconds.
These values are all added up to create the duration.
Note that the values passed in need not conform to their normal range restrictions.
For example you can create a duration of 45 days, or
14 months and 92 minutes.
Some care in using durations must be exercised. A year is considered to have 365.25 days
to account for leap year. The days per month is considered to be 365.25 divided by 12.
Durations are kept as a millisecond resolution but the above considerations may make only
the higher level values meaningful to your application.
When you are getting values out of a duration you may use
singular nouns: year, month, day, hour, minute, second, millisecond
to get the "limited" version [ie month will always be between 1 and 12 inclusive]
or the plural form: years, months, days, hours, minutes, seconds, milliseconds
to get the full duration in terms of those units.
Examples:
<duration months=18/>.year returns 1
<duration months=18/>.month returns 6
<duration months=18/>.years returns 1.5
Durations have comparators: equal, less, more less_or_equal, more_or_equal
and arithimetic: plus, minus, times, divide.
See also 'datetime' for datetime.<plus duration/> and datetime.<minus duration/><echo rest=required />
Takes any number of arguments. Prints out their values and returns the value of the last one. echo is intended to be for debugging print statements. use 'print' or 'status' for permanent parts of code, then you can easily search for calls to 'echo' and remove them once your code works.
returns true if string ends with a_string, otherwise returns false. If case_sensitive is false, the case of the strings doesn't matter.
<equal an_object=required case_sensitive=false=boolean whitespace_sensitive=false=boolean />
This is a "deep" comparison of "_subject" and the first argument. Two objects that are the same or whose field values are equal are equal. Pass in case_sensitive and/or whitespace_sensitive of true to have especially liberal comparison of strings. whtespace_sensitive=false (the default) means that all whitespace in the strings are ignored for the purposes of the comparison. Returns true if "_subject" and an_object are equal, false otherwise. Since this method can walk large object trees, it may be expensive. equal is careful to handle circular data structures without infinite recursion. Two objects which are the same in all ways except that they each point to themselves from the same field are "equal" but they are not "same". See also "same".
<error message="an error occurred"=string />
Prints its string argument in the Java console and stops all processing.
See also "try".
Example:
<try <echo "did it"/> <echo "did it2 "/> <error "hey"/> <echo "did it3"/> >
<echo "caught it"/>
</>
When this call to try is executed,
1. "did it" is printed on the console,
2. "did it2" is printed on the console
3. "hey" is printed on the console
4. "did it3" is NOT printed because that call to echo is never executed.
5. The expressions in the content of the TRY call are executed.
In this case there's only one, so
"caught it" is printed on the console.
6. The value of the last expression in the content of TRY is returned,
in this case the string "caught it".
See also: warning<execute env_or_context=null execution_kind="ek_code" returns="last" />
If _subject is a string, read the string and evaluate the resulting expression.
This is similar to execute_string.
If _subject is a file, read each expression in the file and evaluate it,
returning the result of the evaluation of the last expression.
This is similar to execute_file
If _subject is anything else, send the object, usually an expression to
the evaluator. This is similar to execute_expr.
env_or_context is the environment to evaluate the expression in.
An env is just an object that contains the binding of local variables.
Examples:
"2.<plus 3/>".<execute/> returns 5
"2.<plus aa/>".<execute <thing aa=7/>/> returns 9
Execute can also take Water expressions to execute as the content argument:
<execute> 2.<plus 3/> </> returns 5
Execute takes an executing_kind argument. This defaults to "ek_code"
"ek_code" Treat the _subject or content as an expression and execute it.
"ek_expression" Just returns the subject or the expression(s) in the content
"ek_data" Converts the _subject or content into "data".
"ek_string" If there's a content, just return that string.
else if there's no content, error.
See also: execute_string, execute_expr<execute_expr env_or_context=null execution_kind="ek_code" returns="last" />
Takes an expression as "_subject", executes it and returns the result.
Examples:
<expr>foo</>.<execute_expr/>
a_vec.<for_each> value.<execute_expr/></> executes each expr in a_vec
and returns the last one.
The env_or_context parameter is documented in execute_string.
See also: execute_string<execute_path rest=optional='ek_expression' />
Has the same functionality as a normal path using dot notation,
but calls to execute_path are XML 1.0 friendly because the path parts
are in the content (or attributes), and execute_path does not
use dots between path parts.
Example: <execute_path> thing number integer </>
returns thing.number.integer<execute_string env_or_context=null execution_kind="ek_code" returns="last" file="No file" offset=0 />
Each expression described in the string is executed in order.
Example: "2.<plus 3/>".<execute_string/> returns 5
If returns is "last", the default, only the value of the last expression is returned.
If returns is "all", then a vector of the values of all the top level expressions is returned.
"env_or_context" is shared for the execution of all the source so you can
set a local variable in one form then use it later in the source.
Typical values for env_or_context are:
null use the default environment
_environment use the environment of the call to execute_string.
<environment_of_call/>
Example:
<defmethod foo w>
<set x=5/>
"w.<plus x/>".<execute_string _environment/>
</defmethod>
<foo 7/> returns 12
The execution_kind argument determines how a string is to be executed.
"ek_code" (the default) the source for an argument is evaluated as code.
"ek_string" the source is not evaluated, nor parsed, it is just used as is, as a string
"ek_expression" the source is parsed and a parsed representation of the source is returns.
This will be one of the following kinds of objects:
string, number, boolean, null, character, ie the literals, and expr_call, expr_path.
"ek_data" the source is parsed and a very limited kind of evaluation is performed.
The types of objects returned will be:
string, number, boolean, null, character, i.e. the literals, and "data objects"
and data_paths.
No lookup of variables occurs and no calls are executed. However, literals
are created. Variables are turned into "symbols", i.e. objects that have
as their parent thing.symbol and have a name field of the string of the variable.
Calls are turned into water objects with a parent of a symbol of the call name
and fields corresponding to each field in the input whose values have
been executed with an execution kind of ek_data. This are "data objects".
Example: "<foo 2 color='red'/>".<execute_string execution_kind="ek_data"/>
returns an object whose parent is a symbol with name="foo" and
has two fields: 0=2 and color="red".
There are three special rules for calls.
1. If the name of the call is "char" then the appropriate character is created.
2. If the name of the call is "vector" then a vector is created with
vector fields of values that are the ek_data-executed results of their sources.
Example: "<vector foo bar 4/>".<execute_string execution_kind="ek_data"/> returns
an object <vector <symbol "foo"/> <symbol "bar"/> 4/>
3. If the name of the call is "thing", then an instance of thing is created.
For all other calls, the parent of the returned object is an instance of symbol
having a name of the symbol in the call.
Paths are turned into water object with a parent of thing.data_path
and vector fields of values of the ek_data executed results.
Example: "foo.bar.4".<execute_string execution_kind="ek_data"/> returns
and object <data_path 0=<symbol "foo"/> 1=<symbol bar/> 2=4/>
See also: execute_expr, execute_file<expr returns="first" />
In normal processing, Water takes a string of source code, parses the string
into a expression objects, then executes each expression to create
resulting value objects. Lisp has the notion of expressions and uses
a "reader" to create them before passing them to an evaluator.
Many other languages such as C, Java, and Javascript don't have the
concept of expressions.
In Water, rarely do you deal with expressions directly. They are an intermediate
data format that is created temporarily during the process of executing a string.
However, Water enables you to create expressions, pass them around, and eventually
execute them, perhaps multiple times.
Certain key primitive expressions are created by the Water parser and are
"self executing", that is, executing these expressions just returns the expression
themselves. These are: integers, floats, booleans, characters, strings and null.
Non self_executing expressions are: variables, calls, and paths.
Other data such as vectors and "records", regular objects are usually not
passed to the evaluator, but if they are, they are just returned as is, i.e.
they are "self executing".
Examples:
<expr>34</expr> returns 34
<expr>"some text"</> returns "some text"
<expr>foo</> returns a variable with the name "foo"
<expr>3.<plus 4/></> returns a path of two parts, the integer 3 and a call
expression to the method "plus".
If you have a string in a variable or some other code that, when executed,
results in a string and you want to parse that string into a variable use []
Examples:
<set foo="3.<plus 4/>"/>
<expr>[foo]</> returns a path of two parts, a 3 and a call to plus.
<expr><force_ek_code "foo".<concat "bar"/>/></> returns a variable expression of name "foobar".
A given string might contain the source for one or more expressions.
expr takes a parameter to tell it whether to return the first expression
in the string or a vector of all the expressions in the string.
returning the first expression is the default.
Examples:
<expr>23 45 67</> returns 23
<expr returns="first">23 45 67</> returns 23
<expr returns="all">23 45 67</> returns a vector of the three integers.<expr_to_uri_fields env=null />
path (or one thing)
for every thing in the path
convert the part
if literal path part
add literal to path
if field var
add name to path
if call path part,
if part is a get call, evaluate the arg source in local environment
and add to path
returns integer or string, otherwise error.
else
add name to path
execute each arg_source
add args to query or post-path to append.
else errorBackground
Objects are made up of fields.
Each field has a key and a value.
The key and the value may be any object though
usually the key is a string or an integer.
Meta_fields
Water has special machinery to attach "meta data" to
fields by creating "meta fields".
These meta fields are meant to hold data about a field,
which is not necessarily about the VALUE of the field but
has more to do about what kind of information may be in
the field. the Water system has meta fields for "type"
and "doc" to help users and sytem software know about potential
values for fields. Developers may add their own meta fields
using names appropriate to the domain of their application.
Meta fields must be named by a string.
Syntax
Meta fields are actually just regular fields that have
a key that is a string composed of the key of the field,
the string "_f_" and the meta key itself.
Example: "weight_f_type".
You can create meta fields in a number of ways.
The most common is when defining a method's parameter that
has a type:
vehicle.<defmethod drive speed=65=integer> </defmethod>
makes a meta field in vehicle of speed_f_type
whose value is integer.
vehicle.drive.speed_f_type returns integer.
You can also directly set a meta field via:
thing.<set foo_f_bar=23/>
thing.foo_f_bar returns 23
You can avoid knowing the details of the metafield infix "_f_"
by using the method field_key to make the key:
<field_key "foo" "bar"/> returns "foo_f_bar"
thing.<set_value <field_key "foo" "bar"/> 23/>
thing.<get <field_key "foo" "bar"/>/> returns 23
Restrictions
The meta_key itself, ie "type" must be a string and cannot
start with underscore.
You also can't have a meta_key of "key", "value", or "container".
Field Objects
Most of the time the above knowledge is all you'll need to know
about meta fields. But for more advanced work, you may find it
convenient to think about a field as an actual object
with keys of the meta-keys of the field.
In order to make a field object, use the "field" class to
make a field instance. Each field object must have a key
and may have either a container or some other meta-key fields.
Field Objects with a Container
Examples:
thing.<set weight=48=integer/>
thing.weight returns 48
thing.weight_f_type returns integer
<set my_field=<field "weight" container=thing/>/>
my_field.type returns integer
my_field.value returns 48 (Note: "value" is the default meta_key.
It stands for the regular field value.)
my_field.<set doc="how heavy it is"/>
my_field.doc returns "how heavy it is"
thing.weight_f_doc returns "how heavy it is"
When a field object has a container, it becomes a "proxy" for the
field within its containing object.
A field object with a container specifies a location as an object
and the key within the object. This can be used to get, set and test
if the field exists within the object.
Field Objects without a Container
A field object without a container can be used to "build up" a field
with all its meta-fields and their values. Then, using the
method "install_field", the field can be stuck into an object.
Once this is done, the field object cannot be used to
refer to the values in the installed field, though it can be used
to install a similar field in another object.
Examples:
<set your_field=<field key="material" value="steel" price=89 density=21/>/>
your_field.<install_field thing/>
thing.material returns "steel"
thing.material_f_price returns 89
thing.<get <field_key "material" "density"/>/> returns 21
<set stuff=<thing/>/>
your_field.<install_field stuff/>
stuff.material returns "steel"
thing.<set "material"="wood"/>
thing.material returns "wood"
stuff.material returns "steel"
Despite the fact that both thing.material and stuff.material were
originally created using the same field object, they share no
memory in common.
Implementation
Field objects have special definitions for the methods:
has, get, set_value, and set to achieve their behavior.
See also: field_key, install_field<field_key key=required a_meta_key="value" />
Given a field key and a meta_key, makes up a string that lets you access that meta_key of the field. Example: <field_key "weight" "type"/> returns "weight_f_type". The "meta_key" for the main value of a field is "value". "value" is the default value for the meta_key paramter. <field_key "weight" "value"/> returns "weight" <field_key "weight"/> returns "weight" If key is a string (the usual case) or if meta_key is not "value" (also usual), field_key returns a string, even if either or both of its arguments are not strings. Before building the return value, field_key calls to_concise_xml on both of its arguments and uses the results.
Creates a file resource from a path. <Example> <file "C:/temp/foo.txt"/> <file> C:/temp/<do "foo.txt"/> </> </> To retrieve the content of a file: <Example a_file.content /> To set the content of a file: <Example a_file.<set content="some text"/> />
<filesystem
a_uri=required=
No actual instances of local are created.
If you attempt to create one, it will be converted to a
file or folder resource depending on the uri used.
See: file and folderfilesystem.<exists />
Returns true if the file or folder in '_subject' actually exists
on disk, otherwise returns false.filesystem.<file.append rest=required />
Extends the content of the file with the rest args.
If an arg is not already a string, it is conveted to one
using to_concise_xml before it is written to the file.
returns _subject.filesystem.<file.copy_file new_file=null=filesystem.file />
Takes the original file as '_subject' and one argument,
the new file as a file object.
The new file might or might not actually exist on disk.
If it does, it's content is overwritten with the content
of '_subject', otherwise a new file is created and
its content will be the same as the content of '_subject'.
The new file object is returned.filesystem.<file.execute env_or_context=null execution_kind="ek_code" returns="last" />
Executes the code in the content of the file in "_subject".
Example: <file "C:/foo/bar.h2o"/>.<execute/>
While a file is being executed, it's string name is in thing.loading_file.
"returns" is similar to the execute_string "returns".
"first" return the value of the first expression in the file. Do not execute the other expressions.
"last" [the default] says return the last value in the file.
"all" says return a vector of all the values in the file.
env_or_context parameter behaves just as it does for execute_string and execute_expr.
Example:
The content of the file "junk.h2o" is: x.<plus y/>
<defmethod foo x>
<set y=8/>
<file "junk.h2o"/>.<execute _environment/>
</defmethod>
<foo 7/> returns 15
execution_kind is similar to the execution_kind paramter in execute_string.
See also: execute_stringfilesystem.<file.file_name />
Returns the string of the file name without its folder or
type.
Example:
<resource.local.file "C:/foo/bar.txt"/>.<file_name/>
returns "bar"filesystem.<file.insert at_key="end" rest=required />
Works similar to insert on strings, inserting the rest args into the content of the file in the _subject. The file is returned.
filesystem.<file.print_file title=null=string with_dialog=false=boolean />
Makes a hardcopy of a file. The title argument is a string that is printed at the top of each page along with the date and a page number. The default value is null meaning use the full file name as the title. To give your pages no title, pass in the empty string. The with_dialog argument determines whether a dialog to choose file printing preferences is presented to the user or not. The default is false meaning just print the file with the current settings. For that to work, the default printer must be accessible to your computer. You can see the default printer by choosing the Steam IDE's "File" menu item "Print...". Note that if you change the printer in the dialog, it does not change the default printer. The next time the dialog comes up the printer will be the same as the first time it came up. Setting the default printer is operating system dependent. On the Windows operating system choose Start/settings/printers. In the dialog that comes up, select the icon of the printer you'd like to be the default printer, and choose the File menu item of "Set as Default". print_file only works if the Steam IDE is loaded. Example: filesystem.<file "logical://user/scratch_1.h2o"/>.<print_file "My Junk"/>
filesystem.<file.set _encoded_set_keycontent=null />
set with a '_subject' of a file can only take one argument which must be
the content whose value must be a string.
the content of the file will be set to the string.
Note that you must use:
a_file.<set content="some value"/>
ie you must use the key "content".
If the new content is not a string, then to_concise_xml is called
on it and the resulting string is written to the file.filesystem.<file.subvector start=0=number.integer end=optional=number.integer />
Works similar to subvector on strings, returning a substring of the content of the file.
To write the content of a file, use the syntax:
a_file.<set content="new content"/>
Note that if the new content is a string it writes out the string.
If the new content is a hypertext object, then the to_html
method is automatically called on it to convert it to a string
before writing to the file.
If the new content is another kind of object, then the
to_concise_xml method is called on it to convert it to a string
before writing to the file.filesystem.<file.write_zip_file manifest_content=null rest=true />
Creates a jar or zip file whose name is specified by '_subject' which
should have an extension of .zip or .jar .
The rest args are input files.
whose content will be included in the output file.
These can be strings, files or folders. If it is a string ending in a slash
or a folder, the files in the folder, and the files in any subfolders,
recursively on down will be added to the output file.
jar files should have a manifest file included in them.
If manifest_content is null (the default) and the extension of the
output file is not ".jar", no manifest file is
included in the written file.
If manifest_content is null and the extension of the
output file is ".jar", a default manifest file is
included in the written file.
If the manifest_content is a string, then that string is used as the content
for the manifest file in the output file.
Example:
<filesystem.file
<uri "file:///C:/My Documents/waterdev/deploy/water_full.jar"/>/>.
<write_zip_file
<filesystem.folder "file:///C:/My Documents/waterdev/water/ide/lib/"/>/>
_subject creates a new file named water_full.jar which includes all
the files under the ...ide/lib/ folder.Returns a vector of the files in '_subject', its subfolders and
recursively all the way down.
The returned vector will also contain any files already in 'result'.
If 'result' is passed, it is returned with the found files added.
If 'result' is not passed, (the usual case), a new empty vector is made.A folder represents a diretory of files and subfolders.
asking for the content field of a folder returns a vector of file and folder objects
of the files and folders within the folder.
A .zip or .jar file behaves very much like a folder. When creating one,
you should create it as a folder. Asking for its content will return a vector
of the files within the zip or jar file.
The full path for a file within a zip file is
the_zip_file_name/the_inner_file_name
Note that both the_zip_file_name and the_inner_file_name may themselves have
slashes in them.
Given a file object that is in a zip file, you can get its content field
to get the string of the content of the file just like regular files.
You can also execute such a file out of a zip file using the same syntax
as regular files.
Creating or writing zip files is not yet supported.<for_each include=regular_key returns="last" exclude=null />
for_each is the most useful looping construct of Water.
Example:
<set my_colors=<vector "red" "green" "blue"/> />
my_colors.<for_each> it.<set_value key value.<concat key/>/>
</for_each>
my_colors returns <vector "red0" "green1" "blue2"/>
The content of for_each is executed once for each element in "_subject".
During that execution,
"it" is bound to the object whose fields are being looped over
"key" is bound to the name of the field within "it" currently being looped over and
"value" is bound to the value of that field.
"_subject" is bound to "_subject" of the outer environment to the call.
Other local variables that are bound before the call to for_each,
but in the same lexical scope (such as the same method body) will still be
bound each time the body of the for_each is executed.
By default the object being looped over is treated as a vector and only its integer
fields are looped over starting with field 0 (zero).
The "include" argument is usually a method that determines exactly which fields to loop over:
The system provides several methods that were made expressly for the value of include:
vector_key (the default) Passes the integer-named fields in a vector.
This method is handled specially by for_each for performance and to
process only those integer fields from 0 to just under the length of the node.
system_key Passes fields such as "_parent". Rarely used.
meta_key Passes only field names that are strings that contain an _f_ substring.
string_key Passes all non_system, non_integer, non-meta_key named fields.
regular_key Passes all user fields and all integer-named fields that
are non-negative.
non_system_key Passes all non_system field keys, thus it passes string_keys,
vector_keys, meta_keys, and negative integer fields.
return_true Passes all fields.
You can write your own methods to include other fields than the above methods allow.
The method is called with each key as "_subject".
If the method returns false, the field will not be processed, otherwise it will be.
Examples: <defmethod is_user_or_integer_field>
_subject.<string_key/>.<or _subject.<is_a integer/> />
</defmethod>
<defmethod my_vehicles>
<vector "boat" "plane" "car"/>.<key_of _subject/>
</defmethod>
If the value of "include" is NOT a method, then it is considered to be a vector of
the valid field names to loop over.
Examples:
<vector 100 101 102 103/>.<for_each include=<vector 0 3/> returns="all">
value
</for_each>
returns <vector 100 103/>
<thing color1="red" color2="white" color3="blue"/>.
<for_each include=<vector "color1" "color3"/> returns="all">
value
</for_each>
returns <vector "red" "blue"/>
The exclude parameter, like the include parameter can take a method or a vector.
If a field name passed the include test, then it is tested against the exclude parameter.
If the field name is either in the exclude vector or the exclude method is called
and returns true, then the field name is excluded and not looped over.
Example:
<vector 100 101 102 103 104/>.
<for_each returns="all" exclude=<vector 1 3/>> key </>
returns <vector 0 2 4/>
Early Return:
You can force for_each to exit the loop and return a value by calling
<return some_value "for_each"/> within the content of for_each.
If you call <return some_value "the name of the current method"/>
then the for_each loop will be exited and so will the
containing defmethod, which will return "some_value".
Normal Return:
If for_each does not hit an early return, what it returns depends on the value of the "returns" arguments.
"last" (the default) returns the value of the last expression in its content that was executed.
"all" returns a vector of the values of all the last expressions from each iteration.
"all_except_null" like "all" except nulls are not included in the returned vector.
Example:
<vector 9 8 7/>.<for_each returns="all"> value.<plus 1/> </for_each>
returns <vector 10 9 8/>
<vector 33 null 32 null 31/>.<for_each returns="all_except_null"> value </for_each>
returns <vector 33 32 31/>
Beware: Do not loop over the fields of an object that you are changing
in the code of the content of a call to for_each. You need to get all
of the keys first, then interate through them and change the object
that they came from. You can get the keys via the 'keys' method.
Note in the examploes below pretend that the call to 'echo' is
really code that modifies mything.
example:
<thing color="red" weight=2/>.<keys/>.<for_each> <echo value/> </for_each>
but that leaves you with 'value' inside of the for_each bound to the
key that you're after. You use this value to get the real value from
the object via 'get' like so:
<thing color="red" weight=2/>.<keys/>
<set mything=<thing color="red" weight=2/>>
mything.<keys/>.<for_each>
<echo value mything.<get value/> />
</for_each>
</set>
A more elegant way to accomplish the task is to use the 'include'
parameter of for_each and they the key and value variables will be bound
as you would expect.
<set mything=<thing color="red" weight=2/>>
mything.<for_each include=mything.<keys/>>
<echo key value/>
</for_each>
</set><force_ek_code obj=required />
Most parameters to methods have execution kind of "ek-code". This means that the source code for the argument in the call will be executed and the result of that execution will be passed in to the method as the value for that parameter. You can change this default behavior by indicating another execution_kind for the parameter when defining the method. See documentation on "execution_kinds" for the possibilities. Occasionally a caller to a method will want to execute the argument source code even though the method definition specifies not to. You can override the method specification by wrapping the source code for the argument in a call to "force_ek_code". Example: <defmethod foo acolor="red"=string="ek_string"> acolor </> <foo blue/> returns "blue". In the call you don't have to wrap double-quotes around blue. But if we want to compute the color instead, we must force_ek_code like so: <foo <force_ek_code "blue".<concat "green"/>/>/> returns "bluegreen". Using force_ek_code makes sense only for non-content arguments and only for arguments that are of execution_kind ek_string and ek_expression. You can use it for ek_code and ek_hypertext arguments and it will behave as if you didn't wrap the arg source in it. Using force_ek_code on ek_data arguments will NOT cause an evaluation since ek_data is used when you want to read in some data but not permit general execution during the loading of the data structure.
You can "print" an object to a string using a wide variety of methods in Water.
These methods take a Water object as the subject and return a string
representation of that object. Some of these methods make representations
of an object that can be executed to re-create the object. This is useful for
"serializing" the object to send it over the net, or "persistence" to
save it in a file. Since the higher level formatters can represent not just
the object that is passed to the formatter but objects in its field values
recursively on down, large, complex, self_referential structures can be printed
using these methods.
Understanding the functionality of each formatter is crucial to selecting
the right tool for your job.
- to_string is the crudest of formatters, returning the result of calling
Java's toString method on the subject. For all but the very simplest
literals, the result of to_string cannot be executed to re-create the object.
- to_literal For literals, returns a string that can be read back in.
For non literals, returns false.
- to_path For literals, does with to_literal does. For defclasses,
defmethods and cached instances, returns a path to the object.
For other objects, returns false.
- to_concise_xml Returns a concise_xml representation of the object
which is a literal, a path or, in the case of an instance, a representation
of the whole object including values for all its fields.
- to_h2o The most complex printer, capable of printing out whole classes
including their subclasses and cached instances. to_h2o can take an argument
that causes only cached instances to be printed, not the classes themselves.
- to_html formats objects to be presented in web browsers. The hypertext objects
and objects that contain them print out as html tags. Other objects
print out as empty strings. Water has some clever ways to make forms
out of methods.
- to_xml formats objects not as Concise XML but as XML 1.0 syntax wherein all
attribute values are strings and full ending tags are printed, unlike
to_concise_xml.
Besides these formatters there are a number of other methods that are useful
in making string representations of objects.
- concat concatenates the to_html representations of all its arguments.
- echo prints out objects to the Java console using to_string.
If you'd like to use another formatter just use it like so:
<thing weight=234/>.<to_concise_xml/>.<echo/>
- string methods such as to_uppercase and to_lowercase help transform
strings to a desired format.
- integer.to_hex_string is useful to convert integers to hexidecimal format.
- file.<print_file/> will make a hardcopy of a file. If you want to print a
random string, first write it out to a file then print the file.
See also: to_string, to_literal, to path, to_concise_xml, to_h2o,
cache_instance, to_html, to_xml,
concat, echo, string.to_lowercase, string.to_uppercase,
integer.to_hex_string, filesystem.file.print_file<from obj=required make=false />
'from' attempts to turn an object into another kind of object.
It is a 'data-converter' and in some cases an alternative
way to construct an object from the usual
<some_class/> way of making an instance.
'from' uses a whole bunch of heuristics to do conversion.
If it can't make a reasonable conversion, it errors.
The syntax is: some_type.<from some_object/>
'from' generally accepts many differnt types for some_object.
If some_object is already an instance of some_type, then
some_object is just returned. Otherwise, an attempt is made
to use some_object as a description of an instance of some_type.
If successful, that instance is returned, otherwise error.
There are a lot of details to 'from'. If you're confused about
what it may do in a certain situation, just try it.
In general 'from' does a good job and converting between literals.
It also converts to vectors and even record objects.
boolean
False, the integers 0 and -1, the chars 0fFnN,
and the strings "false" "null" "no" "" "0" "-1" (of any case)
are all converted to false.
Everythng else is convertred to true.
boolean.<from 0/> returns false
boolean.<from "NO"/> returns false
integer
null and false are converted to 0.
true is converted to 1.
integers convert to theemselves.
floats are converted to the integer immediately above it or below it
depending on the 'direction' argument which may be:
"nearest" "towards_zero" "up" "down".
chars are converted to their ascii equivalent.
strings are read as a string of digits (with optional leading minus sign)
Everything else errors.
integer.<from false/> returns 0
integer.<from "123"/> returns 123
integer.<from <char "a"/>/> returns 97
integer.<from 12.3 direction="up"/> returns 124
integer.from can also take a 'radix' parameter to provide a base
for conversion of strings.
integer.<from "A" radix=16/> returns 10
float
integers convert to the float of the same numerical value.
floats convert to themselves
strings are read as a floating point number, usually with a decimal point in them.
float.<from 23/> returns 23.0
float.<from "23.4"/> returns 23.4
float.<from "17"/> returns 17.0
number
floats or integers convert to themselves
chars convert to their ascii equivalent integer
strings are converted to an integer if they have no decimal point in them,
and a float if they do.
number.<from <char "a"/>/> returns 97
number.<from "34"/> returns the integer 34
number.<from "3.4"/> returns the float 3.4
number.from takes a radix argument just like integer.from.
char
An integer is used as the ascii value to find the corresponding char.
A string has its first char returned. If the string is empty, error
char.<from 97/> returns <char "a"/>
char.<from "a"/> returnd <char "a"/>
string
to_concise_xml is called on the argument and the resulting string is returned.
string.<from 123/> returns "123"
If you have a vector of chars and you want to convert it to a string,
you can't use 'from'. Do this instead:
<vector <char "a"/> <char "b"/>/>.<char_vector_to_string /> returns "ab"
vector
A strings are converted into a vector of chars.
Supervectors, ie records that contain vector-keys, are converted into
a straight vector, losing the information in non-vector keys.
vectors are just returned.
For other types of objects an empty vector is returned since they have
a length of zero.
vector.<from "ab"/> returns <vector <char "a"/> <char "b"/>/>
vector.<from <thing 0="red" 1="blue"/>/> returns <vector "red" "blue"/>
literal
Strings are converted into a literal just as normal exection does.
literal.<from "123"/>