It’s all about the bits and pieces
Introducing Lego
For a while now Mathias and I have been hacking away on our very own web framework called Lego.
But why? I hear you cry, why yet another one, what’s wrong with Rails, Merb, Ramaze, Sinatra, Camping, Rango, Waves, Mack, and so on and so on.
Well, they’re all great but we believe they aren’t dumb enough!
Lego however is about as dumb as it gets, all it knows is how to handle the request/response cycle and leaves the rest up to plugins.
The downside of this approach is that it takes a little bit more work to get it up and running the upside is that you get exactly what you want, nothing more, nothing less.
I’m intrigued, tell me more
So at it’s core there’s lego-core which contains only the bare essentials, a way to set up a controller that rack can run, and a way to extend the various parts of lego.
Future plans include a lego-more gem already setup with commonly used plugins so you easily can get up and running quickly and a central repository of available lego plugins.
A simple application
Provided that you have lego-core installed (gem install lego-core) put the following in a config.ru file:
[cc lang="ruby"]
require ‘rubygems’
require ‘lego-core’
class MyApp < Lego::Controller; end
run MyApp
[/cc]
Run it with rackup and point your browser to http://localhost:9292/ and you should be met by a plain old ‘404 – Not found’, not terribly exiting right? But that’s pretty much all lego-core gives you
So what about those plugins?
The lego extension system allows you to hook into various parts of the execution chain, namely:
View – For action and view related stuff
Controller – For defining controller dsl’s
Router – Rules for how lego should match routes, must have a self.match_route method which takes a route and an env parameter and return either a two element array containing the env and a hash of match data (or an empty hash if no match data is available) or false
At it’s core, a plugin is a module that responds to register who’s responsibility is to register with lego, following is a simple plugin example:
[cc lang="ruby"]
module SamplePlugin
# Register is called by lego when plugin is loaded
def self.register(lego)
lego.add_plugin :view, View
lego.add_plugin :router, Matcher
lego.add_plugin :controller, Routes
end
# A plugin module we load as a view helper
module View
def h1(content)
“
#{content}
”
end
end
# A very simply route helper
module Routes
def get(path, &block)
add_route(:get, {:path => path, :action_block => block})
end
end
# A very simple route matcher
module Matcher
def self.match_route(route, env)
(route[:path] == env['PATH_INFO']) ? [env, {}] : false
end
end
end
[/cc]
It’s about time for a real example!
As we showed you earlier, lego-core gives you a way to set up an application but it don’t know how to map routes to action so let’s expand on the previous application with our newly gained knowledge of lego’s extension system:
[cc lang="ruby"]
require ‘rubygems’
require ‘lego-core’
module Routes
def self.register(lego)
lego.add_plugin :controller, SinatraController
lego.add_plugin :router, SimpleRouter
end
# implements a basic Sinatra inspiered dsl
module SinatraController
def get(path, &block)
add_route(:get, {:path => path, :action_block => block})
end
end
# Implements a very basic mather rule
module SimpleRouter
def self.match_route(route, env)
(route[:path] == env['PATH_INFO']) ? true : false
end
end
end
# define an application
class MyApp < Lego::Controller
plugin Routes
get "/" do
"Hello from /"
end
end
run MyApp
[/cc]
As before, run it with rackup and point your browser to http://localhost:9292/ and this time you should be greeted by “Hello from /”.
Don’t repeat yourself
If you have a plugin you want to use in every application, then consider defining it globally:
[cc lang="ruby"]
Lego.plugin MyPlugin
# or group multiple plugin calls in a config block
Lego.config do
plugin MyViewPlugin
plugin MyControllerPlugin
plugin MyRouteMatcherPlugin
end
[/cc]
Configuration options
Lego also comes with a very simple configuration handler, it basically provides two methods, set and options, lets look at them in action:
[cc lang="ruby"]
class MyApp < Lego::Controller
plugin Routes
set :foo => “bar”, :baz => “quux”
get(“/foo”) { options :foo }
get(“/bar”) { options :bar }
end
[/cc]
As with plugins you can use set globally:
[cc lang="ruby"]
Lego.set :foo => “bar”
# or group multiple set calls in a config block
Lego.config do
set :foo => “bar”
set :baz => “quux”
end
[/cc]
Wrapping up
In conclusion Lego is a ‘Use what you want’ framework that tries to stay out of your way as much as possible and thank’s to it’s modular design, you are free to use your favourite technologies and tools.
Please note that it’s still in a highly experimental stage!
