cando 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -68,6 +68,54 @@ to use those edit (or create) the `Rakefile` and include
68
68
  rake cando:users # List users and their roles
69
69
 
70
70
  ### Using CanDo in your project's code
71
+
72
+ #### Api
73
+ Please see [the api documentation](http://rubydoc.info/gems/cando/CanDo) up to date documentation.
74
+
75
+ connect to db (usually called within init block):
76
+
77
+ CanDo.connect "mysql://user:passwd@host:port/database"
78
+
79
+ create a role; capabilities will be created if they don't exist yet:
80
+
81
+ define_role("role_name", ["capability1","capability2", "capability3", ...])
82
+
83
+ assign role(s) to a user: if no user with that id exist, a new one will
84
+ be created; if a role does not exist, an exception is raised. You can pass
85
+ in a role object or just role names; pass in empty array to remove all roles:
86
+
87
+ role3 = CanDo::Role.first
88
+ assign_roles("user1", ["role1", "role2", role3])
89
+
90
+ get user's capabilities; returns an array of strings:
91
+
92
+ capabilities("user1")
93
+
94
+ get user's roles; returns an array of strings:
95
+
96
+ roles("user1")
97
+
98
+ set default handler if `can("u","c"){ ... }` fails (usually called within init block):
99
+
100
+ CanDo.cannot_block { |user_urn, capability| raise "#{user_urn} is missing #{capability}" }
101
+
102
+ guard block by `can` function; will execute `cannot_block` if user is missing
103
+ this capability (see example below):
104
+
105
+ can("user1", :capability1) do
106
+ puts "woohoo"
107
+ end
108
+
109
+ use `can` function as an expression -- `cannot_block` will not be executed if
110
+ expressions resolves to `false`:
111
+
112
+ if can("user1", :capability1)
113
+ puts "woohoo"
114
+ else
115
+ puts ":("
116
+ end
117
+
118
+ #### Usage example
71
119
  Using the CanDo in your code (working code with an empty database):
72
120
 
73
121
  require 'cando'
data/Rakefile CHANGED
@@ -51,6 +51,7 @@ Rake::RDocTask.new do |rdoc|
51
51
 
52
52
  rdoc.rdoc_dir = 'rdoc'
53
53
  rdoc.title = "cando #{version}"
54
+ rdoc.rdoc_files.include('lib')
54
55
  rdoc.rdoc_files.include('README*')
55
56
  rdoc.rdoc_files.include('lib/**/*.rb')
56
57
  rdoc.rdoc_files.include('contrib/**/*.rb')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.2.1
data/cando.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "cando"
8
- s.version = "0.2.0"
8
+ s.version = "0.2.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Daniel Bornkessel"]
12
- s.date = "2014-05-21"
12
+ s.date = "2014-05-27"
13
13
  s.description = "CanDo is a small gem to implement a simple user access system based on users, roles & capabilites, where:\n\n each user can have 0, 1 or many roles\n each role can have 0, 1 or many capabilites\n\nUsers have capabilities by getting roles assigned (role == collection of capabilities). Within the code, the can helper method can be used to test whether a user has a certain capability or not (see below for a working code example)."
14
14
  s.email = "daniel@soundcloud.com"
