Bruter

Bruter is a miniature Ruby library that allows its bearer the ability to craft elegant Rack-based web applications with ease. Bruter stands on the backs of giants:

  • Servers interface with Bruter -- a Rack-compatible application -- with minimal configuration
  • Variably named paths are routed to their proper destination by HttpRouter
  • Dynamic assets -- Sass, LESS, CoffeeScript and more -- are compiled and served by Sprockets
  • Views and templates are rendered as one by Mustache

Surely under 200 lines of code without comments, Bruter is meant to be easy to understand and use. But do not underestimate Bruter's small footprint: Bruter's role lies in its ability to delegate responsibility and provide an intuitive syntax.

Example

Bruter can be found hiding in the usual places.

gem install bruter

You'll need to create a Rackup file.

# config.ru
require 'bruter'
$:.unshift File.dirname(__FILE__)
require 'app/application'
require 'app/views/hello' # Note that you need to require any files you'll reference, including views

run Application.new

Routes and asset paths are defined in a subclass of Bruter::Application.

# app/application.rb

class Application < Bruter::Application

  serve_assets 'assets'                 # Asset paths are relative to where the method is called
  get '/hello/:name', to: 'views/hello' # Bruter will look for a Views::Hello class to render

end

View classes should subclass Bruter::Mustache.

# app/views/hello.rb

module Views
  class Hello < Bruter::Mustache

    def name
      params[:name]
    end

  end
end

Bruter's Mustache will automatically look for an accompanying template in '../templates' relative to the view class.

# app/templates/hello.mustache

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Hello {{name}}!</title>
  <link rel="stylesheet" href="/stylesheets/application.css">
</head>
<body>
  <h1>Bruter kindly welcomes you, {{name}}!</h1>
  <img src="/images/bruter.jpg">
</body>
</html>

Place 'bruter.jpg' in 'app/assets/images' and a stylesheet of your preferred format in 'app/assets/stylesheets' and Sprockets will take care of the rest.

# app/assets/stylesheets/application.css.scss

body {
  text-align: center
  h1 { font-size: 1.25em; }
}

Bruter is a Rack application; choose any compatible server.

rackup config.ru

Routing

Routing is handled by HttpRouter. Most applications will subclass Bruter::Application and generate routes by calling the class method :add. The method accepts a path and a hash of options.

add(path, options = {})

Most routes will want to specify a :to option. The :to option can be any Rack application.

add '/welcome', to: [200, {'Content-Type' => 'text/html'}, ['Welcome to Bruter.']]

Or more interestingly, it can be a string representing a Mustache view class.

add '/welcome', to: 'welcome'           # Looks for Welcome
add '/hello',   to: 'views/hello_there' # Looks for Views::HelloThere

The path can include named variables and globs.

add '/hello/:name',   to: 'hello'   # Matches '/hello/bruter' and '/hello/ted'
add '/tagged/*tags',  to: 'tagged'  # Matches '/tagged/web' and '/tagged/volcano/lava/dinosaurs'

Routes can be restricted to certain HTTP request methods.

add '/post/:id', to: 'posts/show', request_method: ['GET', 'HEAD']

Routes can be named in order to construct their paths at a later time.

add '/post/:id', to: 'posts/show', name: :post  # In a view, calling path(:post, 5) returns '/post/5'

Variable paths can have a regex matching condition placed on them.

add '/:a-plus-:b-equals', to: 'add', matching: {a: /\d+/, b: /\d+/}

Redirects

Redirects can be added by setting a :redirect option instead of a :to option.

add '/old-path', redirect: '/new-path'

Static Files

Static files can be served by the router by setting a :static option instead of a :to option.

add '/images', static: 'app/images'  # Will look for '/images/logo/large.png' in 'app/images/logo/large.png'

Convenience Methods

Bruter also provides a number of convenience methods that pass to :add but first set their :request_method option to correspond to the name of the method.

    get(path, options = {})
   post(path, options = {})
    put(path, options = {})
 delete(path, options = {})
   head(path, options = {})
options(path, options = {})
  trace(path, options = {})
    get(path, options = {})

Under the Hood

When a new Bruter::Application object is instantiated, an HttpRouter object is also instantiated and any routes added to the application class are added to the router object. This object can also be accessed directly with the :router getter method.

app = Bruter::Application.new
app.router.add('/').to('my_view')
run app

See HttpRouter for more information.

Assets

Asset compilation and serving is handled by Sprockets. Asset paths can be added to the asset environment with the class method :serve_assets. The method accepts a path, which is relative to the location the method is called.

# app/application.rb
class Application < Bruter::Application

  serve_assets 'assets'

end

This application will compile and serve assets located in 'app/assets'. For example, a route of /images/logo.png will have the asset environment look for a file named 'app/assets/images/logo.png' and compile (if necessary) and serve it. If it cannot be found, action is passed to the router.

Like with HttpRouter, a new Sprockets::Environment object is instantiated and any asset paths appended to it when a new Bruter::Application object is instantiated. This environment can be accessed directly with the :assets getter method.

app = Bruter::Application.new
app.assets.append_path('my/assets/path')
run app

See Sprockets for more information.

Rendering

Routes can be directed to Rack-compatible applications or to strings that represent Mustache view classes. When the latter occurs the application will instantiate the view class with three objects -- a Rack request object, a Rack response object, and the Router object -- and call render. The view class can simply subclass from Mustache, but it will likely want to subclass Bruter::Mustache, itself a subclass of Mustache.

Bruter::Mustache provides a few helpers. First, it tells any subclasses to look for their templates in '../template' relative to the view file. It provides an :initialize method that accepts the three previously named objects and then attempts to invoke :setup if the view has defined it. It provides getter methods to access the Rack request object (:request), the Rack response object (:response), the Router object (:router), the Rack env (:env) and the params set during routing (:params). It also defines a :path method, which accepts the name of a named route and an optional list of arguments to construct a path string.

For more information, see Mustache.

License

Bruter is Copyright © 2011 by Ted Kimble and distributed under the MIT license; see LICENSE for more information.