patriciomacadden/hobbit

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# Hobbit [![Build Status](http://img.shields.io/travis/patriciomacadden/hobbit.svg)](https://travis-ci.org/patriciomacadden/hobbit) [![Code Climate](http://img.shields.io/codeclimate/github/patriciomacadden/hobbit.svg)](https://codeclimate.com/github/patriciomacadden/hobbit) [![Code Climate Coverage](http://img.shields.io/codeclimate/coverage/github/patriciomacadden/hobbit.svg)](https://codeclimate.com/github/patriciomacadden/hobbit) [![Dependency Status](http://img.shields.io/gemnasium/patriciomacadden/hobbit.svg)](https://gemnasium.com/patriciomacadden/hobbit) [![Gem Version](http://img.shields.io/gem/v/hobbit.svg)](http://badge.fury.io/rb/hobbit)

A minimalistic microframework built on top of [Rack](http://rack.github.io/).

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'hobbit'
# or this if you want to use hobbit master
# gem 'hobbit', github: 'patriciomacadden/hobbit'
```

And then execute:

```bash
$ bundle
```

Or install it yourself as:

```bash
$ gem install hobbit
```

## Features

* DSL inspired by [Sinatra](http://www.sinatrarb.com/).
* [Speed](https://github.com/luislavena/bench-micro).
* Extensible with standard ruby classes and modules, with no extra logic. See
[hobbit-contrib](https://github.com/patriciomacadden/hobbit-contrib).
* Zero configuration.

## Philosophy

* [Don't repeat yourself](http://en.wikipedia.org/wiki/Don't_repeat_yourself)
* Encourages the understanding and use of [Rack](http://rack.github.io/) and
its extensions instead of providing such functionality.

## Usage

Hobbit applications are just instances of classes that inherits from
`Hobbit::Base`, which complies the
[Rack SPEC](http://rubydoc.info/github/rack/rack/master/file/SPEC).

### Hello World example

Create a file called `app.rb`:

```ruby
require 'hobbit'

class App < Hobbit::Base
  get '/' do
    'Hello World!'
  end
end
```

Create a `config.ru` file:

```ruby
require './app'

run App.new # or just `run App`
```

Run it with `rackup`:

```bash
$ rackup
```

View your app at [http://localhost:9292](http://localhost:9292).

### Routes

Every route is composed of a verb, a path (optional) and a block. When an
incoming request matches a route, the block is executed and a response is sent
back to the client. The return value of the block will be the `body` of the
response. The `headers` and `status code` of the response will be calculated by
`Hobbit::Response`, but you could modify it anyway you want it.

See an example:

```ruby
class App < Hobbit::Base
  get '/' do
    # ...
  end

  post '/' do
    # ...
  end

  put '/' do
    # ...
  end

  patch '/' do
    # ...
  end

  delete '/' do
    # ...
  end

  options '/' do
    # ...
  end
end
```

When a route gets called you have this methods available:

* `env`: The Rack environment.
* `request`: a `Hobbit::Request` instance.
* `response`: a `Hobbit::Response` instance.

And any other method defined in your application.

#### Available methods

* `delete`
* `get`
* `head`
* `options`
* `patch`
* `post`
* `put`

**Note**: Since most browsers don't support methods other than **GET** and
**POST** you must use the `Rack::MethodOverride` middleware. (See
[Rack::MethodOverride](https://github.com/rack/rack/blob/master/lib/rack/methodoverride.rb)).

#### Routes with parameters

Besides the standard `GET` and `POST` parameters, you can have routes with
parameters:

```ruby
require 'hobbit'

class App < Hobbit::Base
  # matches both /hi/hobbit and /hi/patricio
  get '/hi/:name' do
    # request.params is filled with the route paramters, like this:
    "Hello #{request.params[:name]}"
  end
end
```

#### Redirecting

If you look at Hobbit implementation, you may notice that there is no
`redirect` method (or similar). This is because such functionality is provided
by [Rack::Response](https://github.com/rack/rack/blob/master/lib/rack/response.rb)
and for now we [don't wan't to repeat ourselves](http://en.wikipedia.org/wiki/Don't_repeat_yourself)
(obviously you can create an extension!). So, if you want to redirect to
another route, do it like this:

```ruby
require 'hobbit'

class App < Hobbit::Base
  get '/' do
    response.redirect '/hi'
  end

  get '/hi' do
    'Hello World!'
  end
end
```

#### Halting

To immediately stop a request within route you can use `halt`. 

```ruby
require 'hobbit'

class App < Hobbit::Base
  use Rack::Session::Cookie, secret: SecureRandom.hex(64)

  def session
    env['rack.session']
  end

  get '/' do
    response.status = 401
    halt response.finish
  end
end
```

### Built on top of rack

Each Hobbit application is a Rack stack (See this
[blog post](http://m.onkey.org/ruby-on-rack-2-the-builder) for more
information).

#### Mapping applications

You can mount any Rack application to the stack by using the `map` class
method:

```ruby
require 'hobbit'

class InnerApp < Hobbit::Base
  # gets called when path_info = '/inner'
  get do
    'Hello InnerApp!'
  end
end

class App < Hobbit::Base
  map('/inner') { run InnerApp.new }

  get '/' do
    'Hello App!'
  end
end
```

#### Using middleware

You can add any Rack middleware to the stack by using the `use` class method:

```ruby
require 'hobbit'

class App < Hobbit::Base
  use Rack::Session::Cookie, secret: SecureRandom.hex(64)
  use Rack::ShowExceptions

  def session
    env['rack.session']
  end

  get '/' do
    session[:name] = 'hobbit'
  end

  # more routes...
end

run App.new
```

### Security

By default, Hobbit (nor Rack) comes without any protection against web
attacks. The use of [rack-protection](https://github.com/rkh/rack-protection)
is highly recommended:

```ruby
require 'hobbit'
require 'rack/protection'
require 'securerandom'

class App < Hobbit::Base
  use Rack::Session::Cookie, secret: SecureRandom.hex(64)
  use Rack::Protection

  get '/' do
    'Hello World!'
  end
end
```

See the [rack-protection](https://github.com/rkh/rack-protection)
documentation for futher information.

### Testing

[rack-test](https://github.com/brynary/rack-test) is highly recommended. See
an example:

In `app.rb`:

```ruby
require 'hobbit'

class App < Hobbit::Base
  get '/' do
    'Hello World!'
  end
end
```

In `app_spec.rb`:

```ruby
require 'minitest/autorun'
# imagine that app.rb and app_spec.rb are stored in the same directory
require 'app'

describe App do
  include Rack::Test::Methods

  def app
    App.new
  end

  describe 'GET /' do
    it 'must be ok' do
      get '/'
      last_response.must_be :ok?
      last_response.body.must_match /Hello World!/
    end
  end
end
```

See the [rack-test](https://github.com/brynary/rack-test) documentation
for futher information.

### Extensions

You can extend Hobbit by creating standard ruby modules. See an example:

```ruby
module MyExtension
  def do_something
    # do something
  end
end

class App < Hobbit::Base
  include MyExtension

  get '/' do
    do_something
    'Hello World!'
  end
end
```

#### Hobbit::Contrib

[hobbit-contrib](https://github.com/patriciomacadden/hobbit-contrib) is a ruby
gem that comes with a lot of hobbit extensions, such as:

* `Hobbit::Render`: provides basic template rendering.
* `Hobbit::Session`: provides helper methods for handling user sessions.
* `Hobbit::Environment`: provides helper methods for handling application
environments.
* `Hobbit::Filter`: provides helper class methods for handling Sinatra-like
filters.
* `Hobbit::ErrorHandling`: provides helper class methods for handling
Sinatra-like error handling.

... And many more!

## Community

* [Wiki](https://github.com/patriciomacadden/hobbit/wiki): Guides, how-tos and recipes
* IRC: [#hobbitrb](irc://chat.freenode.net/#hobbitrb) on [http://freenode.net](http://freenode.net)

## Presentations

* Building web applications in Ruby, by [Krzysztof Wawer](https://github.com/wafcio)
([english](https://speakerdeck.com/wafcio/hobbit-english), [polish](https://speakerdeck.com/wafcio/hobbit))

## Contributing

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

## License

See the [LICENSE](https://github.com/patriciomacadden/hobbit/blob/master/LICENSE).