15
15
  s.extra_rdoc_files = [
data/lib/cando.rb CHANGED
@@ -6,15 +6,41 @@ if File.basename($0) == "rake" # we are in a rake call: export our rake stuff
6
6
  end
7
7
 
8
8
  module CanDo
9
+ # The provided cannot_block is not as expected
9
10
  class ConfigCannotBlockError < RuntimeError; end
10
- class ConfigMysqlDBError < RuntimeError; end
11
- class ConfigMysqlConnectionError < RuntimeError; end
11
+
12
+ # CanDo.connect received an invalid or unsupported connection string
13
+ class ConfigDBError < RuntimeError; end
14
+
15
+ # Error while trying to connect to the database
16
+ class ConfigConnectionError < RuntimeError; end
17
+
18
+ # CanDo is not connected to a database but connection is needed
12
19
  class DBNotConnected < RuntimeError; end
13
20
 
21
+ # Return current database connection
22
+ #
23
+ # raises DBNotConnected exception if CanDo is not connected to a db
14
24
  def self.db
15
25
  @db or raise DBNotConnected.new("CanDo is not connected to a database")
16
26
  end
17
27
 
28
+ # Initializes CanDo
29
+ #
30
+ # This method should be called during boot up to configure CanDo with the db
31
+ # connection and the cannot_block:
32
+ #
33
+ # CanDo.init do
34
+ # # this will be executed if the user does not have the
35
+ # # asked-for capability (only applies if 'can' is passed a block)
36
+ # cannot_block do |user_urn, capability|
37
+ # raise "#{user_urn} can not #{capability} .. user capabilities are: #{capabilities(user_urn)}"
38
+ # end
39
+ #
40
+ # connect "mysql://cando_user:cando_passwd@host:port/database"
41
+ # end
42
+ #
43
+ # ...
18
44
  def self.init(&block)
19
45
  CanDo.instance_eval &block
20
46
 
@@ -32,8 +58,11 @@ module CanDo
32
58
  end
33
59
 
34
60
 
35
- # will be executed if `can(user_urn, :capability) { }` will not be executed
36
- # due to missing capabilities
61
+ # Block to be executed if <tt>can("user", :cap) { }</tt> will not be executed due to missing capability
62
+ #
63
+ # - the block needs to accept two arguments <tt>|user_urn, capability|</tt>
64
+ # - this function should be called in the init method (see there for an example).
65
+ # - if this block gets executed, it'll have the context of the <tt>can(...){ }</tt> call
37
66
  def self.cannot_block(&block)
38
67
  if !block
39
68
  raise ConfigCannotBlockError.new("CanDo#cannot_block expects block")
@@ -45,9 +74,16 @@ module CanDo
45
74
  @@cannot_block_proc = block
46
75
  end
47
76
 
77
+ # Connect to database
78
+ #
79
+ # Pass in a connection string of the form
80
+ #
81
+ # mysql://user:passwd@host:port/database
82
+ #
83
+ # Raises CanDo::ConfigConnectionError or CanDo::ConfigDBError when problems occur
48
84
  def self.connect(connection)
49
85
  if connection =~ /sqlite/
50
- raise ConfigMysqlDBError.new("sqlite is not supported as it misses certain constraints")
86
+ raise ConfigDBError.new("sqlite is not supported as it misses certain constraints")
51
87
  end
52
88
 
53
89
  begin
@@ -55,7 +91,7 @@ module CanDo
55
91
  @db.test_connection
56
92
  @db
57
93
  rescue => e
58
- raise ConfigMysqlConnectionError.new(<<-EOF
94
+ raise ConfigConnectionError.new(<<-EOF
59
95
  Error connecting to database. Be sure to pass in a databse config like 'mysql://user:passwd@host/database':
60
96
  #{e.message}
61
97
  EOF
@@ -63,6 +99,26 @@ EOF
63
99
  end
64
100
  end
65
101
 
102
+ # Method to check whether a user has a certain capability
103
+ #
104
+ # It can be used in two manners:
105
+ #
106
+ # * pass it a block which is only executed if the user has the capability:
107
+ #
108
+ # can("user_urn", :capability) do
109
+ # puts "woohoo"
110
+ # end
111
+ #
112
+ # this will execute cannot_block if user is missing this capability.
113
+ #
114
+ # * use as an expression that return true or false/nil
115
+ #
116
+ # if can("user_urn", :capability) do
117
+ # puts "woohoo"
118
+ # else
119
+ # puts "epic fail"
120
+ # end
121
+ #
66
122
  def can(user_urn, capability)
67
123
  user = CanDo::User.find(:id => user_urn)
68
124
  has_permission = user && user.can(capability)
@@ -78,14 +134,28 @@ EOF
78
134
  has_permission
79
135
  end
80
136
 
137
+ # Define or redefine a role
138
+ #
139
+ # Capabilities will be created if they don't exist yet
81
140
  def define_role(role, capabilities)
82
141
  CanDo::Role.define_role(role, capabilities)
83
142
  end
84
143
 
144
+ # Assign role(s) to a user
145
+ #
146
+ # assign_roles("user_urn", ["role_name", role_object])
147
+ #
148
+ # - if no user with that id exist, a new one will be created
149
+ # - if a role does not exist, an CanDo::Role::UndefinedRole is raised
150
+ # - you can pass in a role object or just role names (see example above)
151
+ # - pass in an empty array to remove all roles from user
85
152
  def assign_roles(user, roles)
86
153
  CanDo::User.find_or_create(:id => user).assign_roles(roles)
87
154
  end
88
155
 
156
+ # Get user's roles
157
+ #
158
+ # returns an array of strings
89
159
  def roles(user)
90
160
  user = CanDo::User.first(:id => user)
91
161
  return [] unless user
@@ -93,6 +163,9 @@ EOF
93
163
  user.roles.map(&:id)
94
164
  end
95
165
 
166
+ # Get user's capabilities
167
+ #
168
+ # returns an array of strings
96
169
  def capabilities(user)
97
170
  user = CanDo::User.first(:id => user)
98
171
  return [] unless user
data/lib/models/role.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  module CanDo
2
2
  class Role < Sequel::Model(:cando_roles)
3
+ # This role does not exist
4
+ class UndefinedRole < Exception; end
5
+
3
6
  many_to_many :users, :join_table => :cando_roles_users
4
7
  many_to_many :capabilities, :join_table => :cando_capabilities_roles
5
8
  unrestrict_primary_key
data/lib/models/user.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module CanDo
2
- class UndefinedRole < Exception; end
3
2
  class User < Sequel::Model(:cando_users)
3
+
4
4
  many_to_many :roles, :join_table => :cando_roles_users
5
5
  unrestrict_primary_key
6
6
 
@@ -22,7 +22,7 @@ module CanDo
22
22
  rescue Sequel::UniqueConstraintViolation => e
23
23
  puts "user already has role '#{r}'"
24
24
  rescue Sequel::NoMatchingRow
25
- raise UndefinedRole.new("Role '#{r}' does not exist")
25
+ raise Role::UndefinedRole.new("Role '#{r}' does not exist")
26
26
  end
27
27
  end
28
28
  end
data/spec/cando_spec.rb CHANGED
@@ -1,11 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
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
3
  describe "CanDo module methods" do
10
4
  context "CanDo.cannot_block expects block accepting two parameters" do
11
5
  it { expect{ CanDo.cannot_block }.to raise_error(CanDo::ConfigCannotBlockError) }
@@ -39,8 +33,8 @@ describe "CanDo module methods" do
39
33
  end
40
34
 
41
35
  context "CanDo.connect" do
42
- it { expect{ CanDo.connect(nil) }.to raise_error(CanDo::ConfigMysqlConnectionError) }
43
- it { expect{ CanDo.connect("sqlite::memory:") }.to raise_error(CanDo::ConfigMysqlDBError) }
36
+ it { expect{ CanDo.connect(nil) }.to raise_error(CanDo::ConfigConnectionError) }
37
+ it { expect{ CanDo.connect("sqlite::memory:") }.to raise_error(CanDo::ConfigDBError) }
44
38
  it { CanDo.connect(ENV['CANDO_TEST_DB']).test_connection be_true }
45
39
  end
46
40
 
@@ -90,8 +84,8 @@ describe "CanDo module methods" do
90
84
  end
91
85
 
92
86
  context "invalid roles" do
93
- it { expect{ assign_roles("user", ["non-existant-role"]) }.to raise_error(CanDo::UndefinedRole) }
94
- it { expect{ assign_roles("user", [nil]) }.to raise_error(CanDo::UndefinedRole) }
87
+ it { expect{ assign_roles("user", ["non-existant-role"]) }.to raise_error(CanDo::Role::UndefinedRole) }
88
+ it { expect{ assign_roles("user", [nil]) }.to raise_error(CanDo::Role::UndefinedRole) }
95
89
  end
96
90
 
97
91
  context "standard situation" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cando
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-05-21 00:00:00.000000000 Z
12
+ date: 2014-05-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sequel
@@ -169,7 +169,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
169
169
  version: '0'
170
170
  segments:
171
171
  - 0
172
- hash: 1474018739418741316
172
+ hash: -614063614560370007
173
173
  required_rubygems_version: !ruby/object:Gem::Requirement
174
174
  none: false
175
175
  requirements: