Setting up an Ant build script for your Scala project

May 3rd, 2010 and revised July 20th, 2010    , ,     2 Comments

Introduction

This is a small writeup which gives one way of setting up a build system for your Scala project. Here Apache Ant is used for managing this process, where the whole configuration is contained within a single build.xml file placed in the project’s root. Execution is done from command line or within your IDE environment.

Prerequisites

Install and configure Scala:

  • Define and set the SCALA_HOME variable in the OS environment
  • Update the PATH variable in the OS environment to include Scala’s bin directory

Install and configure Ant:

  • Define and set the ANT_HOME variable in the OS environment
  • Update the PATH variable in the OS environment to include Ant’s bin directory
  • Optional: If you encounter memory problems, define and set ANT_OPTS=-Xmx500M with JVM memory configuration in the OS environment

Install and configure Java:

  • Define and set the JAVA_HOME variable in the OS environment
  • Update the PATH variable in the OS environment to include Java’s bin directory

Find a suitable file structure for the project:

project-name/
  build/
  lib/
  src/
  test/
  build.xml

The Ant build script

Order of Ant targets:

  • build <- package <- doc <- compile <- init
  • clean <- init

Using project-name/build.xml:

<?xml version="1.0" encoding="UTF-8"?>
 
<project name="ProjectName" default="build" basedir=".">
  <description>Project Build Script</description>
 
  <!-- Targets -->
  <target name="build" depends="package" description="Build complete project"/>
 
  <target name="clean" depends="init" description="Remove previously built files">
    <delete dir="${build.dir}" includeemptydirs="true" quiet="true"/>
  </target>
 
  <target name="init">
    <property environment="env"/>
 
    <!-- check for required tools -->
    <fail message="Missing SCALA_HOME variable in OS environment">
      <condition><isset property="${env.SCALA_HOME}"/></condition>
    </fail>
    <fail message="Missing JAVA_HOME variable in OS environment">
      <condition><isset property="${env.JAVA_HOME}"/></condition>
    </fail>
 
    <!-- Paths -->
    <property name="src.dir" location="${basedir}/src"/>
    <property name="lib.dir" location="${basedir}/lib"/>
    <property name="build.dir" location="${basedir}/build"/>
    <property name="build-classes.dir" location="${build.dir}/classes"/>
    <property name="build-lib.dir" location="${build.dir}/lib"/>
    <property name="build-doc.dir" location="${build.dir}/doc"/>
    <property name="java.dir" location="${env.JAVA_HOME}"/>
    <property name="scala.dir" location="${env.SCALA_HOME}"/>
    <property name="scala-library.jar" location="${scala.dir}/lib/scala-library.jar"/>
    <property name="scala-compiler.jar" location="${scala.dir}/lib/scala-compiler.jar"/>
 
    <path id="project.classpath">
      <pathelement location="${scala-library.jar}"/>
      <pathelement location="${build-classes.dir}"/> <!-- used during recompilation -->
    </path>
 
    <path id="scala.classpath">
      <pathelement location="${scala-compiler.jar}"/>
      <pathelement location="${scala-library.jar}"/>
    </path>	
 
    <taskdef resource="scala/tools/ant/antlib.xml" classpathref="scala.classpath"/>
 
    <echo message="Init project"/>
    <echo message=" with Scala path = ${scala.dir}"/>
    <echo message=" with Java path = ${java.dir}"/>
 
    <uptodate property="build.uptodate" targetfile="${build.dir}/build.done">
      <srcfiles dir= "${src.dir}" includes="**"/>
      <srcfiles dir= "${lib.dir}" includes="**"/>
    </uptodate>
  </target>
 
  <target name="compile" depends="init" unless="build.uptodate">
    <mkdir dir="${build-classes.dir}"/>
    <scalac
      destdir="${build-classes.dir}"
      classpathref="project.classpath">
      <include name="**/*.scala"/>
      <src><pathelement location="${src.dir}"/></src>
    </scalac>
  </target>
 
  <target name="doc" depends="compile" unless="build.uptodate">
    <mkdir dir="${build-doc.dir}"/>
    <scaladoc
      srcdir="${src.dir}"
      destdir="${build-doc.dir}"
      doctitle="Project API documentation"
      classpathref="project.classpath">
      <include name="**/*.scala"/>
    </scaladoc>
  </target>
 
  <target name="package" depends="doc" unless="build.uptodate">
    <mkdir dir="${build-lib.dir}"/>
    <jar destfile="${build-lib.dir}/project.jar">
      <fileset dir="${build-classes.dir}"/>
    </jar>
    <touch file="${build.dir}/build.done"/> <!-- mark build as up-to-date -->
  </target>
