abilities 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +85 -0
  4. data/Rakefile +32 -0
  5. data/lib/abilities.rb +25 -0
  6. data/lib/abilities/action_controller/base.rb +20 -0
  7. data/lib/abilities/action_view/base.rb +14 -0
  8. data/lib/abilities/concern.rb +12 -0
  9. data/lib/abilities/definitions.rb +54 -0
  10. data/lib/abilities/exceptions.rb +3 -0
  11. data/lib/abilities/proxy.rb +23 -0
  12. data/lib/abilities/railtie.rb +14 -0
  13. data/lib/abilities/version.rb +5 -0
  14. data/lib/generators/abilities/install_generator.rb +13 -0
  15. data/lib/generators/abilities/templates/abilities.rb +2 -0
  16. data/test/changes_test.rb +12 -0
  17. data/test/checking_test.rb +52 -0
  18. data/test/controller_test.rb +38 -0
  19. data/test/dummy/README.rdoc +28 -0
  20. data/test/dummy/Rakefile +6 -0
  21. data/test/dummy/app/assets/javascripts/application.js +13 -0
  22. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  23. data/test/dummy/app/controllers/application_controller.rb +5 -0
  24. data/test/dummy/app/helpers/application_helper.rb +2 -0
  25. data/test/dummy/app/models/post.rb +3 -0
  26. data/test/dummy/app/models/user.rb +2 -0
  27. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  28. data/test/dummy/bin/bundle +3 -0
  29. data/test/dummy/bin/rails +4 -0
  30. data/test/dummy/bin/rake +4 -0
  31. data/test/dummy/config.ru +4 -0
  32. data/test/dummy/config/application.rb +23 -0
  33. data/test/dummy/config/boot.rb +5 -0
  34. data/test/dummy/config/database.yml +25 -0
  35. data/test/dummy/config/environment.rb +5 -0
  36. data/test/dummy/config/environments/development.rb +37 -0
  37. data/test/dummy/config/environments/production.rb +83 -0
  38. data/test/dummy/config/environments/test.rb +39 -0
  39. data/test/dummy/config/initializers/abilities.rb +8 -0
  40. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  41. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  42. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  43. data/test/dummy/config/initializers/inflections.rb +16 -0
  44. data/test/dummy/config/initializers/mime_types.rb +4 -0
  45. data/test/dummy/config/initializers/secret_token.rb +1 -0
  46. data/test/dummy/config/initializers/session_store.rb +3 -0
  47. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  48. data/test/dummy/config/locales/en.yml +23 -0
  49. data/test/dummy/config/routes.rb +56 -0
  50. data/test/dummy/config/secrets.yml +22 -0
  51. data/test/dummy/db/migrate/20140629203344_create_users.rb +11 -0
  52. data/test/dummy/db/migrate/20140629203412_create_posts.rb +10 -0
  53. data/test/dummy/db/schema.rb +31 -0
  54. data/test/dummy/log/development.log +80 -0
  55. data/test/dummy/log/test.log +4543 -0
  56. data/test/dummy/public/404.html +67 -0
  57. data/test/dummy/public/422.html +67 -0
  58. data/test/dummy/public/500.html +66 -0
  59. data/test/dummy/public/favicon.ico +0 -0
  60. data/test/generator_test.rb +18 -0
  61. data/test/test_helper.rb +24 -0
  62. data/test/view_test.rb +23 -0
  63. metadata +186 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8dcaf769f98c1072413ffbd18e8a14668ce4d757
