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:
1 2 3 4 5 6 | require 'rubygems' require 'lego-core' class MyApp < Lego::Controller; end run MyApp |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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) "<h1>#{content}</h1>" 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 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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 |
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:
1 2 3 4 5 6 7 8 9 | Lego.plugin MyPlugin # or group multiple plugin calls in a config block Lego.config do plugin MyViewPlugin plugin MyControllerPlugin plugin MyRouteMatcherPlugin end |
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:
1 2 3 4 5 6 7 8 9 | class MyApp < Lego::Controller plugin Routes set :foo => "bar", :baz => "quux" get("/foo") { options :foo } get("/bar") { options :bar } end |
As with plugins you can use set globally:
1 2 3 4 5 6 7 8 | Lego.set :foo => "bar" # or group multiple set calls in a config block Lego.config do set :foo => "bar" set :baz => "quux" end |
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!
Tagged with framework, lego, lego-core, Ruby, web. Written by: Patrik Hedman
