cantango-api 0.1.2 → 0.1.3
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/Gemfile +1 -1
- data/Gemfile.lock +2 -2
- data/README.mdown +272 -27
- data/VERSION +1 -1
- data/cantango-api.gemspec +13 -7
- data/lib/cantango/api/ability.rb +1 -1
- data/lib/cantango/api/ability/dsl.rb +14 -0
- data/lib/cantango/api/ability/dsl/relationship.rb +17 -0
- data/lib/cantango/api/ability/relation.rb +72 -0
- data/lib/cantango/api/ability/scope.rb +13 -0
- data/lib/cantango/api/can.rb +1 -1
- data/spec/cantango/api/ability/dsl/relationship_ex.rb +29 -0
- data/spec/cantango/api/ability/dsl/relationship_spec.rb +29 -0
- data/spec/cantango/api/ability/dsl_spec.rb +38 -0
- data/spec/cantango/api/ability/relation_spec.rb +90 -0
- data/spec/cantango/api/ability/scope_spec.rb +37 -0
- data/spec/fixtures/models/project.rb +9 -0
- metadata +32 -26
- data/lib/cantango/api/can/dsl.rb +0 -26
- data/lib/cantango/api/can/dsl/relation.rb +0 -67
- data/lib/cantango/api/can/dsl/scope.rb +0 -24
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -38,7 +38,7 @@ GEM
|
|
38
38
|
rails (>= 3.1)
|
39
39
|
sugar-high (>= 0.6.1)
|
40
40
|
sweetloader (~> 0.1.6)
|
41
|
-
cantango-core (0.1.9.
|
41
|
+
cantango-core (0.1.9.3)
|
42
42
|
cancan (>= 1.4)
|
43
43
|
hashie (~> 1.2)
|
44
44
|
rails (>= 3.0.1)
|
@@ -137,7 +137,7 @@ PLATFORMS
|
|
137
137
|
DEPENDENCIES
|
138
138
|
bundler (>= 1.1.rc)
|
139
139
|
cantango-config (>= 0.1.9.2)
|
140
|
-
cantango-core (>= 0.1.9.
|
140
|
+
cantango-core (>= 0.1.9.3)
|
141
141
|
cantango-masquerade (>= 0.1.3.2)
|
142
142
|
cutter
|
143
143
|
database_cleaner
|
data/README.mdown
CHANGED
@@ -2,9 +2,10 @@
|
|
2
2
|
|
3
3
|
The main API for [CanTango](https://github.com/kristianmandrup/cantango)
|
4
4
|
|
5
|
-
## Status: Dec
|
5
|
+
## Status: Dec 9 2011
|
6
6
|
|
7
|
-
The API
|
7
|
+
The CanTango API has now been almost fully spec'ed.
|
8
|
+
All specs except for CanTango::Ability::Dsl now pass :)
|
8
9
|
|
9
10
|
## Dependencies
|
10
11
|
|
@@ -12,29 +13,67 @@ This extension depends on the CanTango [core](https://github.com/kristianmandrup
|
|
12
13
|
|
13
14
|
## Core extensions
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
Macro modules
|
17
|
+
|
18
|
+
* CanTango::Api::Macros::
|
17
19
|
* Account
|
20
|
+
* User
|
21
|
+
* Clazz
|
18
22
|
|
19
|
-
These
|
23
|
+
These macro modules allow registration of CanTango User and Account models.
|
20
24
|
|
21
|
-
|
25
|
+
Note: These should perhaps be wrapped in a `Model` namespace? See '-core'
|
26
|
+
|
27
|
+
### Account model registration
|
28
|
+
|
29
|
+
````ruby
|
30
|
+
class UserAccount
|
31
|
+
tango_account
|
32
|
+
end
|
33
|
+
|
34
|
+
class AdminAccount
|
35
|
+
tango_account
|
36
|
+
end
|
37
|
+
|
38
|
+
# if masquerading enabled via 'cantango-masquerade' gem
|
39
|
+
class PublisherAccount
|
40
|
+
tango_account :masquerade
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
### User model registration
|
22
45
|
|
23
46
|
```ruby
|
24
47
|
class User
|
25
|
-
|
48
|
+
tango_user
|
26
49
|
end
|
27
50
|
|
28
51
|
class Admin
|
29
|
-
|
52
|
+
tango_user
|
53
|
+
end
|
54
|
+
|
55
|
+
# if masquerading enabled via 'cantango-masquerade' gem
|
56
|
+
class Publisher
|
57
|
+
tango_user :masquerade
|
30
58
|
end
|
59
|
+
```
|
31
60
|
|
61
|
+
### Generic model registration
|
62
|
+
|
63
|
+
The `Clazz` macro module uses naming conventions to determine if the model is a User or Account model.
|
64
|
+
|
65
|
+
````ruby
|
32
66
|
class UserAccount
|
33
|
-
|
67
|
+
cantango
|
34
68
|
end
|
35
69
|
|
36
|
-
class
|
37
|
-
|
70
|
+
class Admin
|
71
|
+
cantango
|
72
|
+
end
|
73
|
+
|
74
|
+
# if masquerading enabled via 'cantango-masquerade' gem
|
75
|
+
class PublisherAccount
|
76
|
+
cantango :masquerade
|
38
77
|
end
|
39
78
|
```
|
40
79
|
|
@@ -42,38 +81,244 @@ end
|
|
42
81
|
|
43
82
|
The main API consists of the following:
|
44
83
|
|
45
|
-
*
|
46
|
-
*
|
47
|
-
*
|
48
|
-
*
|
49
|
-
*
|
84
|
+
* CanTango::Api::
|
85
|
+
* Ability
|
86
|
+
* Can
|
87
|
+
* Model
|
88
|
+
* Scope
|
89
|
+
* Session
|
50
90
|
|
51
91
|
Each of these have a specific variant for both `Account` and `User`.
|
52
92
|
|
53
|
-
|
93
|
+
## Ability
|
54
94
|
|
55
|
-
*
|
95
|
+
* CanTango::Api::Ability
|
96
|
+
* Account
|
97
|
+
* User
|
98
|
+
* Dsl
|
99
|
+
* Relationship
|
56
100
|
* Relation
|
57
101
|
* Scope
|
58
102
|
|
59
|
-
The Dsl API extends the CanCan Ability API with Relation and Scope APIs.
|
60
103
|
|
61
|
-
|
104
|
+
### Account
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
account_ability(current_account)
|
108
|
+
current_account_ability(:admin)
|
109
|
+
```
|
110
|
+
|
111
|
+
### User
|
62
112
|
|
63
|
-
|
64
|
-
|
113
|
+
```ruby
|
114
|
+
user_ability(current_user)
|
115
|
+
current_user_ability(:editor)
|
116
|
+
```
|
65
117
|
|
66
|
-
|
118
|
+
### Dsl
|
67
119
|
|
68
|
-
|
120
|
+
The Dsl API extends the Ability API with *Relation* and *Scope* APIs.
|
121
|
+
When The `Ability::Dsl` module is included, both these APIs are included into the target.
|
122
|
+
|
123
|
+
### Dsl - Relation
|
69
124
|
|
70
125
|
```ruby
|
71
|
-
|
72
|
-
|
126
|
+
owner_of(Post).can :edit
|
127
|
+
owner_of(Post).cannot :publish
|
128
|
+
|
129
|
+
owner_of(Post). do |owner|
|
130
|
+
owner.can :edit
|
131
|
+
owner.cannot :publish
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
This DSL creates a `Relation` object with #can and #cannot methods that delegate the wrapped ability.
|
136
|
+
|
137
|
+
### Dsl - Scope
|
138
|
+
|
139
|
+
Do relationship on Ability `#user` (also the default scope)
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
scope :user do |user|
|
143
|
+
user.owner_of(Post).can :edit
|
144
|
+
user.owner_of(Post).cannot :publish
|
145
|
+
|
146
|
+
user.owner_of(Post). do |owner|
|
147
|
+
owner.can :edit
|
148
|
+
owner.cannot :publish
|
149
|
+
end
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
This DSL creates a `Scope` object that wraps an ability. It also includes the Relation API.
|
154
|
+
|
155
|
+
Do relationship on Ability `#account`
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
scope :account do |account|
|
159
|
+
account.owner_of(Post) do |owner|
|
160
|
+
owner.can :edit
|
161
|
+
owner.cannot :publish
|
162
|
+
end
|
163
|
+
|
164
|
+
account.can :create, [Blog, Article]
|
165
|
+
account.cannot [:create, :delete], User
|
166
|
+
# ...
|
73
167
|
end
|
74
168
|
```
|
75
169
|
|
76
|
-
|
170
|
+
## Can API
|
171
|
+
|
172
|
+
* CanTango::Api::Can
|
173
|
+
* Account
|
174
|
+
* User
|
175
|
+
|
176
|
+
### Account
|
177
|
+
|
178
|
+
Assuming we have registered the following types of accounts:
|
179
|
+
|
180
|
+
`CanTango.config.accounts.registered # => [:user, admin]`
|
181
|
+
|
182
|
+
Then the following methods become available when this module is included:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
user_account_can? *args
|
186
|
+
admin_account_can? *args
|
187
|
+
|
188
|
+
user_account_cannot? *args
|
189
|
+
admin_account_cannot? *args
|
190
|
+
```
|
191
|
+
|
192
|
+
The following methods are generated by this module, but by default simply forward to #current_user and #current_admin respectively. It is up to the developer to implement these methods to suit the application scenario.
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
current_user_account
|
196
|
+
current_admin_account
|
197
|
+
```
|
198
|
+
|
199
|
+
### User
|
200
|
+
|
201
|
+
Assuming we have registered the following types of accounts:
|
202
|
+
|
203
|
+
`CanTango.config.users.registered # => [:user, admin]`
|
204
|
+
|
205
|
+
Then the following methods become available when this module is included:
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
user_can? *args
|
209
|
+
admin_can? *args
|
210
|
+
|
211
|
+
user_cannot? *args
|
212
|
+
admin_cannot? *args
|
213
|
+
```
|
214
|
+
|
215
|
+
It is up to the developer to make the following methods available.
|
216
|
+
If Devise is used, methods of the form `#current_[user class]` are generated for each Devise user model.
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
current_user
|
220
|
+
current_admin
|
221
|
+
```
|
222
|
+
|
223
|
+
## Model APIs
|
224
|
+
|
225
|
+
* CanTango::Api::Model
|
226
|
+
* Account
|
227
|
+
* User
|
228
|
+
|
229
|
+
Note: The Macros for `User` and `Account` (tango_user, tango_account, ...) might be moved under this namespace later.
|
230
|
+
|
231
|
+
### Account
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
active_user
|
235
|
+
active_account
|
236
|
+
can?
|
237
|
+
cannot?
|
238
|
+
```
|
239
|
+
|
240
|
+
### User
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
active_user
|
244
|
+
active_account
|
245
|
+
can?
|
246
|
+
cannot?
|
247
|
+
```
|
248
|
+
|
249
|
+
## Scope APIs
|
250
|
+
|
251
|
+
* CanTango::Api::Scope
|
252
|
+
* Account
|
253
|
+
* User
|
254
|
+
|
255
|
+
### Account
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
scope_account scope, options, &block # alias: account_scope
|
259
|
+
real_account scope, options, &block
|
260
|
+
```
|
261
|
+
|
262
|
+
`#scope_account` can be used to make multiple AC checks within a block on a specific account. This method will use the masqueraded account if an account being masqueraded.
|
263
|
+
|
264
|
+
`#real_account` is similar to `#scope_account`, but ignores any masquerading, applying the AC checks on the "real" account, not the one being masqueraded (faked).
|
265
|
+
|
266
|
+
### User
|
267
|
+
|
268
|
+
```ruby
|
269
|
+
scope_user scope, options, &block # alias: user_scope
|
270
|
+
real_user scope, options, &block
|
271
|
+
```
|
272
|
+
|
273
|
+
`#scope_user` can be used to make multiple AC checks within a block on a specific user. This method will use the masqueraded user if a user being masqueraded.
|
274
|
+
|
275
|
+
`#real_user` is similar to `#scope_user`, but ignores any masquerading, applying the AC checks on the "real" user, not the one being masqueraded (faked).
|
276
|
+
|
277
|
+
## Session APIs
|
278
|
+
|
279
|
+
* CanTango::Api::Session
|
280
|
+
* Account
|
281
|
+
* User
|
282
|
+
|
283
|
+
### Account
|
284
|
+
|
285
|
+
Assuming we have registered the following types of accounts:
|
286
|
+
|
287
|
+
`CanTango.config.accounts.registered # => [:editor, admin]`
|
288
|
+
|
289
|
+
Then the following methods become available when this module is included:
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
session_editor_account
|
293
|
+
session_admin_account
|
294
|
+
any_account *names
|
295
|
+
guest_account
|
296
|
+
active_account
|
297
|
+
active_account= account
|
298
|
+
```
|
299
|
+
|
300
|
+
`#any_account` will return the first account for which a name matches. If no account matches are found it will default to return the guest account. To find users, it will use the `#current_[account type]` methods.
|
301
|
+
|
302
|
+
### User
|
303
|
+
|
304
|
+
Assuming we have registered the following types of users:
|
305
|
+
|
306
|
+
`CanTango.config.users.registered # => [:user, admin]`
|
307
|
+
|
308
|
+
Then the following methods become available when this module is included:
|
309
|
+
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
session_user
|
313
|
+
session_admin
|
314
|
+
any_account *names
|
315
|
+
guest_user
|
316
|
+
active_user
|
317
|
+
active_user= user
|
318
|
+
```
|
319
|
+
|
320
|
+
`#any_user` will return the first user for which a name matches. If no user matches are found it will default to return the guest user. To find users, it will use the `#current_[user type]` methods.
|
321
|
+
|
77
322
|
|
78
323
|
## Contributing to cantango-api
|
79
324
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.3
|
data/cantango-api.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{cantango-api}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = [%q{Kristian Mandrup}]
|
@@ -29,14 +29,15 @@ Gem::Specification.new do |s|
|
|
29
29
|
"lib/cantango/api.rb",
|
30
30
|
"lib/cantango/api/ability.rb",
|
31
31
|
"lib/cantango/api/ability/account.rb",
|
32
|
+
"lib/cantango/api/ability/dsl.rb",
|
33
|
+
"lib/cantango/api/ability/dsl/relationship.rb",
|
34
|
+
"lib/cantango/api/ability/relation.rb",
|
35
|
+
"lib/cantango/api/ability/scope.rb",
|
32
36
|
"lib/cantango/api/ability/user.rb",
|
33
37
|
"lib/cantango/api/account.rb",
|
34
38
|
"lib/cantango/api/attributes.rb",
|
35
39
|
"lib/cantango/api/can.rb",
|
36
40
|
"lib/cantango/api/can/account.rb",
|
37
|
-
"lib/cantango/api/can/dsl.rb",
|
38
|
-
"lib/cantango/api/can/dsl/relation.rb",
|
39
|
-
"lib/cantango/api/can/dsl/scope.rb",
|
40
41
|
"lib/cantango/api/can/user.rb",
|
41
42
|
"lib/cantango/api/common.rb",
|
42
43
|
"lib/cantango/api/model.rb",
|
@@ -56,6 +57,11 @@ Gem::Specification.new do |s|
|
|
56
57
|
"lib/cantango/api_ext/macros/clazz.rb",
|
57
58
|
"lib/cantango/api_ext/macros/user.rb",
|
58
59
|
"spec/cantango/api/ability/account_spec.rb",
|
60
|
+
"spec/cantango/api/ability/dsl/relationship_ex.rb",
|
61
|
+
"spec/cantango/api/ability/dsl/relationship_spec.rb",
|
62
|
+
"spec/cantango/api/ability/dsl_spec.rb",
|
63
|
+
"spec/cantango/api/ability/relation_spec.rb",
|
64
|
+
"spec/cantango/api/ability/scope_spec.rb",
|
59
65
|
"spec/cantango/api/ability/user_spec.rb",
|
60
66
|
"spec/cantango/api/account_spec.rb",
|
61
67
|
"spec/cantango/api/attributes_spec.rb",
|
@@ -103,7 +109,7 @@ Gem::Specification.new do |s|
|
|
103
109
|
s.add_runtime_dependency(%q<sweetloader>, ["~> 0.1.6"])
|
104
110
|
s.add_runtime_dependency(%q<hashie>, ["~> 1.2"])
|
105
111
|
s.add_runtime_dependency(%q<cantango-config>, [">= 0.1.9.2"])
|
106
|
-
s.add_runtime_dependency(%q<cantango-core>, [">= 0.1.9.
|
112
|
+
s.add_runtime_dependency(%q<cantango-core>, [">= 0.1.9.3"])
|
107
113
|
s.add_development_dependency(%q<bundler>, [">= 1.1.rc"])
|
108
114
|
s.add_development_dependency(%q<jeweler>, [">= 1.6.4"])
|
109
115
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
@@ -114,7 +120,7 @@ Gem::Specification.new do |s|
|
|
114
120
|
s.add_dependency(%q<sweetloader>, ["~> 0.1.6"])
|
115
121
|
s.add_dependency(%q<hashie>, ["~> 1.2"])
|
116
122
|
s.add_dependency(%q<cantango-config>, [">= 0.1.9.2"])
|
117
|
-
s.add_dependency(%q<cantango-core>, [">= 0.1.9.
|
123
|
+
s.add_dependency(%q<cantango-core>, [">= 0.1.9.3"])
|
118
124
|
s.add_dependency(%q<bundler>, [">= 1.1.rc"])
|
119
125
|
s.add_dependency(%q<jeweler>, [">= 1.6.4"])
|
120
126
|
s.add_dependency(%q<rcov>, [">= 0"])
|
@@ -126,7 +132,7 @@ Gem::Specification.new do |s|
|
|
126
132
|
s.add_dependency(%q<sweetloader>, ["~> 0.1.6"])
|
127
133
|
s.add_dependency(%q<hashie>, ["~> 1.2"])
|
128
134
|
s.add_dependency(%q<cantango-config>, [">= 0.1.9.2"])
|
129
|
-
s.add_dependency(%q<cantango-core>, [">= 0.1.9.
|
135
|
+
s.add_dependency(%q<cantango-core>, [">= 0.1.9.3"])
|
130
136
|
s.add_dependency(%q<bundler>, [">= 1.1.rc"])
|
131
137
|
s.add_dependency(%q<jeweler>, [">= 1.6.4"])
|
132
138
|
s.add_dependency(%q<rcov>, [">= 0"])
|
data/lib/cantango/api/ability.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
module CanTango::Api::Ability
|
2
|
+
module Dsl
|
3
|
+
sweetload :Relationship
|
4
|
+
|
5
|
+
include Relationship
|
6
|
+
|
7
|
+
# creates a scope that enforces either using the user or user_account
|
8
|
+
# for determining relationship matches on the models
|
9
|
+
def scope name, &block
|
10
|
+
yield Scope.new name, self, &block
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module CanTango::Api::Ability::Dsl
|
2
|
+
module Relationship
|
3
|
+
def self.included(base)
|
4
|
+
::CanTango.config.user.relations.each do |relationship|
|
5
|
+
base.class_eval %{
|
6
|
+
def #{relationship}_of *models, &block
|
7
|
+
options = models.extract_options!
|
8
|
+
scope = options[:scope] || :user
|
9
|
+
relation = CanTango::Api::Ability::Relation.new :#{relationship}, self, scope, *models, &block
|
10
|
+
yield relation if block
|
11
|
+
relation
|
12
|
+
end
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
|
3
|
+
module CanTango::Api::Ability
|
4
|
+
class MissingRelationError < StandardError; end
|
5
|
+
|
6
|
+
class Relation
|
7
|
+
attr_reader :attribute, :abil, :scope, :models
|
8
|
+
|
9
|
+
include CanTango::Adaptor
|
10
|
+
include CanTango::CanCan::RuleClass
|
11
|
+
|
12
|
+
def initialize attribute, ability, scope, *models, &block
|
13
|
+
@attribute = attribute
|
14
|
+
@abil = ability
|
15
|
+
@scope = scope
|
16
|
+
@models = models
|
17
|
+
|
18
|
+
check_models
|
19
|
+
use_adaptor! self, user_scope
|
20
|
+
end
|
21
|
+
|
22
|
+
delegate :category, :any, :to => :ability
|
23
|
+
|
24
|
+
def can(action)
|
25
|
+
models.each do |model|
|
26
|
+
rules << rule_class.new(true, action, model, nil, condition_block(model))
|
27
|
+
end
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def cannot(action)
|
32
|
+
models.each do |model|
|
33
|
+
rules << rule_class.new(false, action, model, nil, condition_block(model))
|
34
|
+
end
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def condition_block model
|
41
|
+
return attribute_condition(attribute, user_scope) if model.new.respond_to?(attribute)
|
42
|
+
return include_condition(plural_attribute, user_scope) if model.new.respond_to?(plural_attribute)
|
43
|
+
end
|
44
|
+
|
45
|
+
def user_scope
|
46
|
+
@user_scope ||= (scope == :account) ? ability.account : ability.user
|
47
|
+
end
|
48
|
+
|
49
|
+
def scope_key
|
50
|
+
@scope_key ||= (scope == :account) ? :user_account : :user
|
51
|
+
end
|
52
|
+
|
53
|
+
def ability
|
54
|
+
abil.respond_to?(:ability) ? abil.ability : abil
|
55
|
+
end
|
56
|
+
|
57
|
+
def rules
|
58
|
+
ability.send :rules
|
59
|
+
end
|
60
|
+
|
61
|
+
def plural_attribute
|
62
|
+
:"#{attribute.to_s.pluralize}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_models
|
66
|
+
models.each do |model|
|
67
|
+
raise MissingRelationError, "#{model} has no :#{attribute} or :#{plural_attribute} defined" if !model.new.respond_to?(attribute) && !model.new.respond_to?(plural_attribute)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CanTango::Api::Ability
|
2
|
+
class Scope
|
3
|
+
include CanTango::Api::Ability::Dsl::Relationship
|
4
|
+
|
5
|
+
attr_reader :name, :ability
|
6
|
+
|
7
|
+
def initialize name, ability, &block
|
8
|
+
@name = name.to_sym
|
9
|
+
@ability = ability
|
10
|
+
yield self if block
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/cantango/api/can.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
shared_examples_for 'CanTango::Api::Ability::Dsl::Relationship' do
|
2
|
+
describe 'owner_of(model)' do
|
3
|
+
describe 'can' do
|
4
|
+
before do
|
5
|
+
subject.owner_of(Project).can(:edit)
|
6
|
+
end
|
7
|
+
specify { subject.can?(:edit, Project).should be_true }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'cannot' do
|
11
|
+
before do
|
12
|
+
subject.owner_of(Project).can(:edit)
|
13
|
+
end
|
14
|
+
specify { subject.can?(:edit, Project).should be_true }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'block' do
|
18
|
+
before do
|
19
|
+
subject.owner_of(Project) do |owner|
|
20
|
+
owner.can(:edit)
|
21
|
+
owner.cannot(:publish)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
specify { subject.can?(:edit, Project).should be_true }
|
25
|
+
specify { subject.can?(:publish, Project).should be_false }
|
26
|
+
specify { subject.cannot?(:publish, Project).should be_true }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'cantango/api/ability/dsl/relationship_ex'
|
3
|
+
|
4
|
+
class User
|
5
|
+
cantango
|
6
|
+
end
|
7
|
+
|
8
|
+
module CanTango::Ability
|
9
|
+
class Base
|
10
|
+
include CanTango::Api::Ability::Dsl::Relationship
|
11
|
+
|
12
|
+
def user
|
13
|
+
candidate
|
14
|
+
end
|
15
|
+
|
16
|
+
def account
|
17
|
+
candidate
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe CanTango::Api::Ability::Dsl::Relationship do
|
23
|
+
it_should_behave_like 'CanTango::Api::Ability::Dsl::Relationship' do
|
24
|
+
before do
|
25
|
+
@user = User.new 'krisy', 'krisy@gmail.com'
|
26
|
+
end
|
27
|
+
subject { CanTango::Ability::Base.new @user }
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fixtures/models'
|
3
|
+
require 'cantango/api/ability/dsl/relationship_ex'
|
4
|
+
|
5
|
+
class User
|
6
|
+
cantango
|
7
|
+
end
|
8
|
+
|
9
|
+
module CanTango::Ability
|
10
|
+
class Base
|
11
|
+
include CanTango::Api::Ability::Dsl
|
12
|
+
|
13
|
+
def user
|
14
|
+
candidate
|
15
|
+
end
|
16
|
+
|
17
|
+
def account
|
18
|
+
candidate
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe CanTango::Api::Ability::Dsl do
|
24
|
+
before do
|
25
|
+
@user = User.new 'krisy', 'krisy@gmail.com'
|
26
|
+
end
|
27
|
+
subject { CanTango::Ability::Base.new @user }
|
28
|
+
|
29
|
+
it_should_behave_like 'CanTango::Api::Ability::Dsl::Relationship'
|
30
|
+
|
31
|
+
describe 'scope name, &block' do
|
32
|
+
specify do
|
33
|
+
subject.scope :user do |scope|
|
34
|
+
scope.should be_a CanTango::Api::Ability::Scope
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fixtures/models'
|
3
|
+
|
4
|
+
class User
|
5
|
+
include_and_extend SimpleRoles
|
6
|
+
end
|
7
|
+
|
8
|
+
class Admin < User
|
9
|
+
end
|
10
|
+
|
11
|
+
CanTango.configure do |config|
|
12
|
+
config.users.register :user, User
|
13
|
+
config.users.register :admin, Admin
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'spec_helper'
|
17
|
+
require 'helpers/current_user_accounts'
|
18
|
+
|
19
|
+
module CanTango::Ability
|
20
|
+
class Base
|
21
|
+
def user
|
22
|
+
candidate
|
23
|
+
end
|
24
|
+
|
25
|
+
def account
|
26
|
+
candidate
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Context
|
32
|
+
include CanTango::Api::Ability::User
|
33
|
+
|
34
|
+
include_and_extend ::CurrentUsers
|
35
|
+
end
|
36
|
+
|
37
|
+
describe CanTango::Api::Ability::Relation do
|
38
|
+
before do
|
39
|
+
@user = User.new 'krisy', 'krisy@gmail.com'
|
40
|
+
@ability = CanTango::Ability::Base.new @user
|
41
|
+
@scope = CanTango::Api::Ability::Scope.new :user, @ability
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should raise MissingRelation error when no ownership relation on model' do
|
45
|
+
lambda {
|
46
|
+
CanTango::Api::Ability::Relation.new :owner, @ability, @scope, Post
|
47
|
+
}.should raise_error(CanTango::Api::Ability::MissingRelationError)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should NOT raise MissingRelation error when there is the ownership relation on the model' do
|
51
|
+
lambda { CanTango::Api::Ability::Relation.new :owner, @ability, @scope, Project }.should_not raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
subject { CanTango::Api::Ability::Relation.new :owner, @ability, @scope, Project }
|
55
|
+
|
56
|
+
describe 'Relation.new attribute, ability, scope, *models, &block' do
|
57
|
+
specify { subject.attribute.should == :owner }
|
58
|
+
specify { subject.abil.should == @ability }
|
59
|
+
specify { subject.scope.should == @scope }
|
60
|
+
specify { subject.models.should include Project }
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'using Adaptor' do
|
64
|
+
before do
|
65
|
+
@obj = subject.send :user_scope
|
66
|
+
end
|
67
|
+
|
68
|
+
specify { @obj.should == @user }
|
69
|
+
specify { subject.adaptor_for(@obj).should == CanTango::Adaptor::Generic }
|
70
|
+
specify { subject.adaptor_type.should == :generic }
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'can(action)' do
|
74
|
+
specify { subject.send(:rules).should be_empty }
|
75
|
+
specify { subject.can(:edit).send(:rules).should_not be_empty }
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'cannot(action)' do
|
79
|
+
specify { subject.send(:rules).should be_empty }
|
80
|
+
specify { subject.cannot(:edit).send(:rules).should_not be_empty }
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'category(action)' do
|
84
|
+
pending
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'any(action)' do
|
88
|
+
pending
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'cantango/config'
|
2
|
+
require 'fixtures/models'
|
3
|
+
|
4
|
+
class User
|
5
|
+
include_and_extend SimpleRoles
|
6
|
+
end
|
7
|
+
|
8
|
+
class Admin < User
|
9
|
+
end
|
10
|
+
|
11
|
+
CanTango.configure do |config|
|
12
|
+
config.users.register :user, User
|
13
|
+
config.users.register :admin, Admin
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'spec_helper'
|
17
|
+
require 'helpers/current_user_accounts'
|
18
|
+
|
19
|
+
class Context
|
20
|
+
include CanTango::Api::Ability::User
|
21
|
+
|
22
|
+
include_and_extend ::CurrentUsers
|
23
|
+
end
|
24
|
+
|
25
|
+
describe CanTango::Api::Ability::Scope do
|
26
|
+
subject { CanTango::Api::Ability::Scope.new :user, @ability }
|
27
|
+
|
28
|
+
describe 'attributes set on init' do
|
29
|
+
specify { subject.name.should == :user }
|
30
|
+
specify { subject.ability.should == @ability }
|
31
|
+
it 'should yield the scope' do
|
32
|
+
CanTango::Api::Ability::Scope.new(:user, @ability) do |scope|
|
33
|
+
scope.should be_a CanTango::Api::Ability::Scope
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cantango-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2011-12-09 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement: &
|
16
|
+
requirement: &70107040049300 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70107040049300
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: sugar-high
|
27
|
-
requirement: &
|
27
|
+
requirement: &70107040048740 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 0.6.2
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70107040048740
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: sweetloader
|
38
|
-
requirement: &
|
38
|
+
requirement: &70107040048000 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 0.1.6
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70107040048000
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: hashie
|
49
|
-
requirement: &
|
49
|
+
requirement: &70107040047160 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '1.2'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70107040047160
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: cantango-config
|
60
|
-
requirement: &
|
60
|
+
requirement: &70107040046020 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,21 +65,21 @@ dependencies:
|
|
65
65
|
version: 0.1.9.2
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70107040046020
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: cantango-core
|
71
|
-
requirement: &
|
71
|
+
requirement: &70107040044920 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: 0.1.9.
|
76
|
+
version: 0.1.9.3
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70107040044920
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: bundler
|
82
|
-
requirement: &
|
82
|
+
requirement: &70107040043960 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: 1.1.rc
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70107040043960
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: jeweler
|
93
|
-
requirement: &
|
93
|
+
requirement: &70107040042180 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: 1.6.4
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70107040042180
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: rcov
|
104
|
-
requirement: &
|
104
|
+
requirement: &70107040041300 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70107040041300
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: rspec
|
115
|
-
requirement: &
|
115
|
+
requirement: &70107040039440 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,7 +120,7 @@ dependencies:
|
|
120
120
|
version: 2.6.0
|
121
121
|
type: :development
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *70107040039440
|
124
124
|
description: Ability, Can, Scope, Session, User, Account and more APIs for CanTango
|
125
125
|
email: kristian@unity3d.com
|
126
126
|
executables: []
|
@@ -141,14 +141,15 @@ files:
|
|
141
141
|
- lib/cantango/api.rb
|
142
142
|
- lib/cantango/api/ability.rb
|
143
143
|
- lib/cantango/api/ability/account.rb
|
144
|
+
- lib/cantango/api/ability/dsl.rb
|
145
|
+
- lib/cantango/api/ability/dsl/relationship.rb
|
146
|
+
- lib/cantango/api/ability/relation.rb
|
147
|
+
- lib/cantango/api/ability/scope.rb
|
144
148
|
- lib/cantango/api/ability/user.rb
|
145
149
|
- lib/cantango/api/account.rb
|
146
150
|
- lib/cantango/api/attributes.rb
|
147
151
|
- lib/cantango/api/can.rb
|
148
152
|
- lib/cantango/api/can/account.rb
|
149
|
-
- lib/cantango/api/can/dsl.rb
|
150
|
-
- lib/cantango/api/can/dsl/relation.rb
|
151
|
-
- lib/cantango/api/can/dsl/scope.rb
|
152
153
|
- lib/cantango/api/can/user.rb
|
153
154
|
- lib/cantango/api/common.rb
|
154
155
|
- lib/cantango/api/model.rb
|
@@ -168,6 +169,11 @@ files:
|
|
168
169
|
- lib/cantango/api_ext/macros/clazz.rb
|
169
170
|
- lib/cantango/api_ext/macros/user.rb
|
170
171
|
- spec/cantango/api/ability/account_spec.rb
|
172
|
+
- spec/cantango/api/ability/dsl/relationship_ex.rb
|
173
|
+
- spec/cantango/api/ability/dsl/relationship_spec.rb
|
174
|
+
- spec/cantango/api/ability/dsl_spec.rb
|
175
|
+
- spec/cantango/api/ability/relation_spec.rb
|
176
|
+
- spec/cantango/api/ability/scope_spec.rb
|
171
177
|
- spec/cantango/api/ability/user_spec.rb
|
172
178
|
- spec/cantango/api/account_spec.rb
|
173
179
|
- spec/cantango/api/attributes_spec.rb
|
@@ -214,7 +220,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
214
220
|
version: '0'
|
215
221
|
segments:
|
216
222
|
- 0
|
217
|
-
hash: -
|
223
|
+
hash: -3510704107702897300
|
218
224
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
219
225
|
none: false
|
220
226
|
requirements:
|
data/lib/cantango/api/can/dsl.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
module CanTango::Api
|
2
|
-
module Can
|
3
|
-
module Dsl
|
4
|
-
autoload_modules :Relation, :Scope
|
5
|
-
|
6
|
-
def self.included(base)
|
7
|
-
::CanTango.config.user.relations.each do |relationship|
|
8
|
-
base.class_eval %{
|
9
|
-
def #{relationship}_of *models, &block
|
10
|
-
options = models.extract_options!
|
11
|
-
scope = options[:scope] || :user_account
|
12
|
-
relation = Relation.new :#{relationship}, self, scope, *models, &block
|
13
|
-
yield relation if block
|
14
|
-
relation
|
15
|
-
end
|
16
|
-
}
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# creates a scope that enforces either using the user or user_account for determining relationship matches on the models
|
21
|
-
def scope name, &block
|
22
|
-
yield Scope.new name, self, &block
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
require 'active_support/inflector'
|
2
|
-
|
3
|
-
module CanTango
|
4
|
-
module Dsl
|
5
|
-
class Relation
|
6
|
-
attr_reader :attribute, :permit, :scope, :models
|
7
|
-
|
8
|
-
include CanTango::Adaptor
|
9
|
-
include CanTango::CanCan::RuleClass
|
10
|
-
|
11
|
-
def initialize attribute, permit, scope, *models, &block
|
12
|
-
@attribute = attribute
|
13
|
-
@scope = scope
|
14
|
-
@permit = permit
|
15
|
-
@models = models
|
16
|
-
|
17
|
-
check_models
|
18
|
-
use_adaptor! self, user_scope
|
19
|
-
end
|
20
|
-
|
21
|
-
def can(action)
|
22
|
-
models.each do |model|
|
23
|
-
rules << rule_class.new(true, action, model, nil, condition_block(model))
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def cannot(action)
|
28
|
-
models.each do |model|
|
29
|
-
rules << rule_class.new(false, action, model, nil, condition_block(model))
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
protected
|
34
|
-
|
35
|
-
def condition_block model
|
36
|
-
return attribute_condition(attribute, user_scope) if model.new.respond_to?(attribute)
|
37
|
-
return include_condition(plural_attribute, user_scope) if model.new.respond_to?(plural_attribute)
|
38
|
-
end
|
39
|
-
|
40
|
-
def user_scope
|
41
|
-
@user_scope ||= (scope == :account) ? permit.user_account : permit.user
|
42
|
-
end
|
43
|
-
|
44
|
-
def scope_key
|
45
|
-
@scope_key ||= (scope == :account) ? :user_account : :user
|
46
|
-
end
|
47
|
-
|
48
|
-
def ability
|
49
|
-
permit.ability
|
50
|
-
end
|
51
|
-
|
52
|
-
def rules
|
53
|
-
ability.send :rules
|
54
|
-
end
|
55
|
-
|
56
|
-
def plural_attribute
|
57
|
-
:"#{attribute.to_s.pluralize}"
|
58
|
-
end
|
59
|
-
|
60
|
-
def check_models
|
61
|
-
models.each do |model|
|
62
|
-
raise "#{model} has no :#{attribute} or :#{plural_attribute} defined" if !model.new.respond_to?(attribute) && !model.new.respond_to?(plural_attribute)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module CanTango
|
2
|
-
module Dsl
|
3
|
-
class Scope
|
4
|
-
attr_reader :name, :permit
|
5
|
-
|
6
|
-
def initialize name, permit, &block
|
7
|
-
@name = name.to_sym
|
8
|
-
@permit = permit
|
9
|
-
end
|
10
|
-
|
11
|
-
::CanTango.config.user.relations.each do |relationship|
|
12
|
-
class_eval %{
|
13
|
-
def #{relationship}_of *models, &block
|
14
|
-
options = models.extract_options!
|
15
|
-
scope = options[:scope] || name
|
16
|
-
relation = UserRelation.new :#{relationship}, permit, scope, models, &block
|
17
|
-
yield relation if block
|
18
|
-
relation
|
19
|
-
end
|
20
|
-
}
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|