canable 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +24 -0
- data/Gemfile +9 -0
- data/README.rdoc +23 -1
- data/Rakefile +2 -34
- data/canable.gemspec +19 -0
- data/lib/canable.rb +1 -3
- data/lib/canable/version.rb +3 -0
- data/specs.watchr +2 -21
- data/test/helper.rb +2 -20
- data/test/test_cans.rb +1 -1
- data/test/test_enforcers.rb +8 -3
- metadata +15 -70
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.rdoc
CHANGED
@@ -43,7 +43,7 @@ Lets say an article can be viewed and created by anyone, but only updated or des
|
|
43
43
|
Lets look at some sample code now:
|
44
44
|
|
45
45
|
john = User.create(:name => 'John')
|
46
|
-
steve = User.create(:name
|
46
|
+
steve = User.create(:name => 'Steve')
|
47
47
|
|
48
48
|
ruby = Article.new(:title => 'Ruby')
|
49
49
|
john.can_create?(ruby) # true
|
@@ -103,6 +103,28 @@ You can add your own actions like this:
|
|
103
103
|
|
104
104
|
The first parameter is the can method (ie: can_publish?) and the second is the able method (ie: publishable_by?).
|
105
105
|
|
106
|
+
Ables can also be added as class methods. For example, to restrict access to an index action:
|
107
|
+
|
108
|
+
Canable.add(:index, :indexable)
|
109
|
+
|
110
|
+
Then enforce by passing the class instead of the instance:
|
111
|
+
|
112
|
+
class ArticlesController < ApplicationController
|
113
|
+
def index
|
114
|
+
@articles = Article.all
|
115
|
+
enforce_index_permission(Article)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
Then in the article model, add the able check as a class method:
|
120
|
+
|
121
|
+
class Article
|
122
|
+
...
|
123
|
+
def self.indexable_by?(user)
|
124
|
+
!user.nil?
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
106
128
|
== Review
|
107
129
|
|
108
130
|
So, lets review: cans go on user model, ables go on everything, you override ables in each model where you want to enforce permissions, and enforcers go after each time you find or initialize an object in a controller. Bing, bang, boom.
|
data/Rakefile
CHANGED
@@ -1,27 +1,5 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
require File.dirname(__FILE__) + '/lib/canable'
|
5
|
-
|
6
|
-
begin
|
7
|
-
require 'jeweler'
|
8
|
-
Jeweler::Tasks.new do |gem|
|
9
|
-
gem.name = "canable"
|
10
|
-
gem.summary = %Q{Simple permissions that I have used on my last several projects so I figured it was time to abstract and wrap up into something more easily reusable.}
|
11
|
-
gem.description = %Q{Simple permissions that I have used on my last several projects so I figured it was time to abstract and wrap up into something more easily reusable.}
|
12
|
-
gem.email = "nunemaker@gmail.com"
|
13
|
-
gem.homepage = "http://github.com/jnunemaker/canable"
|
14
|
-
gem.authors = ["John Nunemaker"]
|
15
|
-
gem.version = Canable::Version
|
16
|
-
gem.add_development_dependency "shoulda", "~> 2.10.2"
|
17
|
-
gem.add_development_dependency "mocha", "~> 0.9.8"
|
18
|
-
gem.add_development_dependency "mongo_mapper"
|
19
|
-
gem.add_development_dependency "yard", ">= 0"
|
20
|
-
end
|
21
|
-
Jeweler::GemcutterTasks.new
|
22
|
-
rescue LoadError
|
23
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
24
|
-
end
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
25
3
|
|
26
4
|
require 'rake/testtask'
|
27
5
|
Rake::TestTask.new(:test) do |test|
|
@@ -31,14 +9,4 @@ Rake::TestTask.new(:test) do |test|
|
|
31
9
|
test.verbose = true
|
32
10
|
end
|
33
11
|
|
34
|
-
task :test => :check_dependencies
|
35
12
|
task :default => :test
|
36
|
-
|
37
|
-
begin
|
38
|
-
require 'yard'
|
39
|
-
YARD::Rake::YardocTask.new
|
40
|
-
rescue LoadError
|
41
|
-
task :yardoc do
|
42
|
-
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
43
|
-
end
|
44
|
-
end
|
data/canable.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "canable/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "canable"
|
7
|
+
s.version = Canable::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["John Nunemaker"]
|
10
|
+
s.email = ["nunemaker@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/jnunemaker/canable"
|
12
|
+
s.summary = %Q{Simple permissions that I have used on my last several projects so I figured it was time to abstract and wrap up into something more easily reusable.}
|
13
|
+
s.description = %Q{Simple permissions that I have used on my last several projects so I figured it was time to abstract and wrap up into something more easily reusable.}
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
end
|
data/lib/canable.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
module Canable
|
2
|
-
Version = '0.2.0'
|
3
|
-
|
4
2
|
# Module that holds all the can_action? methods.
|
5
3
|
module Cans; end
|
6
4
|
|
@@ -67,7 +65,7 @@ module Canable
|
|
67
65
|
def self.add_enforcer_method(can)
|
68
66
|
Enforcers.module_eval <<-EOM
|
69
67
|
def can_#{can}?(resource)
|
70
|
-
current_user.can_#{can}?(resource)
|
68
|
+
current_user && current_user.can_#{can}?(resource)
|
71
69
|
end
|
72
70
|
|
73
71
|
def enforce_#{can}_permission(resource, message="")
|
data/specs.watchr
CHANGED
@@ -1,27 +1,7 @@
|
|
1
|
-
def growl(title, msg, img)
|
2
|
-
%x{growlnotify -m #{ msg.inspect} -t #{title.inspect} --image ~/.watchr/#{img}.png}
|
3
|
-
end
|
4
|
-
|
5
|
-
def form_growl_message(str)
|
6
|
-
results = str.split("\n").last
|
7
|
-
if results =~ /[1-9]\s(failure|error)s?/
|
8
|
-
growl "Test Results", "#{results}", "fail"
|
9
|
-
elsif results != ""
|
10
|
-
growl "Test Results", "#{results}", "pass"
|
11
|
-
end
|
12
|
-
end
|
13
1
|
|
14
2
|
def run(cmd)
|
15
3
|
puts(cmd)
|
16
|
-
|
17
|
-
IO.popen(cmd) do |com|
|
18
|
-
com.each_char do |c|
|
19
|
-
print c
|
20
|
-
output << c
|
21
|
-
$stdout.flush
|
22
|
-
end
|
23
|
-
end
|
24
|
-
form_growl_message output
|
4
|
+
system(cmd)
|
25
5
|
end
|
26
6
|
|
27
7
|
def run_test_file(file)
|
@@ -38,6 +18,7 @@ watch('lib/.*') { |m| system('clear'); run_all_tests }
|
|
38
18
|
|
39
19
|
# Ctrl-\
|
40
20
|
Signal.trap('QUIT') do
|
21
|
+
system('clear')
|
41
22
|
puts " --- Running all tests ---\n\n"
|
42
23
|
run_all_tests
|
43
24
|
end
|
data/test/helper.rb
CHANGED
@@ -1,12 +1,7 @@
|
|
1
1
|
require 'test/unit'
|
2
|
-
|
3
|
-
gem 'mocha', '~> 0.9.8'
|
4
|
-
gem 'shoulda', '~> 2.10.2'
|
5
|
-
gem 'mongo_mapper'
|
6
|
-
|
7
2
|
require 'mocha'
|
8
3
|
require 'shoulda'
|
9
|
-
require '
|
4
|
+
require 'active_support/all'
|
10
5
|
|
11
6
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
12
7
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
@@ -14,21 +9,8 @@ require 'canable'
|
|
14
9
|
|
15
10
|
class Test::Unit::TestCase
|
16
11
|
def Doc(name=nil, &block)
|
17
|
-
klass =
|
18
|
-
include MongoMapper::Document
|
19
|
-
set_collection_name "test#{rand(20)}"
|
20
|
-
|
21
|
-
if name
|
22
|
-
class_eval "def self.name; '#{name}' end"
|
23
|
-
class_eval "def self.to_s; '#{name}' end"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
12
|
+
klass = Struct.new(:name)
|
27
13
|
klass.class_eval(&block) if block_given?
|
28
|
-
klass.collection.remove
|
29
14
|
klass
|
30
15
|
end
|
31
16
|
end
|
32
|
-
|
33
|
-
MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017)
|
34
|
-
MongoMapper.database = 'test'
|
data/test/test_cans.rb
CHANGED
data/test/test_enforcers.rb
CHANGED
@@ -9,7 +9,7 @@ class EnforcersTest < Test::Unit::TestCase
|
|
9
9
|
|
10
10
|
# Overriding example
|
11
11
|
def can_update?(resource)
|
12
|
-
return false if current_user.
|
12
|
+
return false if current_user && current_user.banned?
|
13
13
|
super
|
14
14
|
end
|
15
15
|
|
@@ -42,9 +42,14 @@ class EnforcersTest < Test::Unit::TestCase
|
|
42
42
|
@user.expects(:can_view?).with(@article).returns(false)
|
43
43
|
assert_raises(Canable::Transgression) { @controller.show }
|
44
44
|
end
|
45
|
-
|
46
|
-
should "
|
45
|
+
|
46
|
+
should "raise error whenever current_user nil" do
|
47
47
|
@controller.current_user = nil
|
48
|
+
assert_raises(Canable::Transgression) { @controller.show }
|
49
|
+
end
|
50
|
+
|
51
|
+
should "be able to override can_xx? method" do
|
52
|
+
@user.expects(:banned?).returns(true)
|
48
53
|
assert_raises(Canable::Transgression) { @controller.update }
|
49
54
|
end
|
50
55
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: canable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- John Nunemaker
|
@@ -15,83 +15,28 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
19
|
-
dependencies:
|
20
|
-
|
21
|
-
name: shoulda
|
22
|
-
prerelease: false
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
-
none: false
|
25
|
-
requirements:
|
26
|
-
- - ~>
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
hash: 35
|
29
|
-
segments:
|
30
|
-
- 2
|
31
|
-
- 10
|
32
|
-
- 2
|
33
|
-
version: 2.10.2
|
34
|
-
type: :development
|
35
|
-
version_requirements: *id001
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: mocha
|
38
|
-
prerelease: false
|
39
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
-
none: false
|
41
|
-
requirements:
|
42
|
-
- - ~>
|
43
|
-
- !ruby/object:Gem::Version
|
44
|
-
hash: 43
|
45
|
-
segments:
|
46
|
-
- 0
|
47
|
-
- 9
|
48
|
-
- 8
|
49
|
-
version: 0.9.8
|
50
|
-
type: :development
|
51
|
-
version_requirements: *id002
|
52
|
-
- !ruby/object:Gem::Dependency
|
53
|
-
name: mongo_mapper
|
54
|
-
prerelease: false
|
55
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
-
none: false
|
57
|
-
requirements:
|
58
|
-
- - ">="
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
hash: 3
|
61
|
-
segments:
|
62
|
-
- 0
|
63
|
-
version: "0"
|
64
|
-
type: :development
|
65
|
-
version_requirements: *id003
|
66
|
-
- !ruby/object:Gem::Dependency
|
67
|
-
name: yard
|
68
|
-
prerelease: false
|
69
|
-
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
-
none: false
|
71
|
-
requirements:
|
72
|
-
- - ">="
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
hash: 3
|
75
|
-
segments:
|
76
|
-
- 0
|
77
|
-
version: "0"
|
78
|
-
type: :development
|
79
|
-
version_requirements: *id004
|
18
|
+
date: 2011-09-07 00:00:00 Z
|
19
|
+
dependencies: []
|
20
|
+
|
80
21
|
description: Simple permissions that I have used on my last several projects so I figured it was time to abstract and wrap up into something more easily reusable.
|
81
|
-
email:
|
22
|
+
email:
|
23
|
+
- nunemaker@gmail.com
|
82
24
|
executables: []
|
83
25
|
|
84
26
|
extensions: []
|
85
27
|
|
86
|
-
extra_rdoc_files:
|
87
|
-
|
88
|
-
- README.rdoc
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
89
30
|
files:
|
90
31
|
- .document
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
91
34
|
- LICENSE
|
92
35
|
- README.rdoc
|
93
36
|
- Rakefile
|
37
|
+
- canable.gemspec
|
94
38
|
- lib/canable.rb
|
39
|
+
- lib/canable/version.rb
|
95
40
|
- specs.watchr
|
96
41
|
- test/helper.rb
|
97
42
|
- test/test_ables.rb
|
@@ -127,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
72
|
requirements: []
|
128
73
|
|
129
74
|
rubyforge_project:
|
130
|
-
rubygems_version: 1.
|
75
|
+
rubygems_version: 1.8.9
|
131
76
|
signing_key:
|
132
77
|
specification_version: 3
|
133
78
|
summary: Simple permissions that I have used on my last several projects so I figured it was time to abstract and wrap up into something more easily reusable.
|