</project>

Reference for Scalac Ant task

Arguments: srcdir, srcref, destdir, classpath, classpathref, sourcepath, sourcepathref, bootclasspath, bootclasspathref, extdirs, extdirsref, encoding, target={jvm-1.5, msil}, force={yes,no}, fork={yes,no}, logging={none,verbose,debug}, debuginfo={none,source,line,vars,notailcalls}, addparams, scalacdebugging, deprecation={yes,no}, optimise={yes,no}, unchecked={yes,no}, failonerror={yes,no}

Nested arguments: src,classpath,sourcepath,bootclasspath,extdirs

Alternative build systems

Simple Build Tool (SBT) - a Scala-centric build system
Maven - a build system aimed at larger projects with many external dependencies

Testing frameworks

Scalatest.org: ScalaTest - dsl-driven framework that supports various testing methodologies
ScalaCheck - functional programming oriented with automatic test-case generation

References

tuples – experimenting with lisp-like syntax as XML replacement

June 14th, 2009 and revised August 29th, 2010    ,     2 Comments

Motivation

The following post is just an experimentation on using a lisp-like syntax, with hints of JSON, for storing structured data as text. The main motivation for this was a need to have a less verbose alternative to XML, but still be readable and editable (weak point of JSON). It should also support pattern matching and common primitive datatypes.

The current specification has errors and is incomplete. The programming elements are currently in the toy stage.

Specification

