cando 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +79 -0
- data/LICENSE.txt +25 -0
- data/README.md +144 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/cando.gemspec +75 -0
- data/contrib/initial_schema.rb +39 -0
- data/lib/cando.rb +88 -0
- data/lib/models/capability.rb +14 -0
- data/lib/models/role.rb +27 -0
- data/lib/models/user.rb +40 -0
- data/lib/tasks/cando.rake +138 -0
- data/spec/cando_spec.rb +126 -0
- data/spec/spec_helper.rb +48 -0
- metadata +180 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
gem "sequel"
|
7
|
+
gem "rake"
|
8
|
+
|
9
|
+
# Add dependencies to develop your gem here.
|
10
|
+
# Include everything needed to run rake, tests, features, etc.
|
11
|
+
group :development do
|
12
|
+
gem "rspec", "~> 2.10.0"
|
13
|
+
gem "rdoc", "~> 3.12"
|
14
|
+
gem "bundler", "~> 1.0"
|
15
|
+
gem "jeweler", "~> 2.0.1"
|
16
|
+
gem "simplecov", ">= 0"
|
17
|
+
end
|
18
|
+
|
19
|
+
group :test do
|
20
|
+
gem "mysql"
|
21
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.3.6)
|
5
|
+
builder (3.2.2)
|
6
|
+
descendants_tracker (0.0.4)
|
7
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
8
|
+
diff-lcs (1.1.3)
|
9
|
+
docile (1.1.3)
|
10
|
+
faraday (0.9.0)
|
11
|
+
multipart-post (>= 1.2, < 3)
|
12
|
+
git (1.2.6)
|
13
|
+
github_api (0.11.3)
|
14
|
+
addressable (~> 2.3)
|
15
|
+
descendants_tracker (~> 0.0.1)
|
16
|
+
faraday (~> 0.8, < 0.10)
|
17
|
+
hashie (>= 1.2)
|
18
|
+
multi_json (>= 1.7.5, < 2.0)
|
19
|
+
nokogiri (~> 1.6.0)
|
20
|
+
oauth2
|
21
|
+
hashie (2.1.1)
|
22
|
+
highline (1.6.21)
|
23
|
+
jeweler (2.0.1)
|
24
|
+
builder
|
25
|
+
bundler (>= 1.0)
|
26
|
+
git (>= 1.2.5)
|
27
|
+
github_api
|
28
|
+
highline (>= 1.6.15)
|
29
|
+
nokogiri (>= 1.5.10)
|
30
|
+
rake
|
31
|
+
rdoc
|
32
|
+
json (1.8.1)
|
33
|
+
jwt (0.1.13)
|
34
|
+
multi_json (>= 1.5)
|
35
|
+
mini_portile (0.5.3)
|
36
|
+
multi_json (1.10.0)
|
37
|
+
multi_xml (0.5.5)
|
38
|
+
multipart-post (2.0.0)
|
39
|
+
mysql (2.9.1)
|
40
|
+
nokogiri (1.6.1)
|
41
|
+
mini_portile (~> 0.5.0)
|
42
|
+
oauth2 (0.9.3)
|
43
|
+
faraday (>= 0.8, < 0.10)
|
44
|
+
jwt (~> 0.1.8)
|
45
|
+
multi_json (~> 1.3)
|
46
|
+
multi_xml (~> 0.5)
|
47
|
+
rack (~> 1.2)
|
48
|
+
rack (1.5.2)
|
49
|
+
rake (10.3.1)
|
50
|
+
rdoc (3.12.2)
|
51
|
+
json (~> 1.4)
|
52
|
+
rspec (2.10.0)
|
53
|
+
rspec-core (~> 2.10.0)
|
54
|
+
rspec-expectations (~> 2.10.0)
|
55
|
+
rspec-mocks (~> 2.10.0)
|
56
|
+
rspec-core (2.10.1)
|
57
|
+
rspec-expectations (2.10.0)
|
58
|
+
diff-lcs (~> 1.1.3)
|
59
|
+
rspec-mocks (2.10.1)
|
60
|
+
sequel (4.10.0)
|
61
|
+
simplecov (0.8.2)
|
62
|
+
docile (~> 1.1.0)
|
63
|
+
multi_json
|
64
|
+
simplecov-html (~> 0.8.0)
|
65
|
+
simplecov-html (0.8.0)
|
66
|
+
thread_safe (0.3.3)
|
67
|
+
|
68
|
+
PLATFORMS
|
69
|
+
ruby
|
70
|
+
|
71
|
+
DEPENDENCIES
|
72
|
+
bundler (~> 1.0)
|
73
|
+
jeweler (~> 2.0.1)
|
74
|
+
mysql
|
75
|
+
rake
|
76
|
+
rdoc (~> 3.12)
|
77
|
+
rspec (~> 2.10.0)
|
78
|
+
sequel
|
79
|
+
simplecov
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2014 Daniel Bornkessel
|
2
|
+
|
3
|
+
The MIT License (MIT)
|
4
|
+
|
5
|
+
Copyright © 2013 SoundCloud Ltd., Internal Tools Team
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
9
|
+
in the Software without restriction, including without limitation the rights
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
12
|
+
furnished to do so, subject to the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
15
|
+
copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
23
|
+
SOFTWARE.
|
24
|
+
|
25
|
+
|
data/README.md
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
# CanDo [![Build Status](https://travis-ci.org/soundcloud/cando.svg?branch=master)](https://travis-ci.org/soundcloud/cando)
|
2
|
+
|
3
|
+
CanDo is a small gem to implement a simple user access system based on users, roles &
|
4
|
+
capabilites, where:
|
5
|
+
|
6
|
+
- each user can have 0, 1 or many roles
|
7
|
+
- each role can have 0, 1 or many capabilites
|
8
|
+
|
9
|
+
Users have capabilities by getting roles assigned (role == collection of
|
10
|
+
capabilities). Within the code, the `can` helper method can be used to test
|
11
|
+
whether a user has a certain capability or not (see below for a working code example).
|
12
|
+
|
13
|
+
## Dependencies
|
14
|
+
|
15
|
+
CanDo depends on the following software:
|
16
|
+
|
17
|
+
* [sequel](http://sequel.jeremyevans.net)
|
18
|
+
* [rake](https://github.com/jimweirich/rake)
|
19
|
+
|
20
|
+
|
21
|
+
## Installation and deployment
|
22
|
+
|
23
|
+
Download and install rake with the following.
|
24
|
+
|
25
|
+
gem install cando
|
26
|
+
|
27
|
+
## Configuration and usage
|
28
|
+
|
29
|
+
### Database setup & configuration
|
30
|
+
If you want to use an individual database for cando, create the db + credentials (adjust values):
|
31
|
+
|
32
|
+
CREATE DATABASE IF NOT EXISTS cando DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
|
33
|
+
GRANT ALL ON `cando`.* to 'cando_user'@'localhost' identified by 'cando_passwd';
|
34
|
+
|
35
|
+
Whenever you want to use a CanDo rake task, you need to set the database config via the env var `$CANDO_DB`:
|
36
|
+
|
37
|
+
export CANDO_DB=mysql://cando_user@cando_passwd@localhost/cando
|
38
|
+
|
39
|
+
for other dbs, [see the sequel
|
40
|
+
documentation](http://sequel.jeremyevans.net/rdoc/classes/Sequel.html#method-c-connect).
|
41
|
+
**Note that you will have to require the gem for your respective dbms, i.e. the
|
42
|
+
`mysql`-gem for mysql, the `sqlite3`-gem for sqlite, etc. **
|
43
|
+
|
44
|
+
### Init cando
|
45
|
+
Cando provides a rake task to get you started. This will setup the necessary
|
46
|
+
tables (they are all prefixed with `cando` and thus should not interfere with
|
47
|
+
your database.
|
48
|
+
|
49
|
+
rake cando:init
|
50
|
+
|
51
|
+
### Using rake tasks
|
52
|
+
Cando provides several useful rake tasks for easy cli-based operations. In order
|
53
|
+
to use those edit (or create) the `Rakefile` and include
|
54
|
+
|
55
|
+
require 'cando'
|
56
|
+
|
57
|
+
To get an overview, execute:
|
58
|
+
|
59
|
+
$ rake -T cando
|
60
|
+
rake cando:init # Initialize cando (creates schema and runs migration)
|
61
|
+
|
62
|
+
rake cando:list # List roles
|
63
|
+
rake cando:add # Add a new role (pass in role name and capabilities with role=<name> capabilities=<cap1>,<cap2>,...
|
64
|
+
rake cando:update # Update role (pass in role name and capabilities with role=<name> capabilities=<cap1>,<cap2>,...
|
65
|
+
rake cando:remove # Remove role (pass in role name with role=<name>)
|
66
|
+
|
67
|
+
rake cando:assign # Assign role to user (args: roles=<r1>,<r2>,<rn> user=<user_urn>)
|
68
|
+
rake cando:users # List users and their roles
|
69
|
+
|
70
|
+
### Using CanDo in your project's code
|
71
|
+
Using the CanDo in your code (working code with an empty database):
|
72
|
+
|
73
|
+
require 'cando'
|
74
|
+
include CanDo
|
75
|
+
|
76
|
+
CanDo.init do
|
77
|
+
# if passed, this will be executed if the user does not have the
|
78
|
+
# asked-for capability (only applies if 'can' is passed a block)
|
79
|
+
cannot_block do |user_urn, capability|
|
80
|
+
raise "#{user_urn} can not #{capability}"
|
81
|
+
end
|
82
|
+
|
83
|
+
connect "mysql://cando_user:cando_passwd@host:port/database"
|
84
|
+
end
|
85
|
+
|
86
|
+
# if the role or a capability does not exist, it'll be created
|
87
|
+
define_role("r1", ["capability1", "capability3"])
|
88
|
+
define_role("r2", ["capability2"])
|
89
|
+
|
90
|
+
# if the user does not exist, he'll be created -- the roles must be available
|
91
|
+
assign_roles("user1", ["r1", "r2"])
|
92
|
+
assign_roles("user2", ["r1"])
|
93
|
+
|
94
|
+
# use 'can' block syntax
|
95
|
+
can("user1", :capability1) do
|
96
|
+
puts "user has capability1"
|
97
|
+
end
|
98
|
+
|
99
|
+
# this will raise an exception as declared in the init block
|
100
|
+
can("user1", :super_admin) do
|
101
|
+
puts "hey hoh" # this will not be printed
|
102
|
+
end
|
103
|
+
|
104
|
+
# when no block is given, 'can' returns true or false/nil
|
105
|
+
unless can("user2", :capability2)
|
106
|
+
puts "user does not have capability1"
|
107
|
+
end
|
108
|
+
|
109
|
+
## Versioning
|
110
|
+
CanDo adheres to Semantic Versioning 2.0.0. If there is a violation of
|
111
|
+
this scheme, report it as a bug.Specifically, if a patch or minor version is
|
112
|
+
released and breaks backward compatibility, that version should be immediately
|
113
|
+
yanked and/or a new version should be immediately released that restores
|
114
|
+
compatibility. Any change that breaks the public API will only be introduced at
|
115
|
+
a major-version release. As a result of this policy, you can (and should)
|
116
|
+
specify any dependency on <project name> by using the Pessimistic Version
|
117
|
+
Constraint with two digits of precision.
|
118
|
+
|
119
|
+
## Licensing
|
120
|
+
|
121
|
+
See the [LICENSE](LICENSE.md) file for details.
|
122
|
+
|
123
|
+
The MIT License (MIT)
|
124
|
+
|
125
|
+
Copyright © 2014 Daniel Bornkessel
|
126
|
+
|
127
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
128
|
+
of this software and associated documentation files (the "Software"), to deal
|
129
|
+
in the Software without restriction, including without limitation the rights
|
130
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
131
|
+
copies of the Software, and to permit persons to whom the Software is
|
132
|
+
furnished to do so, subject to the following conditions:
|
133
|
+
|
134
|
+
The above copyright notice and this permission notice shall be included in
|
135
|
+
all copies or substantial portions of the Software.
|
136
|
+
|
137
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
138
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
139
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
140
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
141
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
142
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
143
|
+
THE SOFTWARE.
|
144
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler'
|
6
|
+
begin
|
7
|
+
Bundler.setup(:default, :development)
|
8
|
+
rescue Bundler::BundlerError => e
|
9
|
+
$stderr.puts e.message
|
10
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
11
|
+
exit e.status_code
|
12
|
+
end
|
13
|
+
require 'rake'
|
14
|
+
|
15
|
+
require 'jeweler'
|
16
|
+
Jeweler::Tasks.new do |gem|
|
17
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
18
|
+
gem.name = "cando"
|
19
|
+
gem.homepage = "http://github.com/kesselborn/cando"
|
20
|
+
gem.license = "MIT"
|
21
|
+
gem.summary = %Q{Simple roles helper}
|
22
|
+
gem.description = %Q{cando description}
|
23
|
+
gem.email = "daniel@soundcloud.com"
|
24
|
+
gem.authors = ["Daniel Bornkessel"]
|
25
|
+
# dependencies defined in Gemfile
|
26
|
+
end
|
27
|
+
Jeweler::RubygemsDotOrgTasks.new
|
28
|
+
|
29
|
+
require 'rspec/core'
|
30
|
+
require 'rspec/core/rake_task'
|
31
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
32
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Code coverage detail"
|
36
|
+
task :simplecov do
|
37
|
+
ENV['COVERAGE'] = "true"
|
38
|
+
Rake::Task['spec'].execute
|
39
|
+
end
|
40
|
+
|
41
|
+
task :default => :spec
|
42
|
+
|
43
|
+
require 'rdoc/task'
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
|
+
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "cando #{version}"
|
49
|
+
rdoc.rdoc_files.include('README*')
|
50
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
rdoc.rdoc_files.include('contrib/**/*.rb')
|
52
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/cando.gemspec
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "cando"
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Daniel Bornkessel"]
|
12
|
+
s.date = "2014-05-20"
|
13
|
+
s.description = "cando description"
|
14
|
+
s.email = "daniel@soundcloud.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
".travis.yml",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.md",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"cando.gemspec",
|
30
|
+
"contrib/initial_schema.rb",
|
31
|
+
"lib/cando.rb",
|
32
|
+
"lib/models/capability.rb",
|
33
|
+
"lib/models/role.rb",
|
34
|
+
"lib/models/user.rb",
|
35
|
+
"lib/tasks/cando.rake",
|
36
|
+
"spec/cando_spec.rb",
|
37
|
+
"spec/spec_helper.rb"
|
38
|
+
]
|
39
|
+
s.homepage = "http://github.com/kesselborn/cando"
|
40
|
+
s.licenses = ["MIT"]
|
41
|
+
s.require_paths = ["lib"]
|
42
|
+
s.rubygems_version = "1.8.23"
|
43
|
+
s.summary = "Simple roles helper"
|
44
|
+
|
45
|
+
if s.respond_to? :specification_version then
|
46
|
+
s.specification_version = 3
|
47
|
+
|
48
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
49
|
+
s.add_runtime_dependency(%q<sequel>, [">= 0"])
|
50
|
+
s.add_runtime_dependency(%q<rake>, [">= 0"])
|
51
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.10.0"])
|
52
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
53
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
54
|
+
s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
|
55
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
56
|
+
else
|
57
|
+
s.add_dependency(%q<sequel>, [">= 0"])
|
58
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
59
|
+
s.add_dependency(%q<rspec>, ["~> 2.10.0"])
|
60
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
61
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
62
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
63
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
64
|
+
end
|
65
|
+
else
|
66
|
+
s.add_dependency(%q<sequel>, [">= 0"])
|
67
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
68
|
+
s.add_dependency(%q<rspec>, ["~> 2.10.0"])
|
69
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
70
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
71
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
72
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
Sequel.migration do
|
2
|
+
up do
|
3
|
+
create_table :cando_users do
|
4
|
+
String :id, :unique => true, :null => false
|
5
|
+
primary_key :id
|
6
|
+
end
|
7
|
+
|
8
|
+
create_table :cando_roles do
|
9
|
+
String :id, :unique => true, :null => false
|
10
|
+
primary_key :id
|
11
|
+
end
|
12
|
+
|
13
|
+
create_table :cando_capabilities do
|
14
|
+
String :id, :unique => true, :null => false
|
15
|
+
primary_key :id
|
16
|
+
end
|
17
|
+
|
18
|
+
# associations
|
19
|
+
create_table :cando_roles_users do
|
20
|
+
String :user_id
|
21
|
+
String :role_id
|
22
|
+
primary_key [:user_id, :role_id], :name => :ur_pk
|
23
|
+
end
|
24
|
+
|
25
|
+
create_table :cando_capabilities_roles do
|
26
|
+
String :role_id
|
27
|
+
String :capability_id
|
28
|
+
primary_key [:role_id, :capability_id], :name =>:rc_pk
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
down do
|
33
|
+
drop_table :cando_users
|
34
|
+
drop_table :cando_roles
|
35
|
+
drop_table :cando_capabilities
|
36
|
+
drop_table :cando_roles_users
|
37
|
+
drop_table :cando_capabilities_roles
|
38
|
+
end
|
39
|
+
end
|
data/lib/cando.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
|
3
|
+
if File.basename($0) == "rake" # we are in a rake call: export our rake stuff
|
4
|
+
require 'rake'
|
5
|
+
import File.join(File.dirname(File.dirname(__FILE__)), "lib", "tasks", "cando.rake" )
|
6
|
+
end
|
7
|
+
|
8
|
+
module CanDo
|
9
|
+
class ConfigCannotBlockError < RuntimeError; end
|
10
|
+
class ConfigMysqlDBError < RuntimeError; end
|
11
|
+
class ConfigMysqlConnectionError < RuntimeError; end
|
12
|
+
class DBNotConnected < RuntimeError; end
|
13
|
+
|
14
|
+
def self.db
|
15
|
+
@db or raise DBNotConnected.new("CanDo is not connected to a database")
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.init(&block)
|
19
|
+
CanDo.instance_eval &block
|
20
|
+
|
21
|
+
begin
|
22
|
+
Sequel::Model.db.test_connection
|
23
|
+
rescue ::Sequel::Error => e
|
24
|
+
raise DBNotConnected.new("No database connection established. Have you called 'connect' within the 'CanDo.init' block? Sequel error message is:\n#{e.message}")
|
25
|
+
end
|
26
|
+
|
27
|
+
Dir.glob(File.expand_path("#{__FILE__}/../models/*.rb")).each do |model|
|
28
|
+
require_relative model
|
29
|
+
end
|
30
|
+
|
31
|
+
Sequel::Model.db
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# will be executed if `can(user_urn, :capability) { }` will not be executed
|
36
|
+
# due to missing capabilities
|
37
|
+
def self.cannot_block(&block)
|
38
|
+
if !block
|
39
|
+
raise ConfigCannotBlockError.new("CanDo#cannot_block expects block")
|
40
|
+
end
|
41
|
+
if block.arity != 2
|
42
|
+
raise ConfigCannotBlockError.new("CanDo#cannot_block expects block expecting two arguments |user_urn, capability|")
|
43
|
+
end
|
44
|
+
|
45
|
+
@@cannot_block_proc = block
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.connect(connection)
|
49
|
+
if connection =~ /sqlite/
|
50
|
+
raise ConfigMysqlDBError.new("sqlite is not supported as it misses certain constraints")
|
51
|
+
end
|
52
|
+
|
53
|
+
begin
|
54
|
+
@db = Sequel.connect(connection)
|
55
|
+
@db.test_connection
|
56
|
+
@db
|
57
|
+
rescue => e
|
58
|
+
raise ConfigMysqlConnectionError.new(<<-EOF
|
59
|
+
Error connecting to database. Be sure to pass in a databse config like 'mysql://user:passwd@host/database':
|
60
|
+
#{e.message}
|
61
|
+
EOF
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def can(user_urn, capability)
|
67
|
+
user = CanDo::User.find(:id => user_urn)
|
68
|
+
has_permission = user && user.can(capability)
|
69
|
+
if block_given?
|
70
|
+
if has_permission
|
71
|
+
return yield
|
72
|
+
end
|
73
|
+
if @@cannot_block_proc
|
74
|
+
@@cannot_block_proc.call(user_urn, capability)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
has_permission
|
79
|
+
end
|
80
|
+
|
81
|
+
def define_role(role, capabilities)
|
82
|
+
CanDo::Role.define_role(role, capabilities)
|
83
|
+
end
|
84
|
+
|
85
|
+
def assign_roles(user, roles)
|
86
|
+
CanDo::User.find_or_create(:id => user).assign_roles(roles)
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module CanDo
|
2
|
+
class Capability < Sequel::Model(:cando_capabilities)
|
3
|
+
many_to_many :roles, :join_table => :cando_capabilities_roles
|
4
|
+
unrestrict_primary_key
|
5
|
+
|
6
|
+
def self.cleanup
|
7
|
+
Capability.all do |cap|
|
8
|
+
if cap.roles.count == 0
|
9
|
+
cap.destroy
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/models/role.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module CanDo
|
2
|
+
class Role < Sequel::Model(:cando_roles)
|
3
|
+
many_to_many :users, :join_table => :cando_roles_users
|
4
|
+
many_to_many :capabilities, :join_table => :cando_capabilities_roles
|
5
|
+
unrestrict_primary_key
|
6
|
+
|
7
|
+
def before_destroy
|
8
|
+
self.remove_all_capabilities
|
9
|
+
self.remove_all_users
|
10
|
+
Capability.cleanup
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.define_role(name, capabilities)
|
14
|
+
role = Role.find_or_create(:id => name)
|
15
|
+
role.remove_all_capabilities
|
16
|
+
capabilities.each do |capability|
|
17
|
+
role.add_capability( Capability.find_or_create(:id => capability.to_s) )
|
18
|
+
end
|
19
|
+
|
20
|
+
role
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
"#{id}\t#{capabilities.map(&:id).join(",")}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/models/user.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module CanDo
|
2
|
+
class UndefinedRole < Exception; end
|
3
|
+
class User < Sequel::Model(:cando_users)
|
4
|
+
many_to_many :roles, :join_table => :cando_roles_users
|
5
|
+
unrestrict_primary_key
|
6
|
+
|
7
|
+
def capabilities
|
8
|
+
roles.inject([]){|a,role| a << role.capabilities}.flatten.uniq.map(&:id)
|
9
|
+
end
|
10
|
+
|
11
|
+
def can(capability)
|
12
|
+
capabilities.include?(capability.to_s)
|
13
|
+
end
|
14
|
+
|
15
|
+
def assign_roles(roles)
|
16
|
+
self.class.db.transaction do
|
17
|
+
self.remove_all_roles
|
18
|
+
roles.each do |r|
|
19
|
+
begin
|
20
|
+
role = r.is_a?(CanDo::Role) ? r : CanDo::Role.where(:id => r).first!
|
21
|
+
self.add_role(role)
|
22
|
+
rescue Sequel::UniqueConstraintViolation => e
|
23
|
+
puts "user already has role '#{r}'"
|
24
|
+
rescue Sequel::NoMatchingRow
|
25
|
+
raise UndefinedRole.new("Role '#{r}' does not exist")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def role_names
|
33
|
+
roles.map(&:id)
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
"#{id}\t#{role_names.join(",")}\t#{capabilities.join(",")}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
CANDO_MIGRATION_DIR = "db/cando-migrations"
|
4
|
+
CANDO_SCHEMA = File.join(File.dirname(File.dirname(File.dirname(__FILE__))), "contrib", "initial_schema.rb")
|
5
|
+
|
6
|
+
namespace :cando do
|
7
|
+
desc "Initialize cando (creates schema and runs migration)"
|
8
|
+
task :init do
|
9
|
+
if Dir.glob("#{CANDO_MIGRATION_DIR}/*#{File.basename(CANDO_SCHEMA)}*").empty?
|
10
|
+
puts green("Copying cando schema to local cando migrations folder '#{CANDO_MIGRATION_DIR}'")
|
11
|
+
cando_schema_migration = File.join(CANDO_MIGRATION_DIR, "#{Time.now.strftime("%Y%m%d%H%M%S")}_#{File.basename(CANDO_SCHEMA)}")
|
12
|
+
|
13
|
+
FileUtils.mkdir_p(CANDO_MIGRATION_DIR) unless File.exists?(CANDO_MIGRATION_DIR)
|
14
|
+
FileUtils.cp(CANDO_SCHEMA, cando_schema_migration)
|
15
|
+
else
|
16
|
+
$stderr.puts red("skipping copying cando schema migration file: already exists")
|
17
|
+
end
|
18
|
+
|
19
|
+
Sequel::Migrator.run(connect_to_db, CANDO_MIGRATION_DIR, { allow_missing_migration_files: true} )
|
20
|
+
|
21
|
+
puts <<EOF
|
22
|
+
#{green("Success!")}
|
23
|
+
|
24
|
+
In order to add, update or remove a role, call
|
25
|
+
|
26
|
+
rake cando:add role=<rolename> capabilities=<cap1>,<cap2>,<cap3>
|
27
|
+
rake cando:update role=<rolename> capabilities=<cap1>,<cap2>,<cap3>
|
28
|
+
rake cando:remove role=<rolename>
|
29
|
+
|
30
|
+
When adding or updating a roles it doesn't matter whether the passed in capabilities
|
31
|
+
exist or not -- if not existant, they will be created automatically
|
32
|
+
|
33
|
+
For more cando rake tasks execute
|
34
|
+
|
35
|
+
rake -T cando
|
36
|
+
|
37
|
+
EOF
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Add a new role (pass in role name and capabilities with role=<name> capabilities=<cap1>,<cap2>,... )"
|
42
|
+
task :add do
|
43
|
+
add_role(false)
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Update role (pass in role name and capabilities with role=<name> capabilities=<cap1>,<cap2>,... )"
|
47
|
+
task :update do
|
48
|
+
add_role(true)
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
desc "Remove role (pass in role name with role=<name>)"
|
53
|
+
task :remove do
|
54
|
+
unless ENV['role']
|
55
|
+
$stderr.puts red("usage: rake cando:remove role=<rolename>")
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
|
59
|
+
connect_to_db
|
60
|
+
unless r = CanDo::Role.find(:id => ENV['role'])
|
61
|
+
$stderr.puts red("role '#{args.role}' does not exist")
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
|
65
|
+
r.destroy
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "Assign role to user (args: roles=<r1>,<r2>,<rn> user=<user_urn>)"
|
69
|
+
task :assign do
|
70
|
+
roles = ENV['roles']
|
71
|
+
user_urn = ENV['user']
|
72
|
+
|
73
|
+
unless roles && user_urn
|
74
|
+
$stderr.puts red("usage: rake cando:assign user=<user_urn> roles=<role1>,<role2>,... ")
|
75
|
+
end
|
76
|
+
|
77
|
+
connect_to_db
|
78
|
+
include CanDo
|
79
|
+
assign_roles(user_urn, roles.split(","))
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "List roles"
|
83
|
+
task :list do
|
84
|
+
connect_to_db
|
85
|
+
puts "ROLE\tCAPABILITIES"
|
86
|
+
CanDo::Role.all.each do |role|
|
87
|
+
puts role
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
desc "List users and their roles"
|
92
|
+
task :users do
|
93
|
+
connect_to_db
|
94
|
+
puts "USER_URN\tROLES\tCAPABILITIES"
|
95
|
+
CanDo::User.all.each do |user|
|
96
|
+
puts user
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
def green(text)
|
103
|
+
"\033[1;32;48m#{text}\033[m"
|
104
|
+
end
|
105
|
+
|
106
|
+
def red(text)
|
107
|
+
"\033[1;31;48m#{text}\033[m"
|
108
|
+
end
|
109
|
+
|
110
|
+
def add_role(force = false)
|
111
|
+
role = ENV['role']
|
112
|
+
capabilities = ENV['capabilities'] && ENV['capabilities'].split(",")
|
113
|
+
|
114
|
+
unless role && capabilities
|
115
|
+
puts red("usage: rake cando:add role=<rolename> capabilities=<cap1>,<cap2>,<cap3>")
|
116
|
+
exit 1
|
117
|
+
end
|
118
|
+
|
119
|
+
connect_to_db
|
120
|
+
if !force && CanDo::Role.find(:id => role)
|
121
|
+
puts red("Role '#{role}' already exists!")
|
122
|
+
puts "If you want to update '#{role}', please use 'rake cando:update'"
|
123
|
+
exit 1
|
124
|
+
end
|
125
|
+
|
126
|
+
include CanDo
|
127
|
+
define_role(role, capabilities)
|
128
|
+
end
|
129
|
+
|
130
|
+
def connect_to_db
|
131
|
+
unless ENV['CANDO_DB']
|
132
|
+
raise "Please pass in database config, e.g. CANDO_DB=mysql://user:passwd@host/database bundle exec rake cando:<command>"
|
133
|
+
end
|
134
|
+
|
135
|
+
CanDo.init do
|
136
|
+
connect(ENV['CANDO_DB'])
|
137
|
+
end
|
138
|
+
end
|
data/spec/cando_spec.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
#describe "Cando" do
|
4
|
+
# it "fails" do
|
5
|
+
# fail "hey buddy, you should probably rename this file and start specing for real"
|
6
|
+
# end
|
7
|
+
#end
|
8
|
+
#
|
9
|
+
describe "CanDo module methods" do
|
10
|
+
context "CanDo.cannot_block expects block accepting two parameters" do
|
11
|
+
it { expect{ CanDo.cannot_block }.to raise_error(CanDo::ConfigCannotBlockError) }
|
12
|
+
it { expect{ CanDo.cannot_block{|x| x} }.to raise_error(CanDo::ConfigCannotBlockError) }
|
13
|
+
it { expect{ CanDo.cannot_block{|x,y,z| x} }.to raise_error(CanDo::ConfigCannotBlockError) }
|
14
|
+
|
15
|
+
it { expect{ CanDo.cannot_block{|x,y| x} }.to_not raise_error(CanDo::ConfigCannotBlockError) }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "CanDo.connect" do
|
19
|
+
it { expect{ CanDo.connect(nil) }.to raise_error(CanDo::ConfigMysqlConnectionError) }
|
20
|
+
it { expect{ CanDo.connect("sqlite::memory:") }.to raise_error(CanDo::ConfigMysqlDBError) }
|
21
|
+
it { CanDo.connect(ENV['CANDO_TEST_DB']).test_connection be_true }
|
22
|
+
end
|
23
|
+
|
24
|
+
context "CanDo.init" do
|
25
|
+
context "CanDo.cannot_block called from config" do
|
26
|
+
it { expect{ CanDo.init{ cannot_block }}.to raise_error(CanDo::ConfigCannotBlockError) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "CanDo exported methods" do
|
31
|
+
include CanDo
|
32
|
+
|
33
|
+
context "CanDo#define_role" do
|
34
|
+
context "empty role (no capabilities)" do
|
35
|
+
it { expect{ define_role("role", []) }.to change{CanDo::Role.count}.from(0).to(1) }
|
36
|
+
it { expect{ define_role("role", []) }.to change{CanDo::Capability.count}.by(0) }
|
37
|
+
end
|
38
|
+
|
39
|
+
context "standard situation" do
|
40
|
+
it { expect{ define_role("role", [:capability1, :capability2]) }.to change{CanDo::Role.count}.from(0).to(1) }
|
41
|
+
it { expect{ define_role("role", [:capability1, :capability2]) }.to change{CanDo::Capability.count}.from(0).to(2) }
|
42
|
+
end
|
43
|
+
|
44
|
+
context "duplication" do
|
45
|
+
before(:each) { define_role("role", [:capability]) }
|
46
|
+
|
47
|
+
it { expect{ define_role("role", [:new_capability]) }.to change{CanDo::Role.count}.by(0) }
|
48
|
+
it { expect{ define_role("new_role", [:capability]) }.to change{CanDo::Capability.count}.by(0) }
|
49
|
+
end
|
50
|
+
|
51
|
+
context "cleanup" do
|
52
|
+
before(:each) do
|
53
|
+
@role = define_role("role", [:capabilty])
|
54
|
+
end
|
55
|
+
|
56
|
+
it { expect{ @role.destroy }.to change{CanDo::Role.count}.from(1).to(0) }
|
57
|
+
it { expect{ @role.destroy }.to change{CanDo::Capability.count}.from(1).to(0) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "CanDo#assign_roles" do
|
62
|
+
include CanDo
|
63
|
+
|
64
|
+
context "user without roles" do
|
65
|
+
it { expect{ assign_roles("user", []) }.to change{CanDo::User.count}.from(0).to(1) }
|
66
|
+
it { expect{ assign_roles("user", []) }.to change{CanDo::Role.count}.by(0) }
|
67
|
+
end
|
68
|
+
|
69
|
+
context "invalid roles" do
|
70
|
+
it { expect{ assign_roles("user", ["non-existant-role"]) }.to raise_error(CanDo::UndefinedRole) }
|
71
|
+
it { expect{ assign_roles("user", [nil]) }.to raise_error(CanDo::UndefinedRole) }
|
72
|
+
end
|
73
|
+
|
74
|
+
context "standard situation" do
|
75
|
+
before(:each) do
|
76
|
+
@r1 = define_role("r1", [:c1, :c2])
|
77
|
+
@r2 = define_role("r2", [:c2, :c3])
|
78
|
+
end
|
79
|
+
|
80
|
+
it { expect{ assign_roles("user", ["r1"]) }.to change{CanDo::User.count}.from(0).to(1) }
|
81
|
+
it { expect{ assign_roles("user", ["r1","r2"]) }.to change{CanDo::User.count}.from(0).to(1) }
|
82
|
+
|
83
|
+
it { expect{ assign_roles("user", [@r1]) }.to change{CanDo::User.count}.from(0).to(1) }
|
84
|
+
it { expect{ assign_roles("user", ["r1",@r2]) }.to change{CanDo::User.count}.from(0).to(1) }
|
85
|
+
end
|
86
|
+
|
87
|
+
context "cleanup" do
|
88
|
+
before(:each) do
|
89
|
+
@role = define_role("role", [:capabilty])
|
90
|
+
@user = assign_roles("user", [@role])
|
91
|
+
end
|
92
|
+
|
93
|
+
it { expect{ @user.destroy }.to change{CanDo::User.count}.from(1).to(0) }
|
94
|
+
it { expect{ @user.destroy }.to change{CanDo::Role.count}.by(0) }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "CanDo#can" do
|
99
|
+
include CanDo
|
100
|
+
|
101
|
+
before(:each) do
|
102
|
+
@role = define_role("role", [:capability1, :capabilty2])
|
103
|
+
@user = assign_roles("user", [@role])
|
104
|
+
end
|
105
|
+
|
106
|
+
context "CanDo#can" do
|
107
|
+
it { can("user", :capability1).should be_true }
|
108
|
+
it { can("user", :undefined_capability).should be_false }
|
109
|
+
|
110
|
+
it { expect{ |can| can("user", :capability1, &can) }.to yield_control }
|
111
|
+
|
112
|
+
context "CanDo.cannot_block" do
|
113
|
+
class DummyException < RuntimeError; end
|
114
|
+
before(:all) do
|
115
|
+
CanDo.cannot_block do |user, capabilty|
|
116
|
+
raise DummyException
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
it { expect{ can("user", :undefined_capability){} }.to raise_error(DummyException) }
|
121
|
+
it { expect{ can("user", :undefined_capability)}.to_not raise_error(DummyException) }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'cando'
|
3
|
+
|
4
|
+
module SimpleCov::Configuration
|
5
|
+
def clean_filters
|
6
|
+
@filters = []
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
SimpleCov.configure do
|
11
|
+
clean_filters
|
12
|
+
load_profile 'test_frameworks'
|
13
|
+
end
|
14
|
+
|
15
|
+
ENV["COVERAGE"] && SimpleCov.start do
|
16
|
+
add_filter "/.rvm/"
|
17
|
+
end
|
18
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
19
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
20
|
+
|
21
|
+
require 'rspec'
|
22
|
+
require 'cando'
|
23
|
+
|
24
|
+
# Requires supporting files with custom matchers and macros, etc,
|
25
|
+
# in ./support/ and its subdirectories.
|
26
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
27
|
+
|
28
|
+
ENV['CANDO_TEST_DB'] or raise "Please set CANDO_TEST_DB to a valid configuration similar to 'mysql://user:passwd@localhost/database'"
|
29
|
+
|
30
|
+
RSpec.configure do |config|
|
31
|
+
Sequel.extension :migration
|
32
|
+
migration = eval(File.read(File.join(File.dirname(File.dirname(__FILE__)), "contrib", "initial_schema.rb")))
|
33
|
+
db = nil
|
34
|
+
|
35
|
+
config.before(:suite) do
|
36
|
+
db = CanDo.init do
|
37
|
+
connect ENV['CANDO_TEST_DB']
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
config.before(:each) do
|
42
|
+
db.drop_table(*db.tables)
|
43
|
+
migration.apply(db, :up)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def connect
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cando
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Daniel Bornkessel
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-05-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sequel
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.10.0
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.10.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rdoc
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.12'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '3.12'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: bundler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '1.0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '1.0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: jeweler
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 2.0.1
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 2.0.1
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: simplecov
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
description: cando description
|
127
|
+
email: daniel@soundcloud.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files:
|
131
|
+
- LICENSE.txt
|
132
|
+
- README.md
|
133
|
+
files:
|
134
|
+
- .document
|
135
|
+
- .rspec
|
136
|
+
- .travis.yml
|
137
|
+
- Gemfile
|
138
|
+
- Gemfile.lock
|
139
|
+
- LICENSE.txt
|
140
|
+
- README.md
|
141
|
+
- Rakefile
|
142
|
+
- VERSION
|
143
|
+
- cando.gemspec
|
144
|
+
- contrib/initial_schema.rb
|
145
|
+
- lib/cando.rb
|
146
|
+
- lib/models/capability.rb
|
147
|
+
- lib/models/role.rb
|
148
|
+
- lib/models/user.rb
|
149
|
+
- lib/tasks/cando.rake
|
150
|
+
- spec/cando_spec.rb
|
151
|
+
- spec/spec_helper.rb
|
152
|
+
homepage: http://github.com/kesselborn/cando
|
153
|
+
licenses:
|
154
|
+
- MIT
|
155
|
+
post_install_message:
|
156
|
+
rdoc_options: []
|
157
|
+
require_paths:
|
158
|
+
- lib
|
159
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
160
|
+
none: false
|
161
|
+
requirements:
|
162
|
+
- - ! '>='
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
segments:
|
166
|
+
- 0
|
167
|
+
hash: -3220119119017063207
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
requirements: []
|
175
|
+
rubyforge_project:
|
176
|
+
rubygems_version: 1.8.23
|
177
|
+
signing_key:
|
178
|
+
specification_version: 3
|
179
|
+
summary: Simple roles helper
|
180
|
+
test_files: []
|