permissionable 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ac8b647c4c845648114c06ce701efeaf427a6c66
4
+ data.tar.gz: 435c2593102b61b7ec1c0ab917ae76584e1885cb
5
+ SHA512:
6
+ metadata.gz: 4995603b3f0610a7dea21aa64d7a42041de7647f4afcfc885e7d78162454b24dce81d13e78e2cc0988b3ba506b3b12f76f719c715feef7f6be51b05553d65a96
7
+ data.tar.gz: 233663404592bc6c69ae5f9f9566f4b4dde70f6ae783c3b2e672e222be38906ff31e1d9286ba9767a21f544fc1c906c36484c7ff6989a8368fa148e3c0720b9e
@@ -0,0 +1,16 @@
1
+ .bundle/
2
+ .yardoc
3
+ Gemfile.lock
4
+ _yardoc/
5
+ coverage/
6
+ doc/
7
+ pkg/
8
+ spec/reports/
9
+ tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .rspec
16
+ permissionable*.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in permissionable.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Robert Falkén
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,74 @@
1
+ # permissionable
2
+ ## Installation
3
+ TODO
4
+
5
+ ## Usage
6
+ ### Hooking up your model with permissionable super powers
7
+ Hooking up your model is as easy as including `Permissionable` and defining your permission **schema**
8
+ ```
9
+ include Permissionable
10
+ permissions read: 1,
11
+ write: 2,
12
+ delete: 3
13
+ ```
14
+
15
+ Your model doesn't have to be an ActiveRecord (AR) model, but Permissionable works out of the box with AR to persist the permissions. Just throw in a `permissions` column in the mix.
16
+ ```
17
+ class AddPermissionsToResource < ActiveRecord::Migration
18
+ def change
19
+ add_column :resources, :permissions, :integer
20
+ end
21
+ end
22
+ ```
23
+
24
+ If your're not using AR can also implement your own `#read_attribute` and `#write_attribute` methods to handle `read_attribute(:permissions)` and `write_attribute(:permissions, permissions_integer)`
25
+
26
+ ### Working with permissions
27
+ #### Check for permissions
28
+ To check if your permissionable resource has a certain permission, use the [] method which will return true or false.
29
+
30
+ For instance, to check if your user has permission to :read_books,
31
+ `user.permissions[:read_books]`
32
+
33
+ You can also specify multiple permissions, which will check to see if your resource has all of the permissions provided (I.e. it will return false if any of the permissions are missing).
34
+ `user.permissions[:read_books, :delete_books]`
35
+
36
+ **Note** if you find the permissions[:read_books, :delete_books] syntax awkward, you can also use #include?
37
+ `user.permissions.include?(:read_books, :delete_books)`
38
+
39
+ #### Add permissions
40
+ You can add permissions to your resource with the familiar "append to"-syntax. To add permissions to :read_books to your user:
41
+ `user.permissions << :read_books`
42
+
43
+ You can also add an array of permissions yo your array of permissions:
44
+ `user.permissions << [:read_books, :delete_books]`
45
+
46
+ **Note** Again, if special syntax like this isn't really your cup of tea, you can also use #add
47
+ `user.permissions.add(:read_books, :delete_books)`
48
+
49
+ #### Remove permissions
50
+ Removing permissions from your resource is pretty straight forward:
51
+ `user.permissions.remove(:delete_books)`
52
+
53
+ ### Examples
54
+ ```
55
+ class User < ActiveRecord::Base
56
+ include Permissionable
57
+
58
+ permissions read: 1,
59
+ write: 2,
60
+ delete: 3
61
+ end
62
+ ```
63
+
64
+ ```
65
+ user = User.create
66
+ user.permissions[:read] # => false
67
+ user.permissions << :read
68
+ user.permissions[:read] # => true
69
+ user.permissions[:read, :write] # => false
70
+ user.permissions << :write
71
+ user.permissions[:read, :write] # => true
72
+ user.permissions.remove(:read)
73
+ user.permissions[:read, :write] # => false
74
+ ```
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,34 @@
1
+ require "permissionable/version"
2
+ require "permissionable/permissions"
3
+
4
+ module Permissionable
5
+
6
+ def permissions
7
+ @permissions ||= Permissions.new(self)
8
+ end
9
+
10
+ # Class methods from here on
11
+ module ClassMethods
12
+ def permissions(permission_definitions)
13
+ @permissions = {}
14
+ permission_definitions.each do |permission,i|
15
+ raise 'Can not assign 0' if i == 0
16
+ raise "#{i} is not an integer" unless i.is_a?(Fixnum)
17
+ if i == 1
18
+ @permissions[permission] = 1
19
+ else
20
+ @permissions[permission] = 2**(i-1)
21
+ end
22
+ end
23
+ end
24
+
25
+ def get_permissions
26
+ @permissions || {}
27
+ end
28
+ end
29
+
30
+ # Automatically extend class methods when module is included
31
+ def self.included(base)
32
+ base.extend(ClassMethods)
33
+ end
34
+ end
@@ -0,0 +1,81 @@
1
+ module Permissionable
2
+ class Permissions
3
+ def initialize(owner)
4
+ @owner = owner
5
+ if @owner.respond_to?(:read_attribute)
6
+ @permission_integer = @owner.read_attribute(:permissions)
7
+ else
8
+ @permission_integer = 0
9
+ end
10
+ end
11
+
12
+ def to_i
13
+ @permission_integer
14
+ end
15
+
16
+ # Add new permissions
17
+ # will safely ignore any permissions already granted
18
+ # Usage:
19
+ # MyModel.last.permissions.add(:write)
20
+ # MyModel.last.permissions.add(:write, :read)
21
+ def add(*permissions)
22
+ permissions.flatten!
23
+ control_definitions(permissions)
24
+ permissions.each do |permission|
25
+ new_permission = defined_permissions[permission]
26
+ @permission_integer += new_permission unless include?(permission)
27
+ end
28
+ sync_with_owner
29
+ end
30
+ alias_method :<<, :add
31
+
32
+ # Remove existing permissions
33
+ # will safely ignore any permissions not already granted
34
+ # Usage:
35
+ # resource.permissions.remove(:write)
36
+ # resource.permissions.remove(:write, :read)
37
+ def remove(*permissions)
38
+ permissions.flatten!
39
+ control_definitions(permissions)
40
+ permissions.each do |permission|
41
+ @permission_integer -= defined_permissions[permission] if include?(permission)
42
+ end
43
+ sync_with_owner
44
+ end
45
+
46
+ # Check if resource has permission
47
+ # Usage:
48
+ # resource.permissions.include?(:write)
49
+ # resource.permissions.include?(:write, :read)
50
+ # @param *permissions [Array]
51
+ # @return [TrueClass, FalseClass]
52
+ def include?(*permissions)
53
+ permissions.flatten!
54
+ control_definitions(permissions)
55
+ # Sum the corresponding int value of all
56
+ # permissions provided in the argument list
57
+ asserted = permissions.inject(0){ |mem, permission| mem + defined_permissions[permission] }
58
+ @permission_integer & asserted == asserted
59
+ end
60
+ alias_method :[], :include?
61
+
62
+ private
63
+
64
+ def control_definitions(permissions)
65
+ permissions.each do |permission|
66
+ raise "Permission #{permission} not defined" if defined_permissions[permission].nil?
67
+ end
68
+ end
69
+
70
+ def sync_with_owner
71
+ if @owner.respond_to?(:write_attribute)
72
+ @owner.write_attribute(:permission, @permission_integer)
73
+ end
74
+ end
75
+
76
+ def defined_permissions
77
+ @owner.class.get_permissions
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,3 @@
1
+ module Permissionable
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'permissionable/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "permissionable"
8
+ spec.version = Permissionable::VERSION
9
+ spec.authors = ["Robert Falkén"]
10
+ spec.email = ["f@lken.se"]
11
+ spec.summary = "Manage and check permissions for your models"
12
+ spec.description = "Integer backed permissions, powered by bitwise comparison"
13
+ spec.homepage = "https://github.com/robertfalken/permissionable"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.3"
24
+ end
@@ -0,0 +1,10 @@
1
+ class Dummy
2
+ include Permissionable
3
+
4
+ permissions run: 1,
5
+ walk: 2,
6
+ sit: 3,
7
+ play: 4,
8
+ eat: 5
9
+
10
+ end
@@ -0,0 +1,54 @@
1
+ require 'pry'
2
+ require 'permissionable'
3
+ require 'dummy'
4
+
5
+
6
+ class FlakyDummy
7
+ include Permissionable
8
+ end
9
+
10
+ describe Permissionable do
11
+ context 'permission definitions' do
12
+ subject(:permissions) { Dummy.instance_variable_get(:@permissions) }
13
+
14
+ context 'valid' do
15
+ it { is_expected.to have_key(:run) }
16
+ it { is_expected.to have_key(:walk) }
17
+ it { is_expected.to have_key(:sit) }
18
+ it { is_expected.to have_key(:play) }
19
+ it { is_expected.to have_key(:eat) }
20
+
21
+ it 'creates a geometric sequence' do
22
+ expect(permissions[:run]).to eq(1)
23
+ expect(permissions[:walk]).to eq(2)
24
+ expect(permissions[:sit]).to eq(4)
25
+ expect(permissions[:play]).to eq(8)
26
+ expect(permissions[:eat]).to eq(16)
27
+ end
28
+ end
29
+
30
+ context 'invalid' do
31
+ it 'can not assign 0' do
32
+ expect{
33
+ FlakyDummy.permissions(nope: 0)
34
+ }.to raise_exception
35
+ end
36
+
37
+ it 'can only assign integers' do
38
+ expect{
39
+ FlakyDummy.permissions(nope: '1')
40
+ }.to raise_exception
41
+ end
42
+ end
43
+ end
44
+
45
+ context 'instance' do
46
+ it 'has permissions getter' do
47
+ dummy = Dummy.new
48
+ expect(dummy).to respond_to(:permissions)
49
+ expect(dummy.permissions).to be_an_instance_of(Permissionable::Permissions)
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,76 @@
1
+ require 'pry'
2
+ require 'permissionable'
3
+ require 'dummy'
4
+
5
+ describe Permissionable::Permissions do
6
+ before(:each) { @permissions = Permissionable::Permissions.new(Dummy.new) }
7
+
8
+ it 'implements #to_i' do
9
+ expect(@permissions.to_i).to eq(0)
10
+ end
11
+
12
+ it 'can add permission with <<' do
13
+ expect{
14
+ @permissions << :play
15
+ }.to change{@permissions.to_i}.by(8)
16
+ end
17
+
18
+ it 'can add permission with #add' do
19
+ expect{
20
+ @permissions << :walk
21
+ }.to change{@permissions.to_i}.by(2)
22
+ end
23
+
24
+ it 'can remove permission with #remove' do
25
+ @permissions << :play
26
+ expect{
27
+ @permissions.remove(:play)
28
+ }.to change{@permissions.to_i}.by(-8)
29
+ end
30
+
31
+ it 'is true with one included permission' do
32
+ @permissions << :run
33
+ expect(@permissions.include?(:run)).to be true
34
+ end
35
+
36
+ it 'is false with one missing permission' do
37
+ @permissions << :run
38
+ expect(@permissions.include?(:walk)).to be false
39
+ end
40
+
41
+ it 'is true for multiple existing permissions' do
42
+ @permissions << :run
43
+ @permissions << :walk
44
+
45
+ expect(@permissions.include?(:run, :walk)).to be true
46
+ end
47
+
48
+ it 'it is false when one of asserted is missing' do
49
+ @permissions << :run
50
+ @permissions << :walk
51
+ expect(@permissions.include?(:run, :play)).to be false
52
+ end
53
+
54
+ it 'can check with []' do
55
+ @permissions << :run
56
+ @permissions << :sit
57
+ expect(@permissions[:run]).to eq(true)
58
+ expect(@permissions[:sit, :run]).to eq(true)
59
+ expect(@permissions[:play]).to eq(false)
60
+ end
61
+
62
+ it 'writes attribute when adding permission' do
63
+ @owner = Dummy.new
64
+ @permissions = Permissionable::Permissions.new(@owner)
65
+ expect(@owner).to receive(:write_attribute).with(:permission, 2)
66
+ @permissions << :walk
67
+ end
68
+
69
+ it 'writes attribute when removing permission' do
70
+ @owner = Dummy.new
71
+ @permissions = Permissionable::Permissions.new(@owner)
72
+ @permissions << :run
73
+ expect(@owner).to receive(:write_attribute).with(:permission, 0)
74
+ @permissions.remove :run
75
+ end
76
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: permissionable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Robert Falkén
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.3'
55
+ description: Integer backed permissions, powered by bitwise comparison
56
+ email:
57
+ - f@lken.se
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/permissionable.rb
68
+ - lib/permissionable/permissions.rb
69
+ - lib/permissionable/version.rb
70
+ - permissionable.gemspec
71
+ - spec/dummy.rb
72
+ - spec/permissionable_spec.rb
73
+ - spec/permissions_spec.rb
74
+ homepage: https://github.com/robertfalken/permissionable
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.2.2
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Manage and check permissions for your models
98
+ test_files:
99
+ - spec/dummy.rb
100
+ - spec/permissionable_spec.rb
101
+ - spec/permissions_spec.rb
102
+ has_rdoc: