Cant is a project mainly written in Ruby, based on the MIT license.
Tiny authorization library, let you craft your own rules
Lightweight authorization library, that let you choose where and how you write your rules
Cant is simple : you can use it in any existing or future framework (provided names don't clash)
Cant is small : around 120 lines of code, has no dependencies but for testing
Cant can be configured at class level, and support basic configuration inheritance
in an existing model
class User
include Cant::Embeddable
cant do |action, code|
(action == :post and Code === code) if drunken?
end
end
deny {bob.cant? :post, kata}
in a separate model
class Permission
include Cant::Embeddable
cant do |user, action, resource|
(action == :post and Code === resource) if user.drunken?
end
end
assert {permission.cant? jackie, :post, kata}
in a rails controller
class ApplicationController < ActionController::Base
include Cant::Embeddable
alias_method :authorize_user!, :die_if_cant!
helper_method :cant?
rescue_from Cant::AccessDenied do |error|
flash[:error] = error.message
redirect_to request.referer
end
end
class KatasController < ApplicationController
before_filter :authenticate_user!, :authorize_user!
cant do |request|
current_user.drunken? if request.method == 'POST'
end
end
in a rack middleware ... I have not experimented yet ...
breaking authorization into small independent pieces is valuable, and you do not need a library for that, though using Cant::Editable and Cant::Questionable mixins can help you do that
Cant is simply put a reduce (or fold) on a list of Rules.
Rule
a tuple of functions predicate, die
rules
a list of Rules
fold
function defining how rules are traversed, and how each predicate is evaluated, and what is the result
Cant provide two fold functions, returning both first Rule that predicates, or nil
predicate
default rationale is : true means cant
die
a function, that can raise or return any result suitable to your need
cant?
calls fold function to operate on rules
die_if_cant!
calls fold function to operate on rules, and calls die function on result
First, choose where you want to define your list, and what information a Rule will need
The point of cant is to define a lists of similar rules together, so that they will require similar informations
A list of rules can be embedded in an existing class using Cant::Embeddable mixin
Then there is one list of rules for any instance of this class, and instance evaluation leads to terser rules
Note that a list of rules can be shared by many inquirers, either explicitly or by using class instance variable inheritance feature
Cant module has "reasonable" default values for fold, die, rules
The Cant::Editable module gather methods to configure a Cant engine (fold, die, rules), and defaults to Cant module values
Cant support basic inheritance functionality for configuration with the Cant::Embeddable module ... Ouch what that means ?
Given Admin inherits from User
And User.die {"I'm not dead!"}
Then assert {Admin.die.call == "I'm not dead!"} is true
Well, have a look at read documentation and source code embeddable.rb if you are having trouble with this functionality
You are free to pick one that suit your needs
There are a couple of things to drive your choice :
params of cant? are passed to predicate
params of die_if_cant! are passed to predicate and die
number and order of params of in a rule list should be the same
the context of predicate evaluation (that is defined in fold function) the receiver methods will be available in function
a container can be a handy parameter (Hash) env, params
a block is a proc, and can use default values for params
So pick your own semantic, or grow an existing one
Cant very meaning is : you can unless you cant, and you define what you cant
Defining not or negative ability require some thinking, and I believe we can do it :)
Use cant? method to check
Use die_if_cant! method to check and run die code
When you check, provide the list of parameters you specified in the list of rules you want to verify
cancan, as I started with it and saw that it did not functioned in presence of mongoid as of < 1.5 ... so I planned to do something no dependent of a model implementation
learn you some erlang?, for the fold illustrations had great impact
Howard and Nunemaker for inheritable class instance variables
specs are green on mri : [1.9.2-p0, 1.8.7-p302]
There is few lines of code and concept is simple : fold a list of functions... Though, we can make it better and lesser, cant we ?
can be ran with
COVERAGE=true rspec /spec
Is MIT, available in source code
Fill an item in tracker
Add a page on wiki
Add a spec, open a pull request on topic branch, commit granted on first accepted patch