Zooplankton

Build Status Code Climate

Zooplankton are the kind of plankton that are animals (as opposed to phytoplankton, which are plants).

Zooplankton is a library for helping you turn Rails routes into URI Template strings. It's useful for helping yourself generate the _links part of HAL, for example.

Usage

Given a route file like this:

SomeApp::Application.routes.draw do
  root 'root#index'
  get '/posts/:slug', to: 'posts#show', as: :post
  get '/posts/:slug/comments', to: 'comments#index', as: :comments
  get '/posts/:slug/comments/:comment_id', to: 'commendts#show', as: :comment
end

Without Zooplankton, you might end up generating a URI template for a route by abusing Rails's url helpers like this:

CGI.unescape post_path(slug: "{slug}")
# => '/posts/{slug}'
CGI.unescape comment_path(slug: "{slug}", comment_id: "{comment_id}")
# => '/posts/{slug}/comments/{comment_id}'

If you needed to include query parameters in your template, you'd have an even harder time. Something like:

CGI.unescape "#{comments_path(slug: "{slug}")}{?page,page_size}"
# => '/posts/{slug}/comments{?page,page_size}'

With Zooplankton, you can use it like this:

> Zooplankton.path_template_for(:root)
# => '/'
> Zooplankton.path_template_for(:post)
# => '/posts/{slug}'
> Zooplankton.path_template_for(:comment)
# => '/posts/{slug}/comments/{comment_id}'

It also handles replacing some (or all, though you might decide to use a Rails url helper at that point) of the templated variables if you want to prepopulate some of them ahead of time:

> Zooplankton.path_template_for(:comment, slug: 'the-best-post-ever')
# => '/posts/the-best-post-ever/comments/{comment_id}'

And you can add some query parameters when you're generating the template, if you need:

> Zooplankton.path_template_for(:comments, :page, slug: 'the-best-post-ever')
# => '/posts/the-best-post-ever/comments{?page}'
> Zooplankton.path_template_for(:comments, %i(page page_size), slug: 'the-best-post-ever')
# => '/posts/the-best-post-ever/comments{?page,page_size}'
> Zooplankton.path_template_for(:comments, %i(page page_size))
# => '/posts/{slug}/comments{?page,page_size}'

If you supply a query parameter for replacement, it'll denote a continuation:

> Zooplankton.path_template_for(:comments, %i(page page_size), slug: 'the-best-post-ever', page: 1)
# => '/posts/the-best-post-ever/comments?page=1{&page_size}'

It'll generate URLs, too, not just paths.

> Zooplankton.url_template_for(:root)
# => 'http://example.com/'
> Zooplankton.url_template_for(:post)
# => 'http://example.com/posts/{slug}'

URI Templates LOLWUT

URI Templates are a notation for teaching machines how to build URIs. They're basically rules for string interpolation. Zooplankton supports a small subset of all the notations, outlined here.

Simple String Expansion

RFC direct link

This is the simplest part of URI Templates and is what Zooplankton uses for parameters that are part of the path of a URI. Basically, given a template like "foo{var}baz" and assuming you have a value of 'bar' for var, you'd end up with "foobarbaz".

Form-Style Query Expansion

RFC direct link

This expansion is for telling a computer to build a query string. Something like "name{?first,last}" with values like in the hash'ben', last: 'hamill'would expand to"name?first=ben&last=hamill"`. Zooplankton will use this when it's appropriate for building query strings.

Form-Style Query Continuation

RFC direct link

This expansion is for telling a computer to finish off a query string that you've already started. Basically, it's like a query expansion, but instructs the computer to use a starting &, rather than a ?. So "name{&first,last}" with values like {first: 'ben', last: 'hamill'} would end up as "name&first=ben&last=hamill", but the greatest usefulness is for something like "name?middle=dale{?first,last}" which would end up as "name?middle=dale&first=ben&last=hamill". Zooplankton will use this when it's appropriate for building query strings.

Testing

rake spec

This library uses the Appraisal gem to test against multiple versions of Rails. You can run them individually with

appraisal rails4 rake spec
appraisal rails5 rake spec

Look in ./Appraisals for available Rails versions.

Contributing

Help is gladly welcomed. If you have a feature you'd like to add, it's much more likely to get in (or get in faster) the closer you stick to these steps:

  1. Open an Issue to talk about it. We can discuss whether it's the right direction or maybe help track down a bug, etc.
  2. Fork the project, and make a branch to work on your feature/fix. Master is where you'll want to start from.
  3. Turn the Issue into a Pull Request. There are several ways to do this, but hub is probably the easiest.
  4. Make sure your Pull Request includes tests.
  5. Bonus points if your Pull Request updates CHANGES.md to include a summary of your changes and your name like the other entries. If the last entry is the last release, add a new ## Unreleased heading.

If you don't know how to fix something, even just a Pull Request that includes a failing test can be helpful. If in doubt, make an Issue to discuss.