(@text
  (#
 
  Quick overview
    An experimental typed data-format using s-expression-like syntax for storing
    structured data.
 
    A tuple can be a named, unnamed, or typed parenthesis that enclose an
    ordered sequence of whitespace separated expressions.
 
    A typed tuple may be a @int, @float, @number, @bool, @bytes, @rule, @text,
    @note or @tuple. An named or unnamed tuple is an untyped @tuple tuple. A
    @note is used for documenting or ignoring tuples and may be skipped during
    processing.
 
    A pair may be a
      : that separates a named key and value expression
      == that separates two expressions in an assertion
      -> that separates two expressions in an substitution
      => that separates two expressions in an combination
 
    A named, unnamed and @tuple typed tuple may contain key-value pairs,
    untyped text, named, unnamed, @tuple, or @text tuples.
 
    A document must start with a typed tuple. If a document discards @note typed
    tuples and starts with one, an assertion failure must be raised.
 
  Syntax
    () - encloses a named, unnamed or typed tuple
 
    (# - begins a text block (nested text blocks are allowed but
         unbalanced text blocks must use double-quotation instead)
    #) - ends a text block
    "" - encloses a text string with escaped characters
    @text - gives one or more text blocks or strings
 
    :  - a key-value pair
    => - rule that matches the left side and then combines it with the right side
    -> - rule that matches the left side and then substitute it with the right side
    == - rule that matches left side and then asserts that the right side is present
    '' - encloses a pattern matching variable that specify type or named reference
 
    @tuple - give a sequence of untyped text, @text, named, unnamed, @rule, or @note tuples
    ("unnamed") - equivalent to @tuple
    (Named) - equivalent to @tuple
    @note - equivalent to @tuple
    @rule - gives a sequence of rules
    @bytes - gives a sequence of base64 encoded text containing unsigned bytes
    @int - gives a sequence of signed integers in 32- or by default 64-bit
    @float - gives a sequence of floating point numbers in 32- or by default 64-bit
    @number - gives a sequence of unbounded numbers
    @bool - gives a sequence of true or false
 
  Pattern matching
    - Application of pattern matching is handled at the application level
    - Pattern matching variables can be used to
      (Data value: 'PI') - assign variable to the value of a pair
      (@rule 'PI' -> (@float 3.14)) - substitute a variable with an expression
      (@rule (Data) == (size: '@int')) - assert that a tuple has a certain structure
 
  Examples
   - Named tuples
       (Document title: "just another format" Document)
       (Dir name: "root" files: (
           (File name: "readme" data: (@bytes (#MTIz#)))
         )
       )
   - Unnamed tuples
       (title: "just another format")
       (name: "root" files: (
           (name: "readme" data: (@bytes (#MTIz#)))
         )
       )
   - Typed tuples in key-value pairs
       (Cell name: "a" value: (@int:32 42))
       (Screen fullscreen: (@bool false))
   - Untyped tuples in key-value pairs
       (Cell name: "b" value: 42)
       (Screen fullscreen: false)
 
  Parsing syntax
    start            ::= tuple-typed | rule-typed | int-typed | note-typed
                       | float-typed | bytes-typed | bool-typed
 
    tuple            ::= tuple-unnamed | tuple-named | tuple-typed
    tuple-unnamed    ::= unnamed<tuple-seq>
    tuple-named      ::= named<name,tuple-seq>
    tuple-typed      ::= typed<tuple-type,tuple-seq>
    tuple-type       ::= '@tuple'
    tuple-seq        ::= {rule | note | text | pair | tuple, pad}
 
    unnamed<body>    ::= '(' body ')'
    named<tag,body>  ::= '(' tag (pad body)? (pad tag)? ')'
    typed<tag,body>  ::= '(' tag (pad body)? (pad tag)? ')'
    name             ::= [a-zA-Z][-A-Za-z0-9]*
    pair             ::= name ':' pad (primitive | tuple)
    primitive        ::= bytes | int | float | bool | text
                       | variable | number-untyped
 
    rule             ::= rule-typed
    rule-typed       ::= typed<rule-type,rule-options? rule-seq>
    rule-type        ::= '@rule'
    rule-options     ::= {pair, pad}
    rule-seq         ::= {rule-combine | rule-substitute | rule-assert, pad}
    rule-combine     ::= tuple pad '=>' pad tuple
    rule-substitute  ::= (tuple pad '->' pad tuple)
                       | variable pad '->' pad (tuple | primitive)
    rule-assert      ::= tuple pad '==' pad tuple
 
    variable         ::= ''' variable-type '''
    variable-type    ::= name | int-type | float-type | bool-type
                       | bytes-type | text-type | tuple-type
 
    note-typed       ::= typed<note-type,tuple-seq>
    note-type        ::= '@note'
 
    bytes            ::= bytes-typed
    bytes-typed      ::= typed<bytes-type,bytes-untyped>
    bytes-type       ::= '@bytes'
    bytes-untyped    ::= '(#' << base64 alphabet with whitespace trimmed away >> '#)'
 
    number-untyped   ::= int-untyped | float-untyped
 
    int              ::= int-untyped | int-typed
    int-typed        ::= typed<int-type,int-seq>
    int-untyped      ::= << characters giving an integer of any size >>
    int-type         ::= '@int' (':32' | ':64')?
    int-seq          ::= {int-untyped, pad}
 
    float            ::= float-untyped | float-typed
    float-typed      ::= typed<float-type,float-seq>
    float-untyped    ::= << characters giving a floating point of any size >>
    float-type       ::= '@float' (':32' | ':64')?
    float-seq        ::= {float-untyped, pad}
 
    bool             ::= bool-untyped | bool-typed
    bool-typed       ::= typed<bool-type,bool-seq>
    bool-untyped     ::= 'true' | 'false'
    bool-type        ::= '@bool'
    bool-seq         ::= {bool-untyped, pad}
 
    text             ::= text-untyped | text-typed
    text-typed       ::= text-string | named<text-type,text-seq>
    text-untyped     ::= text-string | text-block
    text-type        ::= '@text'
    text-seq         ::= {text-string | text-block, pad}
    text-string      ::= '"' << any characters until unescaped double-quote >> '"'
    text-block       ::= '(#' << any characters until text-block is balanced >> '#)'
 
    pad              ::= [/s]+
 
  How to handle text
    - Text-strings are escaped by replacing '\' with '\\' then '"' with '\"', and
      unescaped by replacing '\"' with '"' then '\\' with '\'.
    - Text-blocks are not escaped, but verified that they are balanced. If not they
      become text-strings. A text-block is balanced if all embedded '(#' is matched
      with a corresponding '#)'. A text-block cannot end with the '(' character.
 
  Examples of invalid expressions
    (Data name: "A" name: "B") - duplicate key-value pair
    Data - neither a primitive or named tuple
    name: "A" - pair not enclosed in parenthesis
    @tuple - not enclosed with parenthesis
    '@byte' - variable does not contain a valid type
 
  Examples of valid expressions
    (name: "Kyrre") - unnamed tuple
    "Some characters!" - implicit (@text "Some characters!")
    (state: true) - implicit (state: (@bool true))
    (width: 1024) - implicit (width: (@number 1024))
    (@int 4) - implicit (@int:64 4)
    (@float 3.14) - implicit (@float:64 3.14)
  #)
@text)

Example

Data with redundant information stored in rules:

(@tuple
 
  (@note "Rules for naming all unnamed tuples and discarding notes")
  (@rule forall: true
    (name: '@text' type: '@text') => (Node)
    (from: '@tuple' to: '@tuple') => (Link)
    (inputs: (
        (@rule (name: '@text' datatype: '@text') => (Socket))
      )
    ) => ()
    (outputs: (
        (@rule (name: '@text' datatype: '@text') => (Socket))
      )
    ) => ()
    (name: "Out" datatype: '@text') => ()
    '@note' -> ()
  )
 
  (@note "Rules for substituting in data")
  (@rule forall: true
    'test-data' -> (@bytes (#QUI9PQ==#))
    'instructions' -> "some data in text format"
  )
 
  (@note "The data to be transformed")
  (name: "Group1" type: "Group"
    nodes: (
      (name: "Source" type: "Value" value: 'test-data'
        inputs: ((name: "In" datatype: "bytedata"))
        outputs: ((name: "Out" datatype: "bytedata"))
      )
      (name: "Transform" type: "Process" data: 'instructions'
        inputs: ((name: "In" datatype: "bytedata"))
        outputs: ((name: "Out" datatype: "bytedata"))
      )
      (name: "Target" type: "Value" value: ""
        inputs: ((name: "In" datatype: "bytedata"))
        outputs: ((name: "Out" datatype: "bytedata"))
      )
    )
    links: (
      (from: (node: "Source" socket: "Out") to: (node: "Transform" socket: "In"))
      (from: (node: "Transform" socket: "Out") to: (node: "Target" socket: "In"))
    )
  )
 
@tuple)

The resulting data after the rules of the tuple has been applied to itself:

(@tuple
  (Node name: "Group1" type: "Group"
    nodes: (
      (Node name: "Source" type: "Value" value: (@bytes (#QUI9PQ==#))
        inputs: ((Socket name: "In" datatype: "bytedata"))
        outputs: ((Socket name: "Out" datatype: "bytedata"))
      )
      (Node name: "Transform" type: "Process" data: "some data in text format"
        inputs: ((Socket name: "In" datatype: "bytedata"))
        outputs: ((Socket name: "Out" datatype: "bytedata"))
      )
      (Node name: "Target" type: "Value" value: "output"
        inputs: ((Socket name: "In" datatype: "bytedata"))
        outputs: ((Socket name: "Out" datatype: "bytedata"))
      )
    )
 
    links: (
      (Link from: (node: "Source" socket: "Out")
        to: (node: "Transform" socket: "In")
      )
      (Link from: (node: "Transform" socket: "Out")
        to: (node: "Target" socket: "In")
      )
    )
  )
@tuple)

Ideas for extensions

  • Chaining together separate files
  • Nesting separate files with pattern matching variables – like referencing large bytedata and instantiating tuples
  • Use separate files for validation, update and typing of data

Trait-like CSS on HTML

June 14th, 2009 and revised May 30th, 2010    ,     No Comments

Defining some CSS types

One way of structuring the CSS is to define some types over the CSS classes. What these types might be may be is open, but one instance might be Behaviour, Layout and Roles. The types are not used explicitly in the CSS, but are there to help organize and abstract the CSS classes.

On these types the following CSS classes can be defined:

  • Roles – sidebar, menu, toolbar, group, item, title, input, post, search, button
  • Behaviour – inactive, hidden, selectable, grabable, highlighted
  • Layout – flow{L,R}, break{,L,R}, padded{,L,R,T,B,V,H}, spaced{,L,R,T,B,V,H}

    where {} mean “choose from” and letters are abbreviations for Left, Right, Top, Bottom, Vertically, Horizontally

For Roles it is important to add classes that can be combined or nested. For instance, toolbar and menu might both contain item and group. Furthermore, a sidebar might contain a toolbar or menu. Experimenting and identifying such classes as Roles (or any types) can help simplify or find reoccuring structures in the CSS.

Tagging the HTML elements with CSS classes

Depending on the design of the HTML page, HTML elements may be tagged as you see fit with CSS classes. The variations of Roles is a result of how the HTML elements are nested. These elements can further be tagged with Behaviour and Layout classes.

Example:

<div class="menu">
  <div class="title">title</div>
  <div class="spacedH flowL selectable item">item 1</div>
  <div class="spacedH flowL selectable item">item 2</div>
  <div class="spacedH flowL selectable item">item 3</div>
<div>

Setting the appearance of composed CSS classes

The visual appearance of the HTML elements is specified by a set of selectors, each having a pattern to match and the corresponing CSS attributes to set.

Guidelines for writing the selectors:

  • More specific compositions of CSS classes override less specific
  • Selector A B specifies node B when nested inside A
  • Selector AB specifies node with A and B
  • Selector A>B specifies node B when child of A
  • Selector A+B specifies node B if after A
  • Selector A B, C+D specifies two selectors using the same attributes

Example:

.break { clear: both; }
.breakL { clear: left; }
.breakR { clear: right; }
 
.spaced { margin: 4px; }
.spacedL { margin-left: 4px; }
.spacedV { margin-top: 4px; margin-bottom: 4px; }
.spacedH { margin-left: 4px; margin-right: 4px; }
 
.menu {
  background-color: #404040;
}
 
.menu .title {
  color: #a0a0a0;
  font-weight: bold;
}
 
.menu .item {
  color: #a0a0a0;
}
 
/* Here .item.selectable is node with both */
.menu .item.selectable#hover {
  color: #f0f0f0;
}

References

Reminders on Scala syntax

January 27th, 2009 and revised August 5th, 2010    ,     No Comments

Reminders

The companion object (both for own code and Scala’s API)

// The class definition with primary constructor
class A protected (val arg1: String, private arg2: String) {
  // imports definitions from companion object
  import A._ 
 
  // attributes and primary constructor code
  var busy = false
 
  // methods
  override def toString() = "A"
}
 
// Companion object comes after class/trait definition
object A {
  // utility constructors
  apply(arg: String): A = new A("a", arg)
 
  // apply and unapply methods for object pattern matching (like case classes)
 
  // static methods
}
 
val a = A("test")

Setter and getter functions are defined implicitly for val, var and referenced arguments in primary constructor. To set these manually

class A {
  private[this] var v: Int = 0 // private variable to hold value
  def value(): Int = v
  def value_= (t: Int) { v = t } // setters returns Unit
}

Adding indexing operators

// Here T give the type parameter for the class
class A[T] (size: Int) {
  private val array = new Array[T](size)
  def apply(index: Int): T = { /** get index value */ }
  def update(index: Int, value: T): Unit = { /** set index value*/ }
}
 
val a = new A[Int](100)
a(0) = 1
val n = a(0)

Binding a variable during pattern matching

str match {
  case bound @ "A match!" => println(bound)
  case _ => // no match
}

Defining an extractor for pattern matching (example lacks validation)

object Email {
  def apply(user: String, domain: String): String =
    user + "@" + domain
 
  def unapply(str: String): Option[(String,String)] = {
    str.split("@").toList match {
      case user :: domain :: Nil => Some(user,domain)
      case _ => None
    }
  }
}
 
Email("me@host.com") match {
  case Some(name,host) => println("Username is " + name)
  case None => println("Invalid email address")
}

Imports can be grouped

import scala.collection.mutable.{Map,Stack,Queue}

Types can be aliased

type QMap = Map[Int,Queue[Int]]

Upper A <: T (A is a subtype of T) and lower A >: T (A is a supertype of T) bounded type parameters

class List[+A](elem: A, next: Option[List[A]]) {
  def prepend[B >: A](newElem: B): List[B] = new List(newElem, Some(this))
}
// scala> val l1 = new List(1.0, None)
// l1: List[Double] = List@1f49969
// scala> val l2 = new List(10,Some(l1))
// l2: List[AnyVal] = List@19bf996
 
def sort[T <: Ordered[T]](list: List[T]) { /** ... */ }

Writing () is optional with no arguments, and . is optional for methods with one argument

val b = new B
List(1,2,3) map (_ * 2)

Return keyword is optional (and curly braces on a single expression too)

def test() = "test"

The return type Unit is implicit when functions are declared without =

def printBig(str: String): Unit = {
  println(str.toUpperCase)
  () /** explicitly end the expression with the unit value */
}
def printBig(str: String) { println(str.toUpperCase) } /** same as previous */

References

Simple serialization with XML strings in Javascript

January 12th, 2009 and revised October 25th, 2009    , ,     No Comments

Introduction

Included in this post are some quick and simple functions for doing serialization in Javascript through strings. Reserved XML characters < > & ' " are escaped from input and if any invalid input are found an exception will be raise.

List of XML utility functions:

  • toXmlHeader() – Creates the XML header.
  • toXmlElem(name: string, attributes: object) – Creates and closes an XML element.
  • toXmlElemOpen(name: string, attributes: object) – Creates and opens an XML element.
  • toXmlElemClose(name: string) – Closes an XML element.
  • toXmlText(text: string) – Creates XML text.

A serialization example

var xml = toXmlHeader();
xml += toXmlElemOpen("Library"); // No attributes given.
 
xml += toXmlElemOpen("Authors", {country: "Norway"});
xml += toXmlElem("Author", {name:"Petter Dass"});
xml += toXmlElemClose("Authors");
 
xml += toXmlElemOpen("Books"); // No attributes given.
xml += toXmlElem("Book", {title:"book1", author:"author1"});
xml += toXmlElemOpen("Book", {title:"book2", author:"author1"});
xml += toXmlText("Ach, So?");
xml += toXmlElemClose("Book");
xml += toXmlElem("Book", {title:"book3", author:"author2"});
xml += toXmlElem("Book"); // No attributes given.
xml += toXmlElemClose("Books");
 
xml += toXmlElemClose("Library");
alert(xml); // the complete xml is now contained inside the string.
<?xml version="1.0" encoding="UTF-8"?>
<Library>
<Authors country="Norway">
<Author name="Petter Dass"/></Authors>
<Books>
<Book title="book1" author="author1"/>
<Book title="book2" author="author1">Ach, So?</Book>
<Book title="book3" author="author2"/>
<Book/></Books></Library>

Sourcecode for the XML utility functions

function toXmlValid(str) {
  if (str === undefined || str === null || str.match === undefined || str.match(/<|>|&|'|"/) !== null) {
    throw("invalid string given");
  }
 
  return str;
}
 
function escapeXmlText(str) {
  if (str === undefined || str === null || str.replace === undefined) {
    throw("invalid string given");
  }
 
  // The order of replace is important because the & character is used in escaping.
  return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/'/g, "&apos;");
}
 
function unescapeXmlText(str) {
  if (str === undefined || str === null || str.replace === undefined) {
    throw("invalid string given");
  }
 
  // The order of replace is important because the & character is used in unescaping.
  return str.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&apos;/g, "'").replace(/&quot;/g, "\"").replace(/&amp;/g, "&");
}
 
function toXmlHeader() {
  return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
}
 
function toXmlAttr(name, value) {
  return " " + toXmlValid(name) + "=\"" + escapeXmlText(value) + "\"";
}
 
function toXmlElem(tagName, attributes) {
  var str = "\n<" + toXmlValid(tagName);
 
  if (attributes !== undefined) {	
    for (var key in attributes) {
      if (attributes.hasOwnProperty(key) === true) {
        str += toXmlAttr(key, attributes[key]);
      }
    }
  }
 
  return str + "/>";
}
 
function toXmlElemOpen(tagName, attributes) {
  var str = "\n<" + toXmlValid(tagName);
 
  if (attributes !== undefined) {
    for (var key in attributes) {
      if (attributes.hasOwnProperty(key) === true) {
        str += toXmlAttr(key, attributes[key]);
      }
    }
  }
 
  return str + ">";
}
 
function toXmlElemClose(tagName) {
  return "</" + toXmlValid(tagName) + ">";
}
 
function toXmlText(text) {
  return escapeXmlText(text);
}

References

Comparison against null and undefined in Javascript

August 5th, 2008 and revised July 2nd, 2010    ,     No Comments

Values in Javascript can come from

  • Object – object reference
  • String – immutable, 16-bit USC-2
  • Boolean – true, false
  • Number – only 64-bit floating point, IEEE 754 (double)
  • null – empty object reference
  • undefined – unassigned variables and function arguments, missing object properties

Boolean evaluation of values using == and != operators

Values that are interpreted as false:

  • false
  • null
  • undefined
  • "" – the empty string
  • 0 – the number 0
  • NaN – not a number, result of undefined math operation

All other values and objects are interpreted as true.

Working with comparison operators

The == and != operators will do implicit type conversion of it’s arguments to match their type. Since the null and undefined values are both equal with these operators, errors can occur when a missing object property is used in a null-comparison.

By using the === and !== operators, no implicit type conversion will be done. The values null and undefined are not equal using these operators. These operators can be used to check against missing properties and unassigned arguments among other.

Notice: Be careful if updating your old javascript code with === and !== for null-comparison tests. It might be that an undefined-comparison should have been used instead (or both). Failure to recognise these cases can introduce hard-to-catch errors.

References

Deep Pocket Layout – tree-based UI layout

February 22nd, 2008 and revised July 9th, 2010    ,     No Comments

Overall idea

The Deep Pocket Layout, an illustrative name of a common data-structure, uses a specialized tree data-structure for none-overlapping layout of user interface elements (or widgets). This data-structure can be used for partitioning the screen-space, similar to a quadtree or kd-tree, and uses the naming conventions of border layout. In usage, it functions as a tree of either vertically or horizontally linked partitions, like a combined border/horizontal/vertical layout.

In the following example, the data-structure will be explained as a container widget, as part of an inheritance hierarchy of other widgets.

Introduction by example

The figure above shows the named “pockets” of the data structure. The outmost pockets are used for linking the Pocket Layout Widget (PW) together with other PWs. The center pocket can contain a PW (thus forming a tree) or a different kind of Widget (leaf node). The center pocket specifies the screen-space, while the border pockets acts as internal links to other PWs. When the left or right pockets are linked, they become part of a horizontal layout (top and bottom pockets must always be empty). Conversely, when the top or bottom pockets are linked, they become part of a vertical layout (left and right pockets must always be empty).

The first example below shows how a widget (of any kind) can be inserted by using the center pocket of the PW.

PWs can be arranged into either vertical and horizontal layouts. The figure below shows how a horizontal layout is started. Since P1 it the root of the tree, a new PW P3 is created, replacing the center pocket content of P1. Then P2 is linked with P3, starting a horizontal layout.

The figure below shows how a vertical layout is started. This example is identical to the previous one, but starting a vertical layout instead. (The root constraint for P1 still applies.)

The final example shows how to split a PW in a horizontal layout into a vertical. Here P3 is already part of a horizontal layout. A new PW is created and replaced with P3s center pocket. The vertical layout is then started by linking P6 with P7.

The final deep pocket layout of this example is visualized in the following figure.

Summary

Some features:

  • Enables combination of tree-based vertical/horizontal layouts.
  • Allows the user to insert/remove any PWs in the hierarchy from any depth, thus controlling the complete layout with drag-and-drop.
  • User control over screen space that is delegated within the tree hierarchy.
  • PW linked in either a horizontal or vertical layout can adjust neighboring PWs or delegate request to parent PW.

Implementation extensions:

  • The example used “share equally”, but custom ratios of the linked PWs can be handled by the parent PW.
  • Overlay of drag-and-drop targets when dragging is in progress.

References

Code documentation for Javascript and Actionscript 3

January 1st, 2008 and revised June 14th, 2009    , ,     No Comments

Prerequisites for Actionscript documentation

Prerequisites for Javascript documentation

Actionscript 3 Code Documentation

Example documentation:

/**
* class-description
*/
class-declaration
/**
* method-description
*
* @see method-name
* @param name description
* @return description
*/
method-declaration.
/** attribute-description */
attribute-declaration

Extracting the documentation from the sourcecode:

asdoc.exe -source-path /source/directory -doc-sources /source/directory -output /output/directory -window-title "Project Title"

Javascript Code Documentation

Example documentation:

/**
 * class-description
 *
 * @author author
 * @extends class-name
 * @see class-name
 * @version version
 * @constructor
 */
class-constructor-declaration.
/**
 * method-description
 *
 * @see class-name#method-name
 * @param {data-type} name description
 * @return description
 * @type data-type-of-return
 */
method-declaration.

Extracting the documentation from the sourcecode:

perl jsdoc.pl /source/directory --directory /output/directory --project-name "Project Title"

References for this post

Multiple Inheritance in Javascript

December 26th, 2007 and revised May 16th, 2010    , ,     No Comments

Notice

Javascript does not support multiple inheritance, so the given method will break the instanceof operator! Javascript checks inheritance by traversing the linked list prototype.__proto__ for occurences of the requested prototype. This means that one prototype can only contain one reference to another prototype and in effect only inherit from one prototype. By discarding support for the instanceof operator, multiple inheritance can be simulated.

A support function is available that provide similar functionality as the instanceof operator.

Description and implementation details

The function responsible for applying inheritance between classes works by copying all missing attributes/methods from parent class(es) to the inheritance class. In addition, metadata in the class constructors allows for isInstanceOf() comparisons to to made on objects.

/**
 * Check if object is instance of given class.
 *
 * @param {Object} object Object to check inheritance of.
 * @param {Function} classConstructor Constructor function to check inheritance against.
 * @return Boolean indicating success of comparison.
 * @type {Boolean}
 */
function isInstanceOf(object, classConstructor) {
  // Check for class metadata
  if (object.constructor.meta === undefined || classConstructor.meta === undefined) {
    return object instanceof classConstructor; // Use standard inheritance test
  }
 
  // Use inheritance metadata to perform instanceof comparison
  return object.constructor.meta.fromClasses[classConstructor.meta.index] !== undefined;
}
 
/**
 * Applies inheritance to a class (first argument) from classes (second, third, and
 * so on, arguments).
 *
 * Notes:
 *  - This WILL BREAK the instanceof operator! Use the isInstanceOf() function instead.
 *  - Parent classes must be fully declared before calling this function.
 *  - Multiple classes will be copied in sequence.
 *  - Properties that already exists in class will not be copied.
 */
function applyInheritance() {
  // Validate arguments
  if (arguments.length < 2) {
    throw new Error("No inheritance classes given");
  }
 
  var toClass = arguments[0];
  var fromClasses = Array.prototype.slice.call(arguments, 1, arguments.length);
 
  // Check if class referencer has been created
  if (applyInheritance.allClasses === undefined) {
    applyInheritance.allClasses = [];
  }
 
  // Check for inheritance metadata in toClass
  if (toClass.meta === undefined) {
    toClass.meta = {
      index: applyInheritance.allClasses.length,
      fromClasses : [],
      toClasses: []
    };
    toClass.meta.fromClasses[toClass.meta.index] = true; // class links to itself
    applyInheritance.allClasses.push(toClass);
  }
 
  // Apply inheritance fromClasses
  var fromClass = null;
  for (var i = 0; i < fromClasses.length; i++) {
    fromClass = fromClasses[i];
 
    // Check for inheritance metadata in fromClass
    if (fromClass.meta === undefined) {
      fromClass.meta = {
        index: applyInheritance.allClasses.length,
        fromClasses: [],
        toClasses: []
      };
      fromClasses[i].meta.fromClasses[fromClass.meta.index] = true; // class links to itself
      applyInheritance.allClasses.push(fromClass);
    }
 
    // Link toClass and fromClass
    toClass.meta.fromClasses[fromClass.meta.index] = true;
    fromClass.meta.toClasses[toClass.meta.index] = true;
 
    // Copy prototype fromClass toClass
    for (var property in fromClass.prototype) {
      if (toClass.prototype.hasOwnProperty(property) === false) {
        // Copy missing property from the parent class to the inheritance class
        toClass.prototype[property] = fromClass.prototype[property];
      }
    }
  }
}

Multiple inheritance example:

function Animal(name) {
   // Attributes
   this.name = name;
}
 
Animal.prototype.makeSound = function (soundOutput) {
   soundOutput.playSound("Unknown");
};
 
Animal.prototype.getHierarchy = function () {
   return "Animal";
};
 
function Petable(personality) {
   // Attributes
   this.personality = personality;
}
 
Petable.prototype.isCompatible = function (personality) {
   return this.personality == personality;
};
 
function Dog(name, personality, breed) {
   // Call parent constructors
   Animal.call(this, name);
   Petable.call(this, personality);
 
   // Attributes
   this.breed = breed;
}
// Apply inheritance to Dog from Animal and Petable
applyInheritance(Dog, Animal, Petable);

An example of how to override a method of a parent class:

Dog.prototype.makeSound = function (soundOutput) {
   soundOutput.playSound("Bark");
};

An example of how an overidden method can delegate to it’s parent method:

Dog.prototype.getHierarchy = function () {
   // returns "Animal.Dog"
   return Animal.prototype.getHierarchy.apply(this, arguments) + ".Dog";
};

An example of how to call a parent method:

Dog.prototype.isOwner = function (name, personality) {
   if (this.name != name) {
      return false;
   }
 
   return Petable.prototype.isCompatible.call(this, personality);
};

Notes on calling function objects

References

Associative Arrays in Javascript

December 26th, 2007 and revised July 25th, 2010    ,     No Comments

Introduction

The associative array (also known as hash map) is similar to the ordinary array. Instead of indexing by integers, the associative array uses string keys. It also lacks the bookkeeping abilities of the ordinary array like sort(), splice() etc. In Javascript every object has the ability to act as an associative array.

Creating an associative array and filling it with some data:

var container = {};
container["someKey"] = 3;
container["someOtherKey"] = someObject;
container["anotherKey"] = "Some text";
 
// ... or equivalently
var container = {
  someKey: 3,
  someOtherKey: someObject,
  anotherKey: "Some text"
};

Accessing elements in the associative array:

var someValue = container["someKey"];
container["otherKey"] = someValue;
 
// ... or equivalently
var someValue = container.someKey;
container.otherKey = someValue;

Iterating through all the elements in the associative array:

for (var key in container) {
   // hasOwnProperty() checks that attribute is from non-inherited prototype
   if (container.hasOwnProperty(key)) {
      var element = container[key];
   }
}

Deleting a key in the associative array:

delete container["someKey"];
 
// ... or equivalently
delete container.someKey;
 
// Notice: Don't assign null to the deleted key as
// this will re-create the key!

Checking if a key exists in the associative array:

if (container["someKey"] === undefined) {
   // Key does not exist
}
 
// ... or equivalently
if (container.someKey === undefined) {
   // Key does not exist
}

References