cantango-api 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -7,7 +7,7 @@ group :default do
7
7
  gem 'hashie', '~> 1.2'
8
8
 
9
9
  gem 'cantango-config', '>= 0.1.9.2'
10
- gem 'cantango-core', '>= 0.1.9.2'
10
+ gem 'cantango-core', '>= 0.1.9.3'
11
11
  end
12
12
 
13
13
  group :development do
@@ -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.2)
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.2)
140
+ cantango-core (>= 0.1.9.3)
141
141
  cantango-masquerade (>= 0.1.3.2)
142
142
  cutter
143
143
  database_cleaner
@@ -2,9 +2,10 @@
2
2
 
3
3
  The main API for [CanTango](https://github.com/kristianmandrup/cantango)
4
4
 
5
- ## Status: Dec 1 2011
5
+ ## Status: Dec 9 2011
6
6
 
7
- The API is being spec'ed...
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
- * Macros
16
- * User
16
+ Macro modules
17
+
18
+ * CanTango::Api::Macros::
17
19
  * Account
20
+ * User
21
+ * Clazz
18
22
 
19
- These macros allow registration os CanTango User and Account models.
23
+ These macro modules allow registration of CanTango User and Account models.
20
24
 
21
- Usage example:
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
- tango_user
48
+ tango_user
26
49
  end
27
50
 
28
51
  class Admin
29
- tango_user
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
- tango_account
67
+ cantango
34
68
  end
35
69
 
36
- class AdminAccount
37
- tango_account
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
- * Ability
46
- * Can
47
- * Model
48
- * Scope
49
- * Session
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
- ### Can API
93
+ ## Ability
54
94
 
55
- * Dsl
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
- ## Model APIs
104
+ ### Account
105
+
106
+ ```ruby
107
+ account_ability(current_account)
108
+ current_account_ability(:admin)
109
+ ```
110
+
111
+ ### User
62
112
 
63
- * Account
64
- * User
113
+ ```ruby
114
+ user_ability(current_user)
115
+ current_user_ability(:editor)
116
+ ```
65
117
 
66
- Use by including the `All` module
118
+ ### Dsl
67
119
 
68
- Usage example:
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
- class User
72
- include Cantango::Api::User::All
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
- Note: The `tango_user` and `tango_account` macros should include the relevant All module.
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.2
1
+ 0.1.3
@@ -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.2"
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.2"])
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.2"])
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.2"])
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"])
@@ -1,5 +1,5 @@
1
1
  module CanTango::Api
2
2
  module Ability
3
- autoload_modules :User, :Account
3
+ autoload_modules :User, :Account, :Dsl, :Relation, :Scope
4
4
  end
5
5
  end
@@ -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
@@ -1,5 +1,5 @@
1
1
  module CanTango::Api
2
2
  module Can
3
- autoload_modules :User, :Account, :Dsl
3
+ autoload_modules :User, :Account
4
4
  end
5
5
  end
@@ -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
@@ -1,2 +1,11 @@
1
1
  class Project #< ActiveRecord::Base
2
+ attr_accessor :user
3
+
4
+ def create user
5
+ @user = user
6
+ end
7
+
8
+ def owner
9
+ user
10
+ end
2
11
  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.2
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: &70276899472420 !ruby/object:Gem::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: *70276899472420
24
+ version_requirements: *70107040049300
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: sugar-high
27
- requirement: &70276899471460 !ruby/object:Gem::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: *70276899471460
35
+ version_requirements: *70107040048740
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: sweetloader
38
- requirement: &70276899469500 !ruby/object:Gem::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: *70276899469500
46
+ version_requirements: *70107040048000
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: hashie
49
- requirement: &70276899467420 !ruby/object:Gem::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: *70276899467420
57
+ version_requirements: *70107040047160
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: cantango-config
60
- requirement: &70276899465860 !ruby/object:Gem::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: *70276899465860
68
+ version_requirements: *70107040046020
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: cantango-core
71
- requirement: &70276899461080 !ruby/object:Gem::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.2
76
+ version: 0.1.9.3
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *70276899461080
79
+ version_requirements: *70107040044920
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: bundler
82
- requirement: &70276899459540 !ruby/object:Gem::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: *70276899459540
90
+ version_requirements: *70107040043960
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: jeweler
93
- requirement: &70276899457320 !ruby/object:Gem::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: *70276899457320
101
+ version_requirements: *70107040042180
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: rcov
104
- requirement: &70276899456140 !ruby/object:Gem::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: *70276899456140
112
+ version_requirements: *70107040041300
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: rspec
115
- requirement: &70276899455300 !ruby/object:Gem::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: *70276899455300
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: -1309343168374128705
223
+ hash: -3510704107702897300
218
224
  required_rubygems_version: !ruby/object:Gem::Requirement
219
225
  none: false
220
226
  requirements:
@@ -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