aclatraz 0.1.3 → 0.1.4
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.
- 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
|