aclatraz 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -11
- data/CHANGELOG.rdoc +6 -0
- data/Rakefile +43 -41
- data/aclatraz.gemspec +20 -91
- data/lib/aclatraz.rb +7 -6
- data/lib/aclatraz/acl.rb +6 -8
- data/lib/aclatraz/store.rb +1 -0
- data/lib/aclatraz/store/cassandra.rb +2 -3
- data/lib/aclatraz/store/mongo.rb +56 -0
- data/lib/aclatraz/store/redis.rb +2 -3
- data/lib/aclatraz/store/riak.rb +2 -3
- data/spec/aclatraz/acl_spec.rb +34 -30
- data/spec/aclatraz/guard_spec.rb +136 -147
- data/spec/aclatraz/stores_spec.rb +54 -50
- data/spec/aclatraz/suspect_spec.rb +72 -70
- data/spec/aclatraz_spec.rb +14 -9
- data/spec/alcatraz_bm.rb +1 -1
- data/spec/spec_helper.rb +20 -0
- metadata +20 -26
- data/.document +0 -5
- data/VERSION +0 -1
data/.gitignore
CHANGED
data/CHANGELOG.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -1,69 +1,71 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
begin
|
5
|
-
require 'jeweler'
|
6
|
-
Jeweler::Tasks.new do |gem|
|
7
|
-
gem.name = "aclatraz"
|
8
|
-
gem.email = "kriss.kowalik@gmail.com"
|
9
|
-
gem.homepage = "http://github.com/nu7hatch/aclatraz"
|
10
|
-
gem.authors = ["Kriss 'nu7hatch' Kowalik"]
|
11
|
-
gem.summary = %Q{Flexible access control that doesn't sucks!}
|
12
|
-
gem.description = <<-DESCR
|
13
|
-
Extremaly fast, flexible and intuitive access control mechanism,
|
14
|
-
powered by fast key value stores like Redis.
|
15
|
-
DESCR
|
16
|
-
gem.add_dependency "dictionary", "~> 1.0"
|
17
|
-
gem.add_development_dependency "rspec", "~> 2.0"
|
18
|
-
gem.add_development_dependency "mocha", "~> 0.9"
|
19
|
-
gem.add_development_dependency "redis", "~> 2.0"
|
20
|
-
gem.add_development_dependency "riak-client", "~> 0.8"
|
21
|
-
gem.add_development_dependency "cassandra", "~> 0.8"
|
22
|
-
end
|
23
|
-
Jeweler::GemcutterTasks.new
|
24
|
-
rescue LoadError
|
25
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
26
|
-
end
|
27
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
$:.unshift(File.expand_path('../lib', __FILE__))
|
3
|
+
require 'aclatraz/version'
|
28
4
|
require 'rspec/core/rake_task'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
|
29
7
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
30
8
|
t.pattern = 'spec/**/*_spec.rb'
|
31
|
-
t.rspec_opts = %q[
|
9
|
+
t.rspec_opts = %q[-c -b]
|
32
10
|
end
|
33
11
|
|
34
12
|
RSpec::Core::RakeTask.new(:rcov) do |t|
|
35
13
|
t.rcov = true
|
36
|
-
t.rspec_opts = %q[
|
37
|
-
t.rcov_opts = %q[
|
14
|
+
t.rspec_opts = %q[-c -b]
|
15
|
+
t.rcov_opts = %q[-T -x "spec"]
|
38
16
|
end
|
39
17
|
|
40
|
-
task :spec => :check_dependencies
|
41
|
-
task :default => :spec
|
42
|
-
|
43
|
-
require 'rake/rdoctask'
|
44
18
|
Rake::RDocTask.new do |rdoc|
|
45
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
19
|
rdoc.rdoc_dir = 'rdoc'
|
47
|
-
rdoc.title = "ACLatraz #{version}"
|
20
|
+
rdoc.title = "ACLatraz #{Aclatraz.version}"
|
48
21
|
rdoc.rdoc_files.include('README*')
|
49
22
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
23
|
end
|
51
24
|
|
25
|
+
task :default => :spec
|
26
|
+
|
27
|
+
desc "Build current version as a rubygem"
|
28
|
+
task :build do
|
29
|
+
`gem build aclatraz.gemspec`
|
30
|
+
`mv aclatraz-*.gem pkg/`
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Relase current version to rubygems.org"
|
34
|
+
task :release => :build do
|
35
|
+
`git tag -am "Version bump to #{Aclatraz.version}" v#{Aclatraz.version}`
|
36
|
+
`git push origin master`
|
37
|
+
`git push origin master --tags`
|
38
|
+
`gem push pkg/aclatraz-#{Aclatraz.version}.gem`
|
39
|
+
end
|
40
|
+
|
52
41
|
namespace :benchmark do
|
53
|
-
|
42
|
+
require 'aclatraz'
|
54
43
|
require 'benchmark'
|
55
|
-
require "aclatraz"
|
56
44
|
|
45
|
+
benchmarks = File.expand_path("../spec/alcatraz_bm.rb", __FILE__)
|
46
|
+
|
47
|
+
desc "Redis store benchmarks"
|
57
48
|
task :redis do
|
58
49
|
Aclatraz.init(:redis)
|
59
|
-
|
50
|
+
load benchmarks
|
60
51
|
end
|
52
|
+
|
53
|
+
desc "Cassandra store benchmarks"
|
61
54
|
task :cassandra do
|
62
55
|
Aclatraz.init(:cassandra, "Super1", "Keyspace1")
|
63
|
-
|
56
|
+
load benchmarks
|
64
57
|
end
|
58
|
+
|
59
|
+
desc "Riak store benchmarks"
|
65
60
|
task :riak do
|
66
61
|
Aclatraz.init(:riak, "roles")
|
67
|
-
|
62
|
+
load benchmarks
|
63
|
+
end
|
64
|
+
|
65
|
+
desc "MongoDB store benchmarks"
|
66
|
+
task :mongo do
|
67
|
+
require 'mongo'
|
68
|
+
Aclatraz.init(:mongo, "roles", Mongo::Connection.new.db("aclatraz_test"))
|
69
|
+
load benchmarks
|
68
70
|
end
|
69
71
|
end
|
data/aclatraz.gemspec
CHANGED
@@ -1,95 +1,24 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
# -*- encoding: utf-8 -*-
|
1
|
+
# -*- ruby -*-
|
2
|
+
$:.unshift(File.expand_path('../lib', __FILE__))
|
3
|
+
require 'aclatraz/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |s|
|
7
|
-
s.name
|
8
|
-
s.version
|
6
|
+
s.name = 'aclatraz'
|
7
|
+
s.version = Aclatraz.version
|
8
|
+
s.homepage = 'http://github.com/nu7hatch/aclatraz'
|
9
|
+
s.email = ['chris@nu7hat.ch']
|
10
|
+
s.authors = ['Chris Kowalik']
|
11
|
+
s.summary = %q{Flexible access control mechanism!}
|
12
|
+
s.description = %q{Extremaly fast, flexible and intuitive access control mechanism, powered by fast key value stores like Redis.}
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
15
|
+
s.require_paths = %w[lib]
|
16
|
+
s.extra_rdoc_files = %w[LICENSE README.rdoc CHANGELOG.rdoc TODO.rdoc]
|
9
17
|
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.
|
13
|
-
s.
|
14
|
-
|
15
|
-
|
16
|
-
s.email = %q{kriss.kowalik@gmail.com}
|
17
|
-
s.extra_rdoc_files = [
|
18
|
-
"LICENSE",
|
19
|
-
"README.rdoc"
|
20
|
-
]
|
21
|
-
s.files = [
|
22
|
-
".document",
|
23
|
-
".gitignore",
|
24
|
-
"CHANGELOG.rdoc",
|
25
|
-
"LICENSE",
|
26
|
-
"README.rdoc",
|
27
|
-
"Rakefile",
|
28
|
-
"TODO.rdoc",
|
29
|
-
"VERSION",
|
30
|
-
"aclatraz.gemspec",
|
31
|
-
"examples/dinner.rb",
|
32
|
-
"lib/aclatraz.rb",
|
33
|
-
"lib/aclatraz/acl.rb",
|
34
|
-
"lib/aclatraz/guard.rb",
|
35
|
-
"lib/aclatraz/helpers.rb",
|
36
|
-
"lib/aclatraz/store.rb",
|
37
|
-
"lib/aclatraz/store/cassandra.rb",
|
38
|
-
"lib/aclatraz/store/redis.rb",
|
39
|
-
"lib/aclatraz/store/riak.rb",
|
40
|
-
"lib/aclatraz/suspect.rb",
|
41
|
-
"spec/aclatraz/acl_spec.rb",
|
42
|
-
"spec/aclatraz/guard_spec.rb",
|
43
|
-
"spec/aclatraz/helpers_spec.rb",
|
44
|
-
"spec/aclatraz/stores_spec.rb",
|
45
|
-
"spec/aclatraz/suspect_spec.rb",
|
46
|
-
"spec/aclatraz_spec.rb",
|
47
|
-
"spec/alcatraz_bm.rb",
|
48
|
-
"spec/spec_helper.rb"
|
49
|
-
]
|
50
|
-
s.homepage = %q{http://github.com/nu7hatch/aclatraz}
|
51
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
52
|
-
s.require_paths = ["lib"]
|
53
|
-
s.rubygems_version = %q{1.3.7}
|
54
|
-
s.summary = %q{Flexible access control that doesn't sucks!}
|
55
|
-
s.test_files = [
|
56
|
-
"spec/alcatraz_bm.rb",
|
57
|
-
"spec/spec_helper.rb",
|
58
|
-
"spec/aclatraz/guard_spec.rb",
|
59
|
-
"spec/aclatraz/helpers_spec.rb",
|
60
|
-
"spec/aclatraz/acl_spec.rb",
|
61
|
-
"spec/aclatraz/stores_spec.rb",
|
62
|
-
"spec/aclatraz/suspect_spec.rb",
|
63
|
-
"spec/aclatraz_spec.rb",
|
64
|
-
"examples/dinner.rb"
|
65
|
-
]
|
66
|
-
|
67
|
-
if s.respond_to? :specification_version then
|
68
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
69
|
-
s.specification_version = 3
|
70
|
-
|
71
|
-
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
72
|
-
s.add_runtime_dependency(%q<dictionary>, ["~> 1.0"])
|
73
|
-
s.add_development_dependency(%q<rspec>, ["~> 2.0"])
|
74
|
-
s.add_development_dependency(%q<mocha>, ["~> 0.9"])
|
75
|
-
s.add_development_dependency(%q<redis>, ["~> 2.0"])
|
76
|
-
s.add_development_dependency(%q<riak-client>, ["~> 0.8"])
|
77
|
-
s.add_development_dependency(%q<cassandra>, ["~> 0.8"])
|
78
|
-
else
|
79
|
-
s.add_dependency(%q<dictionary>, ["~> 1.0"])
|
80
|
-
s.add_dependency(%q<rspec>, ["~> 2.0"])
|
81
|
-
s.add_dependency(%q<mocha>, ["~> 0.9"])
|
82
|
-
s.add_dependency(%q<redis>, ["~> 2.0"])
|
83
|
-
s.add_dependency(%q<riak-client>, ["~> 0.8"])
|
84
|
-
s.add_dependency(%q<cassandra>, ["~> 0.8"])
|
85
|
-
end
|
86
|
-
else
|
87
|
-
s.add_dependency(%q<dictionary>, ["~> 1.0"])
|
88
|
-
s.add_dependency(%q<rspec>, ["~> 2.0"])
|
89
|
-
s.add_dependency(%q<mocha>, ["~> 0.9"])
|
90
|
-
s.add_dependency(%q<redis>, ["~> 2.0"])
|
91
|
-
s.add_dependency(%q<riak-client>, ["~> 0.8"])
|
92
|
-
s.add_dependency(%q<cassandra>, ["~> 0.8"])
|
93
|
-
end
|
18
|
+
s.add_runtime_dependency 'dictionary', ['~> 1.0']
|
19
|
+
s.add_development_dependency 'rspec', ["~> 2.0"]
|
20
|
+
s.add_development_dependency 'mocha', [">= 0.9"]
|
21
|
+
s.add_development_dependency 'redis', [">= 2.0"]
|
22
|
+
s.add_development_dependency 'riak-client', [">= 0.8"]
|
23
|
+
s.add_development_dependency 'cassandra', [">= 0.8"]
|
94
24
|
end
|
95
|
-
|
data/lib/aclatraz.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'dictionary'
|
2
2
|
|
3
|
-
require 'aclatraz/helpers'
|
4
|
-
require 'aclatraz/store'
|
5
|
-
require 'aclatraz/acl'
|
6
|
-
require 'aclatraz/guard'
|
7
|
-
require 'aclatraz/suspect'
|
8
|
-
|
9
3
|
module Aclatraz
|
4
|
+
require 'aclatraz/helpers'
|
5
|
+
require 'aclatraz/store'
|
6
|
+
require 'aclatraz/acl'
|
7
|
+
require 'aclatraz/guard'
|
8
|
+
require 'aclatraz/suspect'
|
9
|
+
require 'aclatraz/version'
|
10
|
+
|
10
11
|
# Raised when suspect don't have permission to execute action
|
11
12
|
class AccessDenied < Exception; end
|
12
13
|
|
data/lib/aclatraz/acl.rb
CHANGED
@@ -4,9 +4,9 @@ module Aclatraz
|
|
4
4
|
# All permissions defined in this action.
|
5
5
|
attr_reader :permissions
|
6
6
|
|
7
|
-
def initialize(parent, &block)
|
7
|
+
def initialize(parent, &block)
|
8
8
|
@parent = parent
|
9
|
-
@permissions = Dictionary.new
|
9
|
+
@permissions = Dictionary.new {|h,k| h[k] = false}.merge(parent.permissions)
|
10
10
|
instance_eval(&block) if block_given?
|
11
11
|
end
|
12
12
|
|
@@ -54,9 +54,7 @@ module Aclatraz
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def clone(parent) # :nodoc:
|
57
|
-
|
58
|
-
cloned.instance_variable_set("@permissions", Hash.new(permissions))
|
59
|
-
cloned
|
57
|
+
self.class.new(parent)
|
60
58
|
end
|
61
59
|
end # Action
|
62
60
|
|
@@ -66,7 +64,7 @@ module Aclatraz
|
|
66
64
|
# Current suspected object.
|
67
65
|
attr_accessor :suspect
|
68
66
|
|
69
|
-
def initialize(suspect, &block)
|
67
|
+
def initialize(suspect, &block)
|
70
68
|
@actions = {}
|
71
69
|
@suspect = suspect
|
72
70
|
evaluate(&block) if block_given?
|
@@ -87,7 +85,7 @@ module Aclatraz
|
|
87
85
|
|
88
86
|
# List of permissions defined in default action.
|
89
87
|
def permissions
|
90
|
-
@actions[:_] ? @actions[:_].permissions : Dictionary.new
|
88
|
+
@actions[:_] ? @actions[:_].permissions : Dictionary.new {|h,k| h[k] = false}
|
91
89
|
end
|
92
90
|
|
93
91
|
# Syntactic sugar for actions <tt>actions[action]</tt>.
|
@@ -109,7 +107,7 @@ module Aclatraz
|
|
109
107
|
# end
|
110
108
|
# end
|
111
109
|
def on(action, &block)
|
112
|
-
raise ArgumentError, "No block given" unless block_given?
|
110
|
+
raise ArgumentError, "No block given!" unless block_given?
|
113
111
|
if @actions.key?(action)
|
114
112
|
@actions[action].instance_eval(&block)
|
115
113
|
else
|
data/lib/aclatraz/store.rb
CHANGED
@@ -3,6 +3,7 @@ module Aclatraz
|
|
3
3
|
autoload :Redis, 'aclatraz/store/redis'
|
4
4
|
autoload :Riak, 'aclatraz/store/riak'
|
5
5
|
autoload :Cassandra, 'aclatraz/store/cassandra'
|
6
|
+
autoload :Mongo, 'aclatraz/store/mongo'
|
6
7
|
#autoload :Memcached, 'aclatraz/store/memcached'
|
7
8
|
#autoload :TokyoCabinet, 'aclatraz/store/tokyocabinet'
|
8
9
|
end # Store
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'cassandra'
|
2
|
+
|
1
3
|
module Aclatraz
|
2
4
|
module Store
|
3
5
|
# List of global roles are stored in `roles => all` key. Each suspect has its
|
@@ -16,9 +18,6 @@ module Aclatraz
|
|
16
18
|
SUSPECT_ROLES_KEY = "suspect.%s"
|
17
19
|
|
18
20
|
def initialize(*args)
|
19
|
-
require 'cassandra' rescue raise LoadError, \
|
20
|
-
"You must install the `casssandra` gem to use Cassandra store"
|
21
|
-
|
22
21
|
@family = args.shift
|
23
22
|
@backend = if args.first.respond_to?(:keyspace)
|
24
23
|
args.first
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
|
3
|
+
module Aclatraz
|
4
|
+
module Store
|
5
|
+
# For MongoDB, each role is stored in separate row:
|
6
|
+
#
|
7
|
+
# {"roles" => [
|
8
|
+
# {"suspect" => 1, "role" => "admin" },
|
9
|
+
# {"suspect" => 2, "role" => "manager/ClassName" },
|
10
|
+
# {"suspect" => 3, "role" => "owner/ClassName/1" }
|
11
|
+
# ]}
|
12
|
+
class Mongo
|
13
|
+
include Aclatraz::Helpers
|
14
|
+
|
15
|
+
ROLE_KEY = "role"
|
16
|
+
SUSPECT_KEY = "suspect"
|
17
|
+
|
18
|
+
def initialize(collection, mongo)
|
19
|
+
@backend = mongo
|
20
|
+
@collection = collection
|
21
|
+
end
|
22
|
+
|
23
|
+
def set(role, suspect, object=nil)
|
24
|
+
@backend[@collection].insert(make_doc(role, suspect, object))
|
25
|
+
end
|
26
|
+
|
27
|
+
def roles(suspect=nil)
|
28
|
+
if suspect
|
29
|
+
@backend[@collection].find(SUSPECT_KEY => suspect_id(suspect)).map {|row| row[ROLE_KEY] }
|
30
|
+
else
|
31
|
+
@backend[@collection].find.map {|row| row[ROLE_KEY] }
|
32
|
+
end.compact.uniq
|
33
|
+
end
|
34
|
+
|
35
|
+
def check(role, suspect, object=nil)
|
36
|
+
@backend[@collection].find(make_doc(role, suspect, object)).map.empty? == false or begin
|
37
|
+
object && !object.is_a?(Class) ? check(role, suspect, object.class) : false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete(role, suspect, object=nil)
|
42
|
+
@backend[@collection].remove(make_doc(role, suspect, object))
|
43
|
+
end
|
44
|
+
|
45
|
+
def clear
|
46
|
+
@backend[@collection].remove
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def make_doc(role, suspect, object)
|
52
|
+
{ SUSPECT_KEY => suspect_id(suspect), ROLE_KEY => pack(role.to_s, object) }
|
53
|
+
end
|
54
|
+
end # Mongo
|
55
|
+
end # Store
|
56
|
+
end # Aclatraz
|
data/lib/aclatraz/store/redis.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
1
3
|
module Aclatraz
|
2
4
|
module Store
|
3
5
|
# List of global roles are stored in ROLES set. Each suspect has its
|
@@ -15,9 +17,6 @@ module Aclatraz
|
|
15
17
|
SUSPECT_ROLES_KEY = "suspect.%s.roles"
|
16
18
|
|
17
19
|
def initialize(*args)
|
18
|
-
require 'redis' rescue raise LoadError, \
|
19
|
-
"You must install the `redis` gem to use Redis store"
|
20
|
-
|
21
20
|
@backend = if args.first.respond_to?(:sadd)
|
22
21
|
args.first
|
23
22
|
else
|
data/lib/aclatraz/store/riak.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'riak'
|
2
|
+
|
1
3
|
module Aclatraz
|
2
4
|
module Store
|
3
5
|
# The most optimal way to store roles in riak database is pack everything
|
@@ -10,9 +12,6 @@ module Aclatraz
|
|
10
12
|
include Aclatraz::Helpers
|
11
13
|
|
12
14
|
def initialize(bucket_name, *args)
|
13
|
-
require "riak" rescue raise LoadError, \
|
14
|
-
"You must install the `riak-client` gem to use Riak store"
|
15
|
-
|
16
15
|
@backend = if args.first.respond_to?(:bucket)
|
17
16
|
args.first.bucket(bucket_name)
|
18
17
|
else
|
data/spec/aclatraz/acl_spec.rb
CHANGED
@@ -1,45 +1,49 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe "Aclatraz ACL" do
|
3
|
+
describe "Aclatraz ACL" do
|
4
|
+
subject { Aclatraz::ACL }
|
4
5
|
before(:all) { Aclatraz.init(:redis, "redis://localhost:6379/0") }
|
5
6
|
|
6
|
-
it "should properly
|
7
|
-
acl =
|
8
|
-
acl.suspect.should == :
|
7
|
+
it "should properly set suspect" do
|
8
|
+
acl = subject.new(:suspect) {}
|
9
|
+
acl.suspect.should == :suspect
|
9
10
|
end
|
10
11
|
|
11
12
|
it "should properly store flat access control lists" do
|
12
|
-
acl =
|
13
|
-
acl.actions[:_].allow :
|
14
|
-
acl.permissions[:
|
15
|
-
acl.actions[:_].deny :
|
16
|
-
acl.permissions[:
|
17
|
-
acl.actions[:_].allow :
|
18
|
-
acl.permissions[{:
|
13
|
+
acl = subject.new(:suspect) {}
|
14
|
+
acl.actions[:_].allow :admin
|
15
|
+
acl.permissions[:admin].should be_true
|
16
|
+
acl.actions[:_].deny :admin
|
17
|
+
acl.permissions[:admin].should be_false
|
18
|
+
acl.actions[:_].allow :owner_of => :book
|
19
|
+
acl.permissions[{:owner_of => :book}].should be_true
|
19
20
|
end
|
20
21
|
|
21
|
-
it "should allow for
|
22
|
-
acl =
|
23
|
-
allow :
|
24
|
-
on(:
|
25
|
-
on(:
|
26
|
-
on(:
|
22
|
+
it "should allow for grouping permissions in namespaces, which are inherit from main block" do
|
23
|
+
acl = subject.new(:suspect) do
|
24
|
+
allow :admin
|
25
|
+
on(:library) { allow :librarian }
|
26
|
+
on(:kitchen) { allow :cooker }
|
27
|
+
on(:kennel) { allow :dog }
|
27
28
|
end
|
28
29
|
|
29
|
-
acl.permissions[:
|
30
|
-
acl.permissions[:
|
31
|
-
acl.permissions[:
|
32
|
-
acl.permissions[:
|
33
|
-
|
34
|
-
acl[:
|
35
|
-
acl[:
|
36
|
-
acl[:
|
37
|
-
acl[:
|
38
|
-
|
39
|
-
acl[:
|
30
|
+
acl.permissions[:admin].should be_true
|
31
|
+
acl.permissions[:librarian].should be_false
|
32
|
+
acl.permissions[:cooker].should be_false
|
33
|
+
acl.permissions[:dog].should be_false
|
34
|
+
|
35
|
+
acl[:library].permissions[:librarian].should be_true
|
36
|
+
acl[:library].permissions[:cooker].should be_false
|
37
|
+
acl[:library].permissions[:dog].should be_false
|
38
|
+
acl[:library].permissions[:admin].should be_false
|
39
|
+
|
40
|
+
acl[:kitchen].permissions[:cooker].should be_true
|
41
|
+
acl[:kitchen].permissions[:librarian].should be_false
|
42
|
+
acl[:kitchen].permissions[:dog].should be_false
|
43
|
+
acl[:kitchen].permissions[:admin].should be_false
|
40
44
|
end
|
41
45
|
|
42
|
-
it "should raise
|
43
|
-
lambda {
|
46
|
+
it "should raise error when no block given" do
|
47
|
+
lambda { subject.new }.should raise_error(ArgumentError)
|
44
48
|
end
|
45
49
|
end
|