Renee is the super-friendly Rack based web framework.
run Renee { path('/') { halt "Hello Renee!" } }
This site was built using Renee and is available on Github.
Want the 2 minute intro? Try out this deadly simple tutorial.
Renee is a new way to think about writing web applications.
Traditionally, routing and controller logic have been separate. In Rails, for instance, your path is matched to a controller and an action. This does not reflect the hierarchical nature of REST.
Consider a simple example. The route /posts/45/comments. Typically, you'd expect this to load the post with the id 45, and then load the comments on that post. In Rails, your code to load a post and understand that parameter would have to be in both your posts controller and your comments controller. Sinatra does no better as it searches linearly though a list of path to find a matching path, and then executes the block associated with it.
To model this same idea in Renee, you could do the following:
run Renee do path 'posts' do var :int do |id| post = Posts.find(id) path 'comments' do get { render! "comments", :comments => post.comments } end end end end
Suddenly, you have access to the previously referred to part of the path, namely, the /posts/45 part. It's a locally scoped variable, as is the id, so you don't have to worry about anyone outside of it's scope having access to it.
To find out more, take a look at the routing methods available to you.
Renee lives and breathes inside of Rack. Let's take a look at the example above and understand a little better what's going on. We'll modify it slightly for the sake of clarity:
run Renee do p request.path_info # printing path "posts" do p request.path_info # printing var :int do |id| p request.path_info # printing halt :ok end end end
If you run a request with the path /posts/12 through here, you'll get three print statements:
"/posts/123" "/123" ""
The PATH_INFO is being consumed by each scope. If you don't halt, don't worry, your request will get put back together again after it falls out of each block. This let's you move parts of your application around without fearing how the route is being consumed.
Renee loves Rack. To run a arbitrary rack end point, you can use #run! to stop execution and pass off your request to an Rack application. An example:
run Renee do path "posts" do run! PostsEndpoint # this can be any Rack application end end
To find out more about integrating with rack, take a look at rack integration to find out more!
Converting your variable and returning 400's or 404's can get tedious, so why not do it all in one place? Renee allows you to register arbitrary variable types, transform them, and handle error cases in one, easy place. Here is an example!
run Renee { path "color" do var :hex do |color| get { halt "<body bgcolor='##{color.to_s(16)}'></body>" } end end }.setup { register_variable_type(:hex, /[0-9a-f]{6}/). on_transform { |v| v.to_i(16) }. raise_on_error! }
Now, let's throw some requests against this. If we go to http://127.0.0.1:9393/color/ff99ff, we'll get a nice fuchsia. Try http://127.0.0.1:9393/color/blue and you'll get a 400. Too bad.
To find out more about variable types, read all about them!
Okay, so, writing blocks is fun, but, it can get a bit indent-y when we don't really need it to be. Feel free to chain together whatever methods you'd like. For instance the above example could have been written:
run Renee { path("color").var(:hex).get { |color| halt "<body bgcolor='##{color.to_s(16)}'></body>" } }.setup { register_variable_type(:hex, /[0-9a-f]{6}/). on_transform { |v| v.to_i(16) }. raise_on_error! }
You can easily consume chaining yourself, if you want to implement your own routing methods. Find out more!
Not happy with what Renee gives you? You can easily subclass to define whatever you need.
class MyApp < Renee::Application app { path('justice/great').get.for_great_justice! halt 404, "justice not found" } def for_great_justice! halt "for great justice!" end end run MyApp # curl http://localhost:9393/justice/great # for great justice # curl http://localhost:9393/justice/good # justice not found
Renee is gem-based. If you're using rubygems, you can simply:
$> gem install renee
If you're using Bundler, you can add
gem 'renee', '~> 0.3.0'
to your Gemfile.
Renee has (hopefully) a small number of keywords divided between several components:
Using Renee is as simple as understanding how to configure settings, define routes, and respond to requests. Renee usage in a nutshell:
run Renee { path 'blog' do get { render! "posts/index" } post { Blog.create(request.params); halt :created } var do |id| @blog = Blog.get(id) get { render! "posts/show" } put { @blog.update(request.params); halt :ok } end end }.setup { views_path "./views" }
Check out detailed guides for each aspect below:
↪ Read about Responding and Rendering
Renee is a very modular library comprised of four standalone libraries:
renee-core, renee-render, renee-url-generation, and renee-session.
If you need additional functionality, extending Renee can be very easy and quick. Renee extensions are basically just included modules. Check out the Extending Renee guide for more information.
Renee is also well-documented with YARD:
Renee's structure is pretty simple so far. The basic Rack DSL is contained in renee-core. This gem has no other dependencies other than Rack.
The rendering side is in renee-render, which depends on Tilt.
The kitchen-sink gem which incorporates all of the others is renee. Please, any bugs, any ideas, I'd love to hear any of it. Love, Team Renee. ♥