Skip to content
Ramsey Nasser edited this page Feb 3, 2011 · 9 revisions

Internally, all user code is run through the Ruby VM, making it difficult to label Zajal as a completely new language on its own. Instead, like Processing is to Java, Zajal is based on Ruby and largely compatible with it, but deviates in a few important areas.

The interpreter is written as an openFrameworks application in C++ to benefit from OF's event loop. The API is written mostly in C to interface with the Ruby VM and wrap OF's objects and functions. Experimental and complex parts of the API are implemented in Ruby with plans to re-implement them in C if performance becomes an issue.

Note: This page only describes features that are particular to Zajal and assumes a knowledge of Ruby. For a more complete overview without such assumptions, see Syntax.

Program Structure

Zajal programs are not runnable as Ruby code. Feeding a Zajal program to a stock Ruby interpreter will cause it to complain that setup and update are not defined. This is because, in an effort to keep user code as focused and streamlined as possible, calls like require "zajal" that you may expect are not needed. Details like that are taken care of by the Zajal interpreter.

Programs are structured much as they are Processing, albeit without the Java cruft.

t = 0

setup do
  size 200, 200
  smoothing true
end

update do
  t += 0.1
end

draw do
  circle width/2 + cos(t) * 10, height/2 + sin(t) * 10, 5
end

Top Level Globals

# this is a local variable with top level scope
k = 0

# top level local in event block:
# always works, because this is a closure
update do
  k += 1
end

# top level local in method:
# does not work in ruby, because method calls change scope
# made to work in zajal 
def somefunction n
  return n / k
end

# top level local with same name as method parameter:
# currently errors out.
# not sure if this should be disallowed, or if k should be shadowed here
def otherfunction k
  k += 10
  return k ** 2
end

Public Instance Variables

# normal class definition, but attr_accessor and
# friends can be left out
class Car
  def initialize
    @speed = 10
    @weight = 52.75
    @name = "VW Polo"
  end
end

polo = nil

setup do
  polo = Car.new
end

# instance variables can be set
update do
  polo.speed -= 0.1
end

# instance variables can read
draw do
  text polo.name
  text polo.speed
end

# to restore default Ruby behavior

# attr_* methods set class to default Ruby behavior
class Magazine
  attr_accessor :current_page
  
  def initialize
    @current_page = 0
    @name = "The New Yorker"
  end
end

m = Magazine.new

# works
m.current_page += 1 

# doesn't work, name= method not defined
m.name = "Wired"

# explicitly set class to default Ruby behavior
class Lamp
  attr_private

  def initialize
    @wattage = 60
  end
end

# will result in error, no wattage= method defined
l = Lamp.new
l.wattage += 10

Promiscuous Keyboard Events

# after pressing the 'a' key, all of the following evaluate to true
key_pressed do |key|
  key == "a"
  key == :a
  key =~ /a/
  key == 97 # this might be removed
end

# after pressing the left arrow key, all of the following evaluate to true
key_pressed do |key|
  key == :left
  key == 357
end

# after pressing the '4' key, all of the following evaluate to true
key_pressed do |key|
  key == "4"
  key == :'4'
  key == 52 # this might be removed in favor of key == 4
end

# case-when constructs work as expected
key_pressed do |key|
  case key
  when "a" then # ...
  when :left, :right then # ...
  when /[A-Z]/ then # ...
end
Clone this wiki locally