cando 0.2.0 → 0.2.1

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/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: