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