three 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 67be0ba30ea3e93a427626a755b1b7d68c91237f
4
- data.tar.gz: c596b7c49d054654ca1fca1601b4de14d7b791b9
3
+ metadata.gz: db0908414cedec93c7f8f5cae166fad7b1b1ef9b
4
+ data.tar.gz: 7cd6687d38c7ccc4d9ffef7daaf1d719f7b26aed
5
5
  SHA512:
6
- metadata.gz: 13ec53cbf10eb8da40fbd537951a4978989bed0e899bc27f83a8d5f5efccecac9236b515e2442be805d1cb2da8b9ceb3100f9dc050457d2e0a24be3255619969
7
- data.tar.gz: c2432f75e309ca8fc2a1095e24da1667458d7e083107eff9635b9eadb55e4f4b7bc605db2fc2ca9845b9b0155eac7d9bf5f4107e9e607ce21abfc490d8efab09
6
+ metadata.gz: aa8cbc2fc7e2289a322eadefa7dca02afe0e2cf8d16edeef25087693d0f7e6ea0a793b6ea1d4085d6ac24c08b21010525a357dcacdc532d1cdca3067f50888bf
7
+ data.tar.gz: 3a55795d388bf63dedb2403708a07dcc60ca1d0b4b16f1b4846fb80425b51ae0e59bee59d4797614571b29d8bf5f34d6e101cdc7a3db560361a4a65e1dcee1d1
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .rvmrc
2
+ .Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - "1.9.3"
3
+ - "2.0.0"
4
+ - "2.1.0"
5
+ - jruby-19mode
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ three (1.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ metaclass (0.0.4)
10
+ mocha (1.1.0)
11
+ metaclass (~> 0.0.1)
12
+ rake (10.3.2)
13
+
14
+ PLATFORMS
15
+ ruby
16
+
17
+ DEPENDENCIES
18
+ mocha
19
+ rake
20
+ three!
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2014 Darren Cauthon
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/ORIGINAL_LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011 Dmitriy Zaporozhets
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,153 @@
1
+ ## Three - an even smaller, tinier simple authorization gem for ruby
2
+
3
+ [![Build Status](https://travis-ci.org/darrencauthon/three.png)](https://travis-ci.org/darrencauthon/three)
4
+ [![Code Climate](https://codeclimate.com/github/darrencauthon/three.png)](https://codeclimate.com/github/darrencauthon/three)
5
+
6
+ This gem started as a minor fork of [six](https://github.com/randx/six), a neat, tiny authorization gem. I used six and liked it, but as small was it was I found that I needed maybe half of its code and features. So here is *three*.
7
+
8
+ **three** is a small authentication library, focused on only a few needs:
9
+
10
+ 1. Provide an open/closed method of constructing rules,
11
+ 2. Provide a way to remove permissions, and
12
+ 3. Do it as simply as possible.
13
+
14
+ ### Installation
15
+
16
+ ```ruby
17
+ gem install three
18
+ ```
19
+
20
+ ### Usage
21
+
22
+ Here's the simplest working example... a set of rules that apply for all
23
+
24
+ ```ruby
25
+ # make an object with an "allowed" method that returns an array of permissions
26
+ module Rules
27
+ def self.allowed _, _
28
+ [:edit, :delete]
29
+ end
30
+ end
31
+
32
+ # create an evaluator that can be used to evaluate rules
33
+ evaluator = Three.evaluator_for Rules
34
+
35
+ # use the evaluator to determine what's allowed or not
36
+
37
+ evaluator.allowed? nil, :edit # true
38
+ evaluator.allowed? nil, :close # false
39
+ evaluator.allowed? nil, :delete # true
40
+ ```
41
+
42
+ Unfortunately, that's not a very realistic example. We'll almost always want to evaluate the rules based on some sort of subject:
43
+
44
+ ```ruby
45
+ module AdminRules
46
+ def self.allowed user, _
47
+ return [] unless user.admin?
48
+ [:edit, :delete]
49
+ end
50
+ end
51
+
52
+ evaluator = Three.evaluator_for AdminRules
53
+
54
+ admin_user = User.new(admin: true)
55
+ not_an_admin = User.new(admin: false)
56
+
57
+ evaluator.allowed? admin_user, :edit # true
58
+ evaluator.allowed? not_an_admin_user, :edit # false
59
+ ```
60
+
61
+ See? The array of permissions returned by the "allowed" method are used to determine if a user can do something.
62
+
63
+ The rules can be compounded, like so:
64
+
65
+
66
+ ```ruby
67
+ module AdminRules
68
+ def self.allowed user, _
69
+ return [] unless user.admin?
70
+ [:edit, :delete]
71
+ end
72
+ end
73
+
74
+ module UserRules
75
+ def self.allowed user, _
76
+ return [] if user.admin?
77
+ [:view_my_account]
78
+ end
79
+ end
80
+
81
+ evaluator = Three.evaluator_for(AdminRules, UserRules)
82
+
83
+ admin_user = User.new(admin: true)
84
+ not_an_admin = User.new(admin: false)
85
+
86
+ evaluator.allowed? admin_user, :edit # true
87
+ evaluator.allowed? not_an_admin_user, :edit # false
88
+
89
+ evaluator.allowed? admin_user, :view_my_account # false
90
+ evaluator.allowed? not_an_admin_user, :view_my_account # true
91
+ ```
92
+
93
+ But what about that trailing "_" variable? That's used as an optional target, which you can use to return permissions based on the relationship between the two arguments:
94
+
95
+ ```ruby
96
+ module MovieRules
97
+ def self.allowed user, movie
98
+ if user.is_a_minor? and movie.is_rated_r
99
+ []
100
+ else
101
+ [:can_buy_the_ticket]
102
+ end
103
+ end
104
+ end
105
+
106
+ evaluator = Three.evaluator_for MovieRules
107
+
108
+ minor = User.new(minor: true)
109
+ not_a_minor = User.new(minor: false)
110
+
111
+ scary_movie = Movie.new(rating: 'R')
112
+ kids_movie = Movie.new(rating: 'PG')
113
+
114
+ evaluator.allowed? minor, :can_buy_the_ticket, scary_movie # false
115
+ evaluator.allowed? not_a_minor, :can_buy_the_ticket, scary_movie # true
116
+
117
+ evaluator.allowed? minor, :can_buy_the_ticket, kids_movie # true
118
+ evaluator.allowed? not_a_minor, :can_buy_the_ticket, kids_movie # true
119
+ ```
120
+
121
+ Only one more special thing... what if we want to right a rule that prevents something?
122
+
123
+ ```ruby
124
+ module DefaultLibraryRules
125
+ def self.allowed user, book
126
+ [:reserve_the_book]
127
+ end
128
+ end
129
+
130
+ module FinesOwedRules
131
+ def self.prevented user, _
132
+ if user.owes_fines?
133
+ [:reserve_the_book]
134
+ else
135
+ []
136
+ end
137
+ end
138
+ end
139
+
140
+ evaluator = Three.evaluator_for(DefaultLibraryRules, FinesOwedRules)
141
+
142
+ deadbeat = User.new(fines: 3.0)
143
+ responsible_citizen = User.new(fines: 0)
144
+
145
+ evaluator.allowed? deadbeat, :reserve_the_book # false
146
+ evaluator.allowed? responsible_citizen, :reserve_the_book # true
147
+
148
+ ```
149
+
150
+ The "prevented" method works just like "allowed," except that it will remove the permission from any other rule's "allowed" method.
151
+
152
+ The "prevented" method is the only only feature added with six.
153
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ task :default => [:test]
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs.push "lib"
8
+ t.test_files = FileList['spec/three/*_spec.rb', 'spec/*_spec.rb']
9
+ t.verbose = true
10
+ end
@@ -0,0 +1,71 @@
1
+ module Three
2
+
3
+ class Evaluator
4
+
5
+ def initialize(rules)
6
+ @rules = a_single_array_was_provided?(rules) ? rules[0] : rules
7
+ end
8
+
9
+ def allowed? subject, permissions_to_check, target = nil
10
+ permissions = convert_to_an_array_if_its_not permissions_to_check
11
+ these_permissions_are_allowed_for? permissions, subject, target
12
+ end
13
+
14
+ private
15
+
16
+ def rules
17
+ @rules
18
+ end
19
+
20
+ def convert_to_an_array_if_its_not potential_array
21
+ this_is_an_array?(potential_array) ? potential_array : [potential_array]
22
+ end
23
+
24
+ def these_permissions_are_allowed_for? permissions, subject, target
25
+ permissions.all? { |p| permission_included_between? p, subject, target }
26
+ end
27
+
28
+ def a_single_array_was_provided? rules
29
+ rules.count == 1 && this_is_an_array?(rules[0])
30
+ end
31
+
32
+ def this_is_an_array? thing
33
+ thing.respond_to? :each
34
+ end
35
+
36
+ def permission_included_between? permission_to_check, subject, target
37
+ allowed_permissions_for(subject, target).include? permission_to_check.to_s
38
+ end
39
+
40
+ def allowed_permissions_for subject, target
41
+ all_permissions = all_permissions_for subject, target
42
+ permissions_to_reject = permissions_to_reject_for subject, target
43
+
44
+ all_permissions - permissions_to_reject
45
+ end
46
+
47
+ def all_permissions_for subject, target
48
+ permissions = rules.map { |r| execute_rule r, :allowed, subject, target }
49
+ flatten_permissions permissions
50
+ end
51
+
52
+ def permissions_to_reject_for subject, target
53
+ permissions = rules.map { |r| execute_rule r, :prevented, subject, target }
54
+ flatten_permissions permissions
55
+ end
56
+
57
+ def execute_rule rule, method, subject, target
58
+ begin
59
+ rule.send(method, subject, target)
60
+ rescue
61
+ []
62
+ end
63
+ end
64
+
65
+ def flatten_permissions permissions
66
+ permissions.flatten.map { |a| a.to_s }
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,3 @@
1
+ module Three
2
+ VERSION = "1.0.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ require_relative '../lib/three.rb'
2
+ require 'minitest/autorun'
3
+ require 'minitest/spec'
4
+ require 'mocha/setup'
@@ -0,0 +1,237 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Three do
4
+
5
+ describe "allowed?" do
6
+
7
+ describe "there are no rules" do
8
+
9
+ let(:abilities) { Three::Evaluator.new([]) }
10
+
11
+ it "should return false" do
12
+ abilities.allowed?(nil, :does_not_matter).must_equal false
13
+ abilities.allowed?(Object.new, :something_else).must_equal false
14
+ end
15
+
16
+ end
17
+
18
+ [:one, :two].each do |permission|
19
+
20
+ describe "one rule that returns one permission" do
21
+
22
+ let(:abilities) { Three.evaluator_for([rule]) }
23
+
24
+ let(:subject) { Object.new }
25
+
26
+ let(:rule) do
27
+ o = Object.new
28
+ o.stubs(:allowed).with(subject, nil).returns [permission]
29
+ o
30
+ end
31
+
32
+ it "should return true for the allowed permission" do
33
+ abilities.allowed?(subject, permission).must_equal true
34
+ end
35
+
36
+ it "should return false for other permissions" do
37
+ abilities.allowed?(subject, :something_else).must_equal false
38
+ abilities.allowed?(subject, :another_thing).must_equal false
39
+ end
40
+
41
+ describe "with a target" do
42
+
43
+ let(:target) { Object.new }
44
+
45
+ before do
46
+ rule.stubs(:allowed).with(subject, target).returns [permission]
47
+ end
48
+
49
+ it "should return true for the allowed permission" do
50
+ abilities.allowed?(subject, permission).must_equal true
51
+ end
52
+
53
+ it "should return true if asked for the permission in an array" do
54
+ abilities.allowed?(subject, [permission]).must_equal true
55
+ end
56
+
57
+ it "should return false for other permissions" do
58
+ abilities.allowed?(subject, :something).must_equal false
59
+ abilities.allowed?(subject, :another).must_equal false
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ describe "one rule that returns two permissions" do
69
+
70
+ let(:abilities) { Three.evaluator_for([rule]) }
71
+
72
+ let(:subject) { Object.new }
73
+
74
+ let(:rule) do
75
+ o = Object.new
76
+ o.stubs(:allowed).with(subject, nil).returns [:orange, :banana]
77
+ o
78
+ end
79
+
80
+ it "should return true if asked for either, alone" do
81
+ abilities.allowed?(subject, :orange).must_equal true
82
+ abilities.allowed?(subject, :banana).must_equal true
83
+ end
84
+
85
+ it "should return true if asked for both at the same time" do
86
+ abilities.allowed?(subject, [:orange, :banana]).must_equal true
87
+ end
88
+
89
+ it "should return true if asked for one and another that does not match" do
90
+ abilities.allowed?(subject, [:orange, :apple]).must_equal false
91
+ abilities.allowed?(subject, [:pear, :banana]).must_equal false
92
+ end
93
+
94
+ it "should return false for other permissions" do
95
+ abilities.allowed?(subject, :apple).must_equal false
96
+ abilities.allowed?(subject, :pear).must_equal false
97
+ end
98
+
99
+ end
100
+
101
+ describe "two rules that return one permission each" do
102
+
103
+ let(:abilities) { Three.evaluator_for([rule1, rule2]) }
104
+
105
+ let(:subject) { Object.new }
106
+
107
+ let(:rule1) do
108
+ o = Object.new
109
+ o.stubs(:allowed).with(subject, nil).returns [:orange]
110
+ o
111
+ end
112
+
113
+ let(:rule2) do
114
+ o = Object.new
115
+ o.stubs(:allowed).with(subject, nil).returns [:banana]
116
+ o
117
+ end
118
+
119
+ it "should return true if asked for either, alone" do
120
+ abilities.allowed?(subject, :orange).must_equal true
121
+ abilities.allowed?(subject, :banana).must_equal true
122
+ end
123
+
124
+ it "should return true if asked for both at the same time" do
125
+ abilities.allowed?(subject, [:orange, :banana]).must_equal true
126
+ end
127
+
128
+ it "should return true if asked for one and another that does not match" do
129
+ abilities.allowed?(subject, [:orange, :apple]).must_equal false
130
+ abilities.allowed?(subject, [:pear, :banana]).must_equal false
131
+ end
132
+
133
+ it "should return false for other permissions" do
134
+ abilities.allowed?(subject, :apple).must_equal false
135
+ abilities.allowed?(subject, :pear).must_equal false
136
+ end
137
+
138
+ end
139
+
140
+ describe "rejecting permissions" do
141
+
142
+ let(:abilities) { Three.evaluator_for([rule1, rule2]) }
143
+
144
+ let(:subject) { Object.new }
145
+
146
+ let(:rule1) do
147
+ o = Object.new
148
+ o.stubs(:allowed).with(subject, nil).returns [:orange, :banana]
149
+ o.stubs(:prevented).with(subject, nil).returns [:apple]
150
+ o
151
+ end
152
+
153
+ let(:rule2) do
154
+ o = Object.new
155
+ o.stubs(:allowed).with(subject, nil).returns [:apple, :pear]
156
+ o.stubs(:prevented).with(subject, nil).returns [:banana]
157
+ o
158
+ end
159
+
160
+ it "should return false for the permissions that are prevented" do
161
+ abilities.allowed?(subject, :banana).must_equal false
162
+ abilities.allowed?(subject, :apple).must_equal false
163
+ end
164
+
165
+ it "should return true for the permissions that are not prevented" do
166
+ abilities.allowed?(subject, :pear).must_equal true
167
+ abilities.allowed?(subject, :orange).must_equal true
168
+ end
169
+
170
+ describe "with a target" do
171
+
172
+ let(:target) { Object.new }
173
+
174
+ before do
175
+ rule1.stubs(:allowed).with(subject, target).returns [:orange, :banana]
176
+ rule1.stubs(:prevented).with(subject, target).returns [:apple]
177
+
178
+ rule2.stubs(:allowed).with(subject, target).returns [:apple, :pear]
179
+ rule2.stubs(:prevented).with(subject, target).returns [:banana]
180
+ end
181
+
182
+ it "should return false for the permissions that are prevented" do
183
+ abilities.allowed?(subject, :banana, target).must_equal false
184
+ abilities.allowed?(subject, :apple, target).must_equal false
185
+ end
186
+
187
+ it "should return true for the permissions that are not prevented" do
188
+ abilities.allowed?(subject, :pear, target).must_equal true
189
+ abilities.allowed?(subject, :orange, target).must_equal true
190
+ end
191
+ end
192
+
193
+ end
194
+
195
+ describe "alternate constructor" do
196
+
197
+ let(:abilities) { Three.evaluator_for(rule1, rule2) }
198
+
199
+ let(:subject) { Object.new }
200
+
201
+ let(:rule1) do
202
+ o = Object.new
203
+ o.stubs(:allowed).with(subject, nil).returns [:orange, :banana]
204
+ o.stubs(:prevented).with(subject, nil).returns [:apple]
205
+ o
206
+ end
207
+
208
+ let(:rule2) do
209
+ o = Object.new
210
+ o.stubs(:allowed).with(subject, nil).returns [:apple, :pear]
211
+ o.stubs(:prevented).with(subject, nil).returns [:banana]
212
+ o
213
+ end
214
+
215
+ it "should return false for the permissions that are prevented" do
216
+ abilities.allowed?(subject, :banana).must_equal false
217
+ abilities.allowed?(subject, :apple).must_equal false
218
+ end
219
+
220
+ it "should return true for the permissions that are not prevented" do
221
+ abilities.allowed?(subject, :pear).must_equal true
222
+ abilities.allowed?(subject, :orange).must_equal true
223
+ end
224
+
225
+ end
226
+
227
+ describe "no rules provided" do
228
+ it "should return false for everything" do
229
+ abilities = Three::Evaluator.new([])
230
+ abilities.allowed?(Object.new, :anything).must_equal false
231
+ abilities.allowed?(Object.new, :anything, Object.new).must_equal false
232
+ end
233
+ end
234
+
235
+ end
236
+
237
+ end
data/three.gemspec ADDED
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/three/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'three'
6
+ s.version = Three::VERSION
7
+ s.date = '2014-06-16'
8
+ s.summary = "three"
9
+ s.description = "Even simpler authorization gem"
10
+ s.authors = ["Darren Cauthon"]
11
+ s.email = 'darren@cauthon.com'
12
+ s.files = `git ls-files`.split($/)
13
+ s.homepage = 'https://github.com/darrencauthon/three'
14
+
15
+ s.add_development_dependency 'mocha'
16
+ s.add_development_dependency 'rake'
17
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: three
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darren Cauthon
@@ -44,7 +44,21 @@ executables: []
44
44
  extensions: []
45
45
  extra_rdoc_files: []
46
46
  files:
47
+ - .gitignore
48
+ - .rspec
49
+ - .travis.yml
50
+ - Gemfile
51
+ - Gemfile.lock
52
+ - LICENSE
53
+ - ORIGINAL_LICENSE
54
+ - README.markdown
55
+ - Rakefile
47
56
  - lib/three.rb
57
+ - lib/three/evaluator.rb
58
+ - lib/three/version.rb
59
+ - spec/spec_helper.rb
60
+ - spec/three_spec.rb
61
+ - three.gemspec
48
62
  homepage: https://github.com/darrencauthon/three
49
63
  licenses: []
50
64
  metadata: {}
@@ -64,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
78
  version: '0'
65
79
  requirements: []
66
80
  rubyforge_project:
67
- rubygems_version: 2.2.2
81
+ rubygems_version: 2.0.14
68
82
  signing_key:
69
83
  specification_version: 4
70
84
  summary: three