Getting Started

This guide will help you get started with Lively, a framework for building real-time applications in Ruby.

Installation

To install Lively, you can use the following command:

$ gem install lively

Basic Usage

Create a new directory for your Lively application:

$ mkdir my_lively_app
$ cd my_lively_app

Then create a gems.rb file in your project directory:

source "https://rubygems.org"
gem "lively"

Next, run bundle install to install the Lively gem:

$ bundle install

Create an application.rb file in your project directory:

#!/usr/bin/env lively

class HelloWorldView < Live::View
	def bind(page)
		super
		self.update!
	end
	
	def render(builder)
		builder.tag(:p) do
			builder.text("Hello World!")
		end
	end
end

Application = Lively::Application[HelloWorldView]

Now you can run your Lively application:

$ chmod +x application.rb
$ ./application.rb

You should see "Hello World!" displayed in your browser.

Shared State

When multiple browser windows need to share state — for example, a multiplayer game or a collaborative tool — you can pass shared state to Application[]. The state is passed as keyword arguments to all views, both during the initial page render and when browsers reconnect via WebSocket.

#!/usr/bin/env lively

class GameState
	def initialize
		@players = []
	end
	
	attr :players
	
	def add_player(player)
		@players << player
	end
end

class GameView < Live::View
	def initialize(id, data, game_state: nil)
		super(id, data)
		@game_state = game_state
	end
	
	def render(builder)
		builder.tag(:p) do
			builder.text("Players: #{@game_state.players.length}")
		end
	end
end

Application = Lively::Application[GameView, game_state: GameState.new]

The game_state: keyword is passed to every GameView instance — whether created by the initial page load or by a WebSocket reconnection. This means all connected browsers share the same GameState object.

For more complex applications, subclass class Lively::Application and add routes with #configure_routes:

class Application < Lively::Application
	def allowed_views
		[DisplayView, ControlView]
	end
	
	def state
		{controller: @controller}
	end
	
	def initialize(delegate)
		@controller = MyController.new
		super
	end
	
	def configure_routes(router)
		router.get("/") do
			body = resolver.root(DisplayView)
			Lively::Pages::Index.new(title: title, body: body).call
		end
		
		router.get("/control") do
			body = resolver.root(ControlView)
			Lively::Pages::Index.new(title: title, body: body).call
		end
	end
end

allowed_views defines the view classes the shared resolver may construct. Each matched route constructs its root view using the shared resolver, wraps that concrete body in a page, and invokes Page#call to produce the response. This keeps view construction lazy without making the page body itself callable. Lively installs its /live WebSocket route independently, so overriding configure_routes does not remove it.

Routes match exact paths and may accept one or more HTTP methods. Handlers receive the original request and can parse query parameters when needed. Routes without an explicit method accept every method.

Requests which do not match a route are passed to the application's delegate. Applications that need custom fallback behavior can supply an appropriate delegate when they are constructed.

Live Reloading

To enable live reloading, add the io-watch gem to your gems.rb file:

gem "io-watch"

Then run:

$ io-watch . -- ./application.rb