4
+ data.tar.gz: b6d76bf41fc236ab00c23e12d04313047761b5d3
5
+ SHA512:
6
+ metadata.gz: 833a56e60b6484581beef76c1ea9894b2dec1b6418a3b85a9d65148a9f590cbdfa9b574221c7994501778677a1dd36bdb7b221ca81ab91c776cbcb3ec410e8cc
7
+ data.tar.gz: 59edbc899675ac1cadc1d3b9edb84898302c01ba958e838410f2aeab1542fc747578b6f71835b3f1c979f0b8440ce531e10e70a97344c57a4238680baa1510d7
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Museways
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,85 @@
1
+ {<img src="https://badge.fury.io/rb/abilities.png" alt="Gem Version" />}[http://badge.fury.io/rb/abilities] {<img src="https://codeclimate.com/github/museways/abilities.png" />}[https://codeclimate.com/github/museways/abilities] {<img src="https://travis-ci.org/museways/abilities.png?branch=master" alt="Build Status" />}[https://travis-ci.org/museways/abilities]
2
+
3
+ = Abilities
4
+
5
+ Minimalistic cancan alternative for rails.
6
+
7
+ = Install
8
+
9
+ Put this line in your Gemfile:
10
+ gem 'abilities'
11
+
12
+ Then bundle:
13
+ $ bundle
14
+
15
+ = Configuration
16
+
17
+ Generate the abilities initializer:
18
+ bundle exec rails g abilities:install
19
+
20
+ Ensure there is a current_user helper available in your controllers and views:
21
+ class ApplicationController < ActionController::Base
22
+ helper :current_user
23
+ def current_user
24
+ @current_user ||= User.find_by(id: session[:user_id])
25
+ end
26
+ end
27
+
28
+ = Usage
29
+
30
+ == Defining
31
+
32
+ All the abilities are defined in config/initializers/abilities.rb by can and cannot methods:
33
+ Abilities.define do
34
+ can :create, Post
35
+ cannot :destroy, User unless admin?
36
+ can :edit, Post do |post|
37
+ post.user == self
38
+ end
39
+ end
40
+
41
+ == Loading
42
+
43
+ If you want to load the abilities from the database you may do something like this:
44
+ permissions.each do |permission|
45
+ can premissions.action, permissions.subject
46
+ end
47
+
48
+ == Checking
49
+
50
+ === Controllers
51
+
52
+ With the authorize! method Abilities::AccessDenied is raised if authorization fails:
53
+ class PostsController < ApplicationController
54
+ def edit
55
+ @post = Post.find(params[:id])
56
+ authorize! :edit, @post
57
+ end
58
+ end
59
+
60
+ If you don't want an exception to be raised use can? and cannot? helpers:
61
+ class UsersController < ApplicationController
62
+ def edit
63
+ @post = Post.find(params[:id])
64
+ if can? :edit, @post
65
+ @post.update post_params
66
+ else
67
+ # handle access denied
68
+ end
69
+ end
70
+ end
71
+
72
+ === Views
73
+
74
+ The helpers can? and cannot? are available:
75
+ <% if can? :create, Post %>
76
+ <%= link_to new_post_path %>
77
+ <% end %>
78
+
79
+ = Credits
80
+
81
+ This gem is maintained and funded by museways[http://museways.com].
82
+
83
+ = License
84
+
85
+ It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Abilities'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
22
+ require 'rake/testtask'
23
+
24
+ Rake::TestTask.new(:test) do |t|
25
+ t.libs << 'lib'
26
+ t.libs << 'test'
27
+ t.pattern = 'test/**/*_test.rb'
28
+ t.verbose = false
29
+ end
30
+
31
+
32
+ task default: :test
data/lib/abilities.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'abilities/action_controller/base'
2
+ require 'abilities/action_view/base'
3
+ require 'abilities/proxy'
4
+ require 'abilities/definitions'
5
+ require 'abilities/exceptions'
6
+ require 'abilities/concern'
7
+ require 'abilities/railtie'
8
+
9
+ module Abilities
10
+ class << self
11
+
12
+ def define(&block)
13
+ @block = block
14
+ end
15
+
16
+ def can?(actor, action, subject)
17
+ Definitions.new(actor, &@block).can?(action, subject)
18
+ end
19
+
20
+ def cannot?(*args)
21
+ !can?(*args)
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ module Abilities
2
+ module ActionController
3
+ module Base
4
+ extend ActiveSupport::Concern
5
+
6
+ protected
7
+
8
+ %w(can? cannot?).each do |name|
9
+ define_method name do |action, subject|
10
+ Abilities.send name, current_user, action, subject
11
+ end
12
+ end
13
+
14
+ def authorize!(action, subject)
15
+ raise Abilities::AccessDenied unless can? action, subject
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module Abilities
2
+ module ActionView
3
+ module Base
4
+ extend ActiveSupport::Concern
5
+
6
+ %w(can? cannot?).each do |name|
7
+ define_method name do |action, subject|
8
+ Abilities.send name, current_user, action, subject
9
+ end
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ module Abilities
2
+ module Concern
3
+ extend ActiveSupport::Concern
4
+
5
+ %w(can? cannot?).each do |name|
6
+ define_method name do |action, subject|
7
+ Abilities.send name, self, action, subject
8
+ end
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,54 @@
1
+ module Abilities
2
+ class Definitions
3
+
4
+ def initialize(actor, &block)
5
+ @actor = actor
6
+ Proxy.new(actor, self, &block)
7
+ end
8
+
9
+ def add(actions, subjects, behavior, &block)
10
+ actions = [actions] unless actions.is_a? Array
11
+ subjects = [subjects] unless subjects.is_a? Array
12
+ subjects.each do |subject|
13
+ actions.each do |action|
14
+ (all[find_subject_class(subject)] ||= {})[action.to_s] = block_given? ? block : behavior
15
+ end
16
+ end
17
+ end
18
+
19
+ def can?(action, subject)
20
+ if actions = all[find_subject_class(subject)]
21
+ if behavior = actions[action.to_s]
22
+ if behavior.is_a? Proc
23
+ @actor.instance_exec subject, &behavior
24
+ else
25
+ behavior
26
+ end
27
+ else
28
+ false
29
+ end
30
+ else
31
+ false
32
+ end
33
+ end
34
+
35
+ def cannot?(*args)
36
+ !can?(*args)
37
+ end
38
+
39
+ protected
40
+
41
+ def all
42
+ @all ||= {}
43
+ end
44
+
45
+ def find_subject_class(subject)
46
+ if subject.is_a? Class
47
+ subject.name
48
+ else
49
+ subject.class.name
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,3 @@
1
+ module Abilities
2
+ class AccessDenied < StandardError; end
3
+ end
@@ -0,0 +1,23 @@
1
+ module Abilities
2
+ class Proxy
3
+
4
+ def initialize(actor, definitions, &block)
5
+ @actor = actor
6
+ @definitions = definitions
7
+ instance_eval &block
8
+ end
9
+
10
+ def can(actions, subjects, &block)
11
+ @definitions.add actions, subjects, true, &block
12
+ end
13
+
14
+ def cannot(actions, subjects, &block)
15
+ @definitions.add actions, subjects, false, &block
16
+ end
17
+
18
+ def method_missing(name, *args, &block)
19
+ @actor.send name, *args, &block
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ module Abilities
2
+ class Railtie < Rails::Railtie
3
+
4
+ initializer 'abilites' do
5
+ User rescue {}
6
+ if defined? User
7
+ User.send :include, Abilities::Concern
8
+ end
9
+ ::ActionView::Base.send :include, Abilities::ActionView::Base
10
+ ::ActionController::Base.send :include, Abilities::ActionController::Base
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ module Abilities
2
+
3
+ VERSION = '0.0.1'
4
+
5
+ end
@@ -0,0 +1,13 @@
1
+ require 'rails/generators'
2
+
3
+ module Abilities
4
+ class InstallGenerator < Rails::Generators::Base
5
+
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ def create_capable_concern
9
+ copy_file 'abilities.rb', 'config/initializers/abilities.rb'
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,2 @@
1
+ Abilities.define do
2
+ end
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+
3
+ class ChangesTest < ActiveSupport::TestCase
4
+
5
+ test "record changes" do
6
+ user = User.new
7
+ assert user.cannot?(:destroy, Post)
8
+ user.admin = true
9
+ assert user.can?(:destroy, Post)
10
+ end
11
+
12
+ end
@@ -0,0 +1,52 @@
1
+ require 'test_helper'
2
+
3
+ class CheckingTest < ActiveSupport::TestCase
4
+
5
+ test "can definition with model" do
6
+ assert user.can?(:create, Post)
7
+ assert !user.cannot?(:create, Post)
8
+ end
9
+
10
+ test "can definition with instance" do
11
+ assert user.can?(:create, post)
12
+ assert !user.cannot?(:create, post)
13
+ end
14
+
15
+ test "cannot definition" do
16
+ assert user.cannot?('read', post)
17
+ assert !user.can?('read', post)
18
+ end
19
+
20
+ test "ability conditions" do
21
+ assert admin_user.can?(:destroy, post)
22
+ assert user.cannot?(:destroy, post)
23
+ end
24
+
25
+ test "ability block" do
26
+ assert user.can?(:update, post_with_user)
27
+ end
28
+
29
+ test "undefined definition" do
30
+ assert user.cannot?(:other, post)
31
+ assert user.cannot?(:other, post)
32
+ end
33
+
34
+ private
35
+
36
+ def post_with_user
37
+ @post_with_user ||= Post.new(user: user)
38
+ end
39
+
40
+ def post
41
+ @post ||= Post.new
42
+ end
43
+
44
+ def user
45
+ @user ||= User.new
46
+ end
47
+
48
+ def admin_user
49
+ @admin_user ||= User.new(admin: true)
50
+ end
51
+
52
+ end
@@ -0,0 +1,38 @@
1
+ require 'test_helper'
2
+
3
+ class ControllerTest < ActiveSupport::TestCase
4
+
5
+ test "can helper" do
6
+ assert controller.send(:can?, :create, post)
7
+ end
8
+
9
+ test "cannot helper" do
10
+ assert controller.send(:cannot?, :read, post)
11
+ end
12
+
13
+ test "authorize helper" do
14
+ assert_nothing_raised do
15
+ controller.send :authorize!, :create, post
16
+ end
17
+ assert_raises Abilities::AccessDenied do
18
+ controller.send :authorize!, :read, post
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def controller
25
+ @controller ||= ActionController::Base.new.tap do |controller|
26
+ controller.class_eval do
27
+ define_method :current_user do
28
+ @user ||= User.new
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def post
35
+ @post ||= Post.new
36
+ end
37
+
38
+ end