Get Waves

  
  # a recent gem build from Waves edge on GitHub
  gem install dyoder-waves --source=http://gems.github.com

  # get the framework source
  git clone git://github.com/dyoder/waves.git
  cd waves
  # install gem dependencies needed to work from source
  rake setup 
  rake package && sudo rake install_gem

  # completely obsolete release from Rubyforge
  # included here only to warn you away from it.
  # gem install waves

Fire it up

  # working from gems
  waves ~/Sites/blog

  # working from framework source
  ./bin/waves ~/Sites/blog

This creates the default application structure in the target directory. The application module’s name is the constant-cased version of the target directory basename, in this case Blog.

  cd ~/Sites/blog

  # irb-based console
  waves-console

  # run the web server
  waves-server

What’s all this, then?

Each Waves application consists of a Ruby module structured with internal namespaces. Thus:

Blog::Configurations
Blog::Resources
Blog::Controllers
Blog::Models
Blog::Views
Blog::Helpers

As you might have guessed, the actual working classes live in these namespaces. E.g. Blog::Models::User.

The otherwise harsh birth and life of these working classes is softened by AutoCode, a sort of mini-Industrial Revolution for Ruby constants. The Waves framework uses AutoCode to automatically instantiate controllers, models, views, etc. the first time each constant is needed by the application. Waves looks for a file in a path that corresponds to the namespaced constant name. If such exists, Waves will auto_load the constant from the file. If not, Waves knows how to auto_create the class or module from sensible defaults.

For example, when Waves encounters Blog::Controllers::MonkeyShines for the first time, it tries to load it from controllers/monkey_shines.rb. If that file does not exist, the app clones Blog::Controllers::MonkeyShines from Waves::Controllers::Base.

The result is that you only need to define models, controllers, etc. when the default behavior stops meeting your needs.

Where it’s at

./
  configurations/   # (auto_load || auto_create)
  controllers/      # (auto_load || auto_create)
  helpers/          # (auto_load || auto_create)
  lib/              
    application.rb  # Application requires and includes, plus your configuration needs.
    tasks/          # .rb and .rake files in here are automatically required by the main Rakefile
  log/              # I'm a lumberjack, and I'm okay.  (Really, what did you think?)
  models/           # (auto_load || auto_create)
  public/           # Images, css, misc. assets
  Rakefile          # 
  resources/        # (auto_load || auto_create)
  schema/            
    migrations/      
  startup.rb         # Finds and requires the framework.  Mostly don't touch.
  templates/         # Views expect templates to live here.
  views/             # (auto_load || auto_create)

Application configuration

Waves uses inheritable configurations. The default application starts with two usable configurations: Development and Production. These are subclasses of Configurations::Default, and they inherit the attributes defined in Default. Waves runtimes (e.g. waves-console and waves-server) use the configuration specified by ENV['mode'].

Look, for example, at the Development configuration in configurations/development.rb. Here is where you configure the host and port for the web server, the database, and the Rack handler. If you want Waves to run on port 24601 for both your development and production configurations, you can remove the declaration here and in Production, and add it to Default.

The value of the database attribute will be used by the active ORM layer to establish a database connection. The default ORM layer is Sequel, but there is also an ActiveRecord layer available, and others under development. What you set for database depends on the particular ORM’s needs. The Sequel layer uses the value as the args to Sequel.connect, for instance . Sequel’s current documentation seems to favor a URL-style argument, but we have been getting along fine with a hash, as you’ll see in the generated defaults.

  # With the Sequel sqlite adapter, the :database parameter is read as a path
  # relative to the application root.
  database :adapter => 'sqlite', :database => 'blog.db'

Create the initial db schema.

You can create a Sequel migration with:

rake schema:migration name=users
vi schema/migrations/001_users.rb
Run migrations with:
  rake schema:migrate

  # or with a version number
  rake schema:migrate version=1

Configure Rack

You can run Waves on any Rack-supported Web server, such as Thin and Mongrel (the latter being the default). To use another server, edit the handler parameter in your configuration files (configurations/development.rb). For example, to use Thin:

handler ::Rack::Handler::Thin, :Host => host, :Port => port

You can also configure Rack middleware in the configuration files. Just edit the application parameter:

application do
  use ::Rack::ShowExceptions
  use Rack::CommonLogger
  use ::Rack::Static, :urls => [ '/favicon.ico' ], :root => 'public'
  run ::Waves::Dispatchers::Default.new
end