Wrapt
Wrapt is a rack middleware that provides facilities to any rack application for wrapping the content in a consistent layout.
Wrapt is intended to sit out the front of a rack graph (but doesn’t have to), and is only activated when a downstream application asks to be wrapped in a layout. This means that disparate rack applications that have been mounted, may share the same layout and appear to belong to a single application.
Wrapt injects a layout object into the Rack environment which is idle until activated. To activeate, just assign it some content, and return it as the body portion of your response.
Example
Declare your middleware stack
use Wrapt
run MyApp
Get your application using the wrapt layout
class MyApp def self.call(env) new.call(env) end def call(env) layout = env[‘layout’] layout.content = “This is the content of my app” Rack::Response.new(layout).finish end
end
Say our layout file looked like this:
%html
%body
= yield
We would end up with:
<html>
<body>
This is the content of my app
</body>
</html>
Layout Files
Wrapt is built on Tilt Any tilt compatible template is usable.
A layout file is one that is constructed for use with a layout. To fill in the content into the layout template, you ‘yield’.
Template Location
By default, wrapt will look in the following palces for your layout templates:
- layouts
- views/layouts
- app/views/layouts
You can customize this by passing an array of directory locations to wrapt when declaring the middleware.
use Wrapt do |wrapt|
wrapt.layout_dirs = ["/path/to/my/layouts", "/fallback/path/to/layouts"]
end
Directories are checked in order and the first template found is used.
Template Naming
Templates follow a simple naming convention.
<template_name>.<format>.<template_type>
For example. The default template name is “application” with a default format of “html”. This will match anything then of the form “application.html”
And will render the layout, inserting the content in the right spot.
You can define the name of the default template when declaring the middleware
use Wrapt do |wrapt|
wrapt.default_template = "my_default_layout"
end
You can also select the layout to use inside a request. The following sets the layout for all downstream applications as ‘special’ (unless it’s changed downstream’)
def call(env)
layout = env['layout']
layout.template_name = "special"
app.call(env)
end
Ask the layout to check if a given layout is available. You can then decide if you want to use that, or leave it as is.
def call(env)
content = generate_content_somehow
layout = env['layout']
layout.template_name = 'error' if layout.template_name?('error')
layout.content = content
Rack::Response.new(layout).finish
end
Format
Layouts are associated with a format. By default the format is html. Tempaltes are selected by their name with ...
You can select a default format when declaring the middleware
use Wrapt do |wrapt|
wrapt.default_format = :json
end
Or in the request
def call(env)
layout = env['layout']
layout.format = :json
layout.content = {:my => "hash"}.to_json
end
Content Sections
Wrapt allows you to have different sections of content. To declare this:
layout.content = "foo" # main content
layout.set_content_for(:nav, "some navigation")
Once that content is set, you may then use it in the layout by yielding to the layout.
%h1 My Layout
= yield # yields the main content
%nav
= yield :nav # yields the content with the label :nav
Preventing Layouts from the Client
Wrapt allows you to prevent layouts from being applied when requested by the client.
This means that when using ajax, or esi, you can request the content without layout. There is no magic formula for this, because there could be any number of ways to provide this facility. Instead of prescribing a method to allow requests to not include the layout, you may configure wrapt with a block which checks the request. From there you can choose to ignore the layout request.
Example
use Wrapt do |wrapt|
wrapt.ignore_layout do |env|
request = Rack::Request.new(env)
request.params['ignore_layout'] == 'true'
end
end
run MyApp
Now when you make a request to any url, you may tell it to ignore the layout by including an ‘ignore_layout=true’ on the url.
GET ‘/foo?ignore_layout=true’
Helpers
You can include any helpers you need into the layout by including them into
Wrapt::Helpers
Wrapping content on demand
You can use the layouter object to wrap content on demand
def call(env)
layout = env['layout']
wrapped_content = layout.wrap("my content", :layout => :inner_layout, :format => :json)
layout.content = wrapped_content
Rack::Response(layout).finish
end
Note on Patches/Pull Requests
- Fork the project.
- Make your feature addition or bug fix.
- Add tests for it. This is important so I don’t break it in a
future version unintentionally. - Commit, do not mess with rakefile, version, or history.
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) - Send me a pull request. Bonus points for topic branches.
Copyright
Copyright © 2010 Daniel Neighman. See LICENSE for details.