authority 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -12,4 +12,4 @@ gemfile:
12
12
  - gemfiles/3.0.gemfile
13
13
  - gemfiles/3.1.gemfile
14
14
  - gemfiles/3.2.gemfile
15
- - Gemfile
15
+ - Gemfile
data/README.markdown CHANGED
@@ -22,6 +22,7 @@ It requires that you already have some kind of user object in your application,
22
22
  <li><a href="#models">Models</a></li>
23
23
  <li><a href="#authorizers">Authorizers</a>
24
24
  <ul>
25
+ <li><a href="#passing_options">Passing Options</a></li>
25
26
  <li><a href="#default_methods">Default methods</a></li>
26
27
  <li><a href="#testing_authorizers">Testing Authorizers</a></li>
27
28
  </ul></li>
@@ -36,18 +37,32 @@ It requires that you already have some kind of user object in your application,
36
37
  <a name="overview">
37
38
  ## Overview
38
39
 
39
- The goals of Authority are:
40
+ Using Authority, you have:
40
41
 
41
- - To allow broad, **class-level** rules. Examples:
42
+ - Broad, **class-level** rules. Examples:
42
43
  - "Basic users cannot delete any Widget."
43
44
  - "Only admin users can create Offices."
44
- - To allow fine-grained, **instance-level** rules. Examples:
45
+ - Fine-grained, **instance-level** rules. Examples:
45
46
  - "Management users can only edit schedules with date ranges in the future."
46
47
  - "Users can't create playlists more than 20 songs long unless they've paid."
47
- - To provide a clear syntax for permissions-based views. Example:
48
+ - A clear syntax for permissions-based views. Example:
48
49
  - `link_to 'Edit Widget', edit_widget_path(@widget) if current_user.can_update?(@widget)`
49
- - To gracefully handle any access violations: by default, it displays a "you can't do that" screen and logs the violation.
50
- - To do all this with minimal effort and mess.
50
+ - Graceful handling of access violations: by default, it displays a "you can't do that" screen and logs the violation.
51
+ - Minimal effort and mess.
52
+
53
+ Most importantly, you have **total flexibility**: Authority does not constrain you into using a particular scheme of roles and/or permissions.
54
+
55
+ Authority lets you:
56
+
57
+ - Grant permissions based on users' points (like StackOverflow)
58
+ - Check user roles in a separate, single-sign-on app
59
+ - Disallow certain actions based on time or date
60
+ - Allow an action only for users with compatible browsers
61
+ - ...do anything else you can think of.
62
+
63
+ All you have to do is define the methods you need on your authorizers. You have all the flexibility of normal Ruby classes.
64
+
65
+ **You** make the rules; Authority enforces them.
51
66
 
52
67
  <a name="flow_of_authority">
53
68
  ## The flow of Authority
@@ -180,6 +195,29 @@ ScheduleAuthorizer.updatable_by?(user)
180
195
 
181
196
  As you can see, you can specify different logic for every method on every model, if necessary. On the other extreme, you could simply supply a [default method](#default_methods) that covers all your use cases.
182
197
 
198
+ <a name="passing_options">
199
+ #### Passing Options
200
+
201
+ Any options you pass when checking permissions will be passed right up the chain. One use case for this would be if you needed an associated instance in order to do a class-level check. For example:
202
+
203
+ ```ruby
204
+ # I don't have a comment instance to check, but I need to know
205
+ # which post the user wants to comment on
206
+ user.can_create?(Comment, :for => @post)
207
+ ```
208
+
209
+ This would ultimately call `creatable_by?` on the designated authorizer with two arguments: the user and `{:for => @post}`. If you've defined that method yourself, you'd need to ensure that it accepts the options hash before doing this, or you'd get a "wrong number of arguments" error.
210
+
211
+ There's nothing special about the hash key `:for`; I just think it reads well in this case. You can pass any options that make sense in your case.
212
+
213
+ If you **don't** pass options, none will be passed to your authorizer, either.
214
+
215
+ And you could always handle the case above without options if you don't mind creating an extra model instance:
216
+
217
+ ```ruby
218
+ user.can_create?(Comment.new(:post => @post))
219
+ ```
220
+
183
221
  <a name="default_methods">
184
222
  #### Default Methods
185
223
 
@@ -361,18 +399,36 @@ Your method will be handed the `SecurityViolation`, which has a `message` method
361
399
  - [TMA](http://www.tma1.com) for employing me and letting me open source some of our code.
362
400
 
363
401
  <a name="contributing">
402
+
403
+ ## Responses, AKA 'Hollaback'
404
+
405
+ Do you like Authority? Has it cleaned up your code, made you more personable, and taught you the Secret to True Happiness? Awesome! I'd **love** to get email from you - see my Github profile for the address.
406
+
364
407
  ## Contributing
365
408
 
366
- What should you contribute? Try the TODO file for ideas, or grep the project for 'TODO' comments.
409
+ How can you contribute? Let me count the ways.
410
+
411
+ ### 1. Publicity
412
+
413
+ If you like Authority, tell people! Blog, tweet, comment, or even... [shudder]... talk with people *in person*. If you feel up to it, I mean. It's OK if you don't.
414
+
415
+ ### 2. Documentation
416
+
417
+ Add examples to the [wiki](http://github.com/nathanl/authority/wiki) to help others solve problems like yours.
418
+
419
+ ### 3. Issues
420
+
421
+ Tell me your problems and/or ideas.
367
422
 
368
- How can you contribute?
423
+ ### 4. Code or documentation
369
424
 
370
- 1. Let's talk! Before you do a bunch of work, open an issue so we can be sure we agree.
371
- 2. Fork this project
372
- 3. Create your feature branch (`git checkout -b my-new-feature`)
373
- 4. `bundle install` to get all dependencies
374
- 5. `rspec spec` to run all tests.
375
- 6. Update/add tests for your changes and code until they pass.
376
- 7. Commit your changes (`git commit -am 'Added some feature'`)
377
- 8. Push to the branch (`git push origin my-new-feature`)
378
- 9. Create a new Pull Request
425
+ 1. Have an idea. If you don't have one, check the TODO file or grep the project for 'TODO' comments.
426
+ 2. Open an issue so we can talk it over.
427
+ 3. Fork this project
428
+ 4. Create your feature branch (`git checkout -b my-new-feature`)
429
+ 5. `bundle install` to get all dependencies
430
+ 6. `rspec spec` to run all tests.
431
+ 7. Update/add tests for your changes and code until they pass.
432
+ 8. Commit your changes (`git commit -am 'Added some feature'`)
433
+ 9. Push to the branch (`git push origin my-new-feature`)
434
+ 10. Create a new Pull Request
data/TODO.markdown CHANGED
@@ -5,7 +5,9 @@
5
5
  - Add tests for the generators
6
6
  - Test `ActionController` integration
7
7
 
8
- ## Documentation
9
-
10
8
  ## Features
11
9
 
10
+ ### Use translation files
11
+
12
+ - Move all user-facing messages into en.yml
13
+ - Add other languages
@@ -21,8 +21,12 @@ module Authority
21
21
  Authority.adjectives.each do |adjective|
22
22
 
23
23
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
24
- def #{adjective}_by?(user)
25
- authorizer.#{adjective}_by?(user)
24
+ def #{adjective}_by?(user, options = {})
25
+ if options.empty?
26
+ authorizer.#{adjective}_by?(user)
27
+ else
28
+ authorizer.#{adjective}_by?(user, options)
29
+ end
26
30
  end
27
31
  RUBY
28
32
  end
@@ -38,8 +42,12 @@ module Authority
38
42
  Authority.adjectives.each do |adjective|
39
43
 
40
44
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
41
- def #{adjective}_by?(user)
42
- authorizer.#{adjective}_by?(user)
45
+ def #{adjective}_by?(user, options = {})
46
+ if options.empty?
47
+ authorizer.#{adjective}_by?(user)
48
+ else
49
+ authorizer.#{adjective}_by?(user, options)
50
+ end
43
51
  end
44
52
 
45
53
  def authorizer
@@ -17,8 +17,12 @@ module Authority
17
17
  # Each instance method simply calls the corresponding class method
18
18
  Authority.adjectives.each do |adjective|
19
19
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
20
- def #{adjective}_by?(user)
21
- self.class.#{adjective}_by?(user)
20
+ def #{adjective}_by?(user, options = {})
21
+ if options.empty?
22
+ self.class.#{adjective}_by?(user)
23
+ else
24
+ self.class.#{adjective}_by?(user, options)
25
+ end
22
26
  end
23
27
  RUBY
24
28
  end
@@ -26,14 +30,18 @@ module Authority
26
30
  # Each class method simply calls the `default` method
27
31
  Authority.adjectives.each do |adjective|
28
32
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
29
- def self.#{adjective}_by?(user)
30
- default(:#{adjective}, user)
33
+ def self.#{adjective}_by?(user, options = {})
34
+ if options.empty?
35
+ default(:#{adjective}, user)
36
+ else
37
+ default(:#{adjective}, user, options)
38
+ end
31
39
  end
32
40
  RUBY
33
41
  end
34
42
 
35
43
  # Whitelisting approach: anything not specified will be forbidden
36
- def self.default(adjective, user)
44
+ def self.default(adjective, user, options = {})
37
45
  false
38
46
  end
39
47
 
@@ -10,8 +10,12 @@ module Authority
10
10
 
11
11
  Authority.verbs.each do |verb|
12
12
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
13
- def can_#{verb}?(resource)
14
- resource.#{Authority.abilities[verb]}_by?(self)
13
+ def can_#{verb}?(resource, options = {})
14
+ if options.empty?
15
+ resource.#{Authority.abilities[verb]}_by?(self)
16
+ else
17
+ resource.#{Authority.abilities[verb]}_by?(self, options)
18
+ end
15
19
  end
16
20
  RUBY
17
21
  end
@@ -1,3 +1,3 @@
1
1
  module Authority
2
- VERSION = "2.0.1"
2
+ VERSION = "2.1.0"
3
3
  end
@@ -52,9 +52,22 @@ describe Authority::Abilities do
52
52
  AbilityModel.should respond_to(method_name)
53
53
  end
54
54
 
55
- it "should delegate `#{method_name}` to its authorizer class" do
56
- AbilityModel.authorizer.should_receive(method_name).with(@user)
57
- AbilityModel.send(method_name, @user)
55
+ describe "if given an options hash" do
56
+
57
+ it "should delegate `#{method_name}` to its authorizer class, passing the options" do
58
+ AbilityModel.authorizer.should_receive(method_name).with(@user, :lacking => 'nothing')
59
+ AbilityModel.send(method_name, @user, :lacking => 'nothing')
60
+ end
61
+
62
+ end
63
+
64
+ describe "if not given an options hash" do
65
+
66
+ it "should delegate `#{method_name}` to its authorizer class, passing no options" do
67
+ AbilityModel.authorizer.should_receive(method_name).with(@user)
68
+ AbilityModel.send(method_name, @user)
69
+ end
70
+
58
71
  end
59
72
 
60
73
  end
@@ -75,10 +88,24 @@ describe Authority::Abilities do
75
88
  @ability_model.should respond_to(method_name)
76
89
  end
77
90
 
78
- it "should delegate `#{method_name}` to a new authorizer instance" do
79
- AbilityModel.authorizer.stub(:new).and_return(@authorizer)
80
- @authorizer.should_receive(method_name).with(@user)
81
- @ability_model.send(method_name, @user)
91
+ describe "if given an options hash" do
92
+
93
+ it "should delegate `#{method_name}` to a new authorizer instance, passing the options" do
94
+ AbilityModel.authorizer.stub(:new).and_return(@authorizer)
95
+ @authorizer.should_receive(method_name).with(@user, :with => 'mayo')
96
+ @ability_model.send(method_name, @user, :with => 'mayo')
97
+ end
98
+
99
+ end
100
+
101
+ describe "if not given an options hash" do
102
+
103
+ it "should delegate `#{method_name}` to a new authorizer instance, passing no options" do
104
+ AbilityModel.authorizer.stub(:new).and_return(@authorizer)
105
+ @authorizer.should_receive(method_name).with(@user)
106
+ @ability_model.send(method_name, @user)
107
+ end
108
+
82
109
  end
83
110
 
84
111
  end
@@ -23,9 +23,23 @@ describe Authority::Authorizer do
23
23
  @authorizer.should respond_to(method_name)
24
24
  end
25
25
 
26
- it "should delegate `#{method_name}` to the corresponding class method by default" do
27
- @authorizer.class.should_receive(method_name).with(@user)
28
- @authorizer.send(method_name, @user)
26
+
27
+ describe "if given an options hash" do
28
+
29
+ it "should delegate `#{method_name}` to the corresponding class method, passing the options" do
30
+ @authorizer.class.should_receive(method_name).with(@user, :under => 'God')
31
+ @authorizer.send(method_name, @user, :under => 'God')
32
+ end
33
+
34
+ end
35
+
36
+ describe "if not given an options hash" do
37
+
38
+ it "should delegate `#{method_name}` to the corresponding class method, passing no options" do
39
+ @authorizer.class.should_receive(method_name).with(@user)
40
+ @authorizer.send(method_name, @user)
41
+ end
42
+
29
43
  end
30
44
 
31
45
  end
@@ -41,10 +55,24 @@ describe Authority::Authorizer do
41
55
  Authority::Authorizer.should respond_to(method_name)
42
56
  end
43
57
 
44
- it "should delegate `#{method_name}` to the authorizer's `default` method by default" do
45
- able = method_name.sub('_by?', '').to_sym
46
- Authority::Authorizer.should_receive(:default).with(able, @user)
47
- Authority::Authorizer.send(method_name, @user)
58
+ describe "if given an options hash" do
59
+
60
+ it "should delegate `#{method_name}` to the authorizer's `default` method, passing the options" do
61
+ able = method_name.sub('_by?', '').to_sym
62
+ Authority::Authorizer.should_receive(:default).with(able, @user, :with => 'gusto')
63
+ Authority::Authorizer.send(method_name, @user, :with => 'gusto')
64
+ end
65
+
66
+ end
67
+
68
+ describe "if not given an options hash" do
69
+
70
+ it "should delegate `#{method_name}` to the authorizer's `default` method, passing no options" do
71
+ able = method_name.sub('_by?', '').to_sym
72
+ Authority::Authorizer.should_receive(:default).with(able, @user)
73
+ Authority::Authorizer.send(method_name, @user)
74
+ end
75
+
48
76
  end
49
77
 
50
78
  end
@@ -53,8 +81,19 @@ describe Authority::Authorizer do
53
81
 
54
82
  describe "the default method" do
55
83
 
56
- it "should return false" do
57
- Authority::Authorizer.default(:implodable, @user).should be_false
84
+ describe "if given an options hash" do
85
+
86
+ it "should return false" do
87
+ Authority::Authorizer.default(:implodable, @user, {:for => "my_object"}).should be_false
88
+ end
89
+ end
90
+
91
+ describe "if not given an options hash" do
92
+
93
+ it "should return false" do
94
+ Authority::Authorizer.default(:implodable, @user).should be_false
95
+ end
96
+
58
97
  end
59
98
 
60
99
  end
@@ -16,10 +16,24 @@ describe Authority::UserAbilities do
16
16
  @user.should respond_to(method_name)
17
17
  end
18
18
 
19
- it "should delegate the authorization check to the resource provided" do
20
- @ability_model.should_receive("#{Authority.abilities[verb]}_by?").with(@user)
21
- @user.send(method_name, @ability_model)
19
+ describe "if given options" do
20
+
21
+ it "should delegate the authorization check to the resource, passing the options" do
22
+ @ability_model.should_receive("#{Authority.abilities[verb]}_by?").with(@user, :size => 'wee')
23
+ @user.send(method_name, @ability_model, :size => 'wee')
24
+ end
25
+
22
26
  end
27
+
28
+ describe "if not given options" do
29
+
30
+ it "should delegate the authorization check to the resource, passing no options" do
31
+ @ability_model.should_receive("#{Authority.abilities[verb]}_by?").with(@user)
32
+ @user.send(method_name, @ability_model)
33
+ end
34
+
35
+ end
36
+
23
37
  end
24
38
 
25
39
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authority
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-06-16 00:00:00.000000000 Z
13
+ date: 2012-08-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
17
- requirement: &75848730 !ruby/object:Gem::Requirement
17
+ requirement: &2160582080 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,7 +22,7 @@ dependencies:
22
22
  version: 3.0.0
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *75848730
25
+ version_requirements: *2160582080
26
26
  description: Authority helps you authorize actions in your Rails app. It's ORM-neutral
27
27
  and has very little fancy syntax; just group your models under one or more Authorizer
28
28
  classes and write plain Ruby methods on them.
@@ -90,9 +90,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
90
  version: '0'
91
91
  requirements: []
92
92
  rubyforge_project:
93
- rubygems_version: 1.8.10
93
+ rubygems_version: 1.8.16
94
94
  signing_key:
95
95
  specification_version: 3
96
96
  summary: Authority helps you authorize actions in your Rails app using plain Ruby
97
97
  methods on Authorizer classes.
98
- test_files: []
98
+ test_files:
99
+ - spec/authority/abilities_spec.rb
100
+ - spec/authority/authorizer_spec.rb
101
+ - spec/authority/configuration_spec.rb
102
+ - spec/authority/controller_spec.rb
103
+ - spec/authority/user_abilities_spec.rb
104
+ - spec/authority_spec.rb
105
+ - spec/spec_helper.rb
106
+ - spec/support/ability_model.rb
107
+ - spec/support/example_controllers.rb
108
+ - spec/support/mock_rails.rb
109
+ - spec/support/user.rb