sevn 0.0.0 → 0.0.1
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.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.gitignore +42 -0
- data/.travis.yml +7 -0
- data/CHANGELOG +4 -0
- data/Gemfile +4 -0
- data/Guardfile +9 -0
- data/LICENSE +23 -0
- data/README.md +3 -0
- data/lib/sevn/ability.rb +138 -0
- data/lib/sevn/constants.rb +12 -0
- data/lib/sevn/errors.rb +36 -0
- data/lib/sevn/rules_pack.rb +73 -0
- data/lib/sevn/version.rb +3 -0
- data/lib/sevn.rb +4 -0
- data/sevn.gemspec +28 -0
- data/spec/sevn_initialize_spec.rb +36 -0
- data/spec/sevn_rules_packs_spec.rb +33 -0
- data/spec/sevn_spec.rb +10 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/author.rb +7 -0
- data/spec/support/book.rb +11 -0
- data/spec/support/book_rules.rb +14 -0
- data/spec/support/valid_abilities_example.rb +52 -0
- metadata +119 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ea1db10a6fd23625dc64c16c7576ce504b45196
|
4
|
+
data.tar.gz: 20015ee56eaa39af5f0843818dedf45acb3ba97a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 690a4b61162d2d1aad37f856b55da8d96f8f281110d2f3c0339f1a525fa62405420e8cdd175a62f17c2e3b66e22c870ad00fa0c9df1fcaef000c033d6f5c2cf6
|
7
|
+
data.tar.gz: 2e108d7f82b9dbe5e31d7767f51f04dcf7071297c3210a3f6ebd95408bc057c86d0ed65e24931be0e301b5e5a5bdbdc834a4c60715fb6ac7d62c07a46eb4cf92
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.gitignore
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
Gemfile.lock
|
12
|
+
|
13
|
+
## Specific to RubyMotion:
|
14
|
+
.dat*
|
15
|
+
.repl_history
|
16
|
+
build/
|
17
|
+
|
18
|
+
## Documentation cache and generated files:
|
19
|
+
/.yardoc/
|
20
|
+
/_yardoc/
|
21
|
+
/doc/
|
22
|
+
/rdoc/
|
23
|
+
|
24
|
+
## Environment normalisation:
|
25
|
+
/.bundle/
|
26
|
+
/vendor/bundle
|
27
|
+
/lib/bundler/man/
|
28
|
+
|
29
|
+
# for a library or gem, you might want to ignore these files since the code is
|
30
|
+
# intended to run in multiple environments; otherwise, check them in:
|
31
|
+
# Gemfile.lock
|
32
|
+
# .ruby-version
|
33
|
+
# .ruby-gemset
|
34
|
+
|
35
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
36
|
+
.rvmrc
|
37
|
+
|
38
|
+
# IDE
|
39
|
+
/.idea
|
40
|
+
|
41
|
+
# MAC
|
42
|
+
*.DS_Store
|
data/.travis.yml
ADDED
data/CHANGELOG
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2011 Dmitriy Zaporozhets
|
4
|
+
Copyright (c) 2015 Miguel Angel Cervera Castaldi
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
23
|
+
|
data/README.md
ADDED
data/lib/sevn/ability.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
module Sevn
|
2
|
+
class Ability
|
3
|
+
# Initialize ability object
|
4
|
+
#
|
5
|
+
# == Parameters:
|
6
|
+
# packs::
|
7
|
+
# A Hash or rules to add with initialization
|
8
|
+
#
|
9
|
+
# == Returns:
|
10
|
+
# self
|
11
|
+
#
|
12
|
+
def initialize(packs={})
|
13
|
+
raise Sevn::Errors::InitializeArgumentError.new unless packs.kind_of?(Hash)
|
14
|
+
|
15
|
+
@rules_packs = {}
|
16
|
+
|
17
|
+
packs.each { |name, pack| add_pack(name, pack) }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Check if +object+ can do +actions+ in +subject+
|
21
|
+
#
|
22
|
+
# Basically this method
|
23
|
+
# 1. determine which rules pack it should use, by priority it would check:
|
24
|
+
# - Use pack defined in options[:use_pack]
|
25
|
+
# - Use pack defined by object method :sevn_rule_pack
|
26
|
+
# - Use pack defined by object's class method :sevn_rule_pack
|
27
|
+
# - Underscore object's class, and look for it
|
28
|
+
# 2. check if any of results include allowed action
|
29
|
+
#
|
30
|
+
# == Parameters:
|
31
|
+
# actions::
|
32
|
+
# Symbol or Array of Symbols of the actions to check
|
33
|
+
# object::
|
34
|
+
# object trying to access resource
|
35
|
+
# subject::
|
36
|
+
# resource to be accessed
|
37
|
+
# options::
|
38
|
+
# a list of options to consider when checking.
|
39
|
+
#
|
40
|
+
# == Options:
|
41
|
+
# use_pack::
|
42
|
+
# check for actions in the specified pack instead of auto-determining the pack.
|
43
|
+
#
|
44
|
+
# == Returns:
|
45
|
+
# true or false
|
46
|
+
#
|
47
|
+
# == Exceptions:
|
48
|
+
# if no pack can be determined for the current subject, it will raise a NoPackError
|
49
|
+
#
|
50
|
+
def allowed?(object, actions, subject, options = {})
|
51
|
+
# if multiple actions passed, check all actions to be allowed
|
52
|
+
if actions.respond_to?(:each)
|
53
|
+
actions.all? { |action| action_allowed?(object, action, subject, options) }
|
54
|
+
else
|
55
|
+
# single action check
|
56
|
+
action_allowed?(object, actions, subject, options)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def add_pack(name, pack)
|
62
|
+
if valid_rules_pack?(pack)
|
63
|
+
@rules_packs[name.to_sym] = pack
|
64
|
+
else
|
65
|
+
raise Sevn::Errors::InvalidPackPassed.new
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def pack_exist?(name)
|
70
|
+
@rules_packs.has_key?(name.to_sym)
|
71
|
+
end
|
72
|
+
|
73
|
+
def valid_rules_pack?(pack)
|
74
|
+
pack.kind_of?(Sevn::RulesPack)
|
75
|
+
end
|
76
|
+
|
77
|
+
def action_allowed?(object, action, subjects, options)
|
78
|
+
if subjects.kind_of?(Array)
|
79
|
+
# if subjects is an Array, let's group them by class
|
80
|
+
# check if action is allowed for the whole class or to all the subjects of that class
|
81
|
+
subjects.group_by(&:class).all? do |class_name, subjects_of_class|
|
82
|
+
action_allowed_for?(object, action, class_name, options) ||
|
83
|
+
subjects_of_class.all? { |subject| action_allowed_for?(object, action, subject, options) }
|
84
|
+
end
|
85
|
+
else
|
86
|
+
# if subject is a single object, check if action is allowed for that object
|
87
|
+
action_allowed_for?(object, action, subjects, options)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def action_allowed_for?(object, action, subject, options)
|
92
|
+
determine_rule_pack(subject, options).allowed?(object, action, subject)
|
93
|
+
end
|
94
|
+
|
95
|
+
def determine_rule_pack(subject, options)
|
96
|
+
if options.has_key?(:use_pack)
|
97
|
+
pack = options[:use_pack]
|
98
|
+
@rules_packs[pack] || raise(Sevn::Errors::NoPackError(pack, true))
|
99
|
+
elsif subject.kind_of?(Class)
|
100
|
+
get_class_rule_pack(subject) || raise(Sevn::Errors::NoPackError(subject.name))
|
101
|
+
else
|
102
|
+
get_instance_rule_pack(subject) || raise(Sevn::Errors::NoPackError(subject.class.name))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_class_rule_pack(subject)
|
107
|
+
if subject.respond_to?(:sevn_rule_pack) && pack_exist?(subject.sevn_rule_pack)
|
108
|
+
@rules_packs[subject.sevn_rule_pack]
|
109
|
+
elsif String.method_defined?(:underscore) && pack_exist?(subject.name.underscore.to_sym)
|
110
|
+
@rules_packs[subject.name.underscore.to_sym]
|
111
|
+
elsif pack_exist?(underscore(subject.name).to_sym)
|
112
|
+
@rules_packs[underscore(subject.name).to_sym]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_instance_rule_pack(subject)
|
117
|
+
if subject.respond_to?(:sevn_rule_pack) && pack_exist?(subject.sevn_rule_pack)
|
118
|
+
@rules_packs[subject.sevn_rule_pack]
|
119
|
+
elsif subject.class.respond_to?(:sevn_rule_pack) && pack_exist?(subject.class.sevn_rule_pack)
|
120
|
+
@rules_packs[subject.class.sevn_rule_pack]
|
121
|
+
elsif String.method_defined?(:underscore) && pack_exist?(subject.class.name.underscore.to_sym)
|
122
|
+
@rules_packs[subject.class.name.underscore.to_sym]
|
123
|
+
elsif pack_exist?(underscore(subject.class.name).to_sym)
|
124
|
+
@rules_packs[underscore(subject.class.name).to_sym]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Rails adds :underscore to the String class
|
129
|
+
# In case the underscore method is not defined, we define our own.
|
130
|
+
def underscore(class_name)
|
131
|
+
class_name.gsub(/::/, '/').
|
132
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
133
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
134
|
+
tr("-", "_").
|
135
|
+
downcase
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/lib/sevn/errors.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Sevn
|
2
|
+
module Errors
|
3
|
+
class NoPackError < StandardError
|
4
|
+
def initialize(pack_name, via_use_pack_option = false)
|
5
|
+
@pack_name = pack_name
|
6
|
+
@via_use_pack_option = via_use_pack_option
|
7
|
+
end
|
8
|
+
|
9
|
+
def message
|
10
|
+
if @via_use_pack_option
|
11
|
+
"Rule Pack #{@pack_name} doesn't exist"
|
12
|
+
else
|
13
|
+
"Rule Pack for #{@pack_name.constantize} model doesn't exist"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class InvalidPackPassed < StandardError
|
19
|
+
def message
|
20
|
+
'Wrong Rule Pack. You must provide a pack of kind Sevn::RulesPack'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class InitializeArgumentError < StandardError
|
25
|
+
def message
|
26
|
+
'Sevn.new require hash as pack argument in format {:name_of_pack => RulesPack.new}'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class InvalidPackAbilitiesType < StandardError
|
31
|
+
def message
|
32
|
+
'RulesPack abilities must be an "Array"'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Sevn
|
2
|
+
class RulesPack
|
3
|
+
def initialize
|
4
|
+
@allowed_abilities = general_abilities
|
5
|
+
@scoped_abilities = Hash.new { |hash, key| hash[key] = Sevn::Constants::EMPTY_ARRAY }
|
6
|
+
@aliases = Sevn::Constants::DEFAULT_ALIASES.merge(action_aliases)
|
7
|
+
abilities_check(@allowed_abilities)
|
8
|
+
end
|
9
|
+
|
10
|
+
def allowed?(object, action, subject)
|
11
|
+
@allowed_abilities.include?(action) ||
|
12
|
+
@scoped_abilities[scoped_abilities_key(object, subject)].include?(action) ||
|
13
|
+
prepare_and_check_scoped_abilities(object, action, subject)
|
14
|
+
end
|
15
|
+
|
16
|
+
def general_abilities
|
17
|
+
Sevn::Constants::EMPTY_ARRAY
|
18
|
+
end
|
19
|
+
|
20
|
+
def abilities(object, subject)
|
21
|
+
Sevn::Constants::EMPTY_ARRAY
|
22
|
+
end
|
23
|
+
|
24
|
+
def action_aliases
|
25
|
+
Sevn::Constants::EMPTY_HASH
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def all_abilities(object, subject)
|
30
|
+
@allowed_abilities + @scoped_abilities[scoped_abilities_key(object, subject)]
|
31
|
+
end
|
32
|
+
|
33
|
+
def prepare_and_check_scoped_abilities(object, action, subject)
|
34
|
+
from_abilities_method(object, subject).include?(action) ||
|
35
|
+
from_action_method(object, action, subject).include?(action) ||
|
36
|
+
from_aliased_action_method(object, action, subject).include?(action)
|
37
|
+
end
|
38
|
+
|
39
|
+
def from_abilities_method(object, subject)
|
40
|
+
abilities_from_method = abilities(object, subject)
|
41
|
+
abilities_check(abilities_from_method)
|
42
|
+
@scoped_abilities[scoped_abilities_key(object, subject)] += abilities_from_method
|
43
|
+
end
|
44
|
+
|
45
|
+
def from_action_method(object, action, subject)
|
46
|
+
sevn_action = "sevn_#{action}".to_sym
|
47
|
+
if self.respond_to?(sevn_action) && self.send(sevn_action, object, subject)
|
48
|
+
@scoped_abilities[scoped_abilities_key(object, subject)] << action
|
49
|
+
else
|
50
|
+
# Return empty array to avoid breaking the interface
|
51
|
+
Sevn::Constants::EMPTY_ARRAY
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def from_aliased_action_method(object, action, subject)
|
56
|
+
sevn_aliased_action = "sevn_#{@aliases[action]}".to_sym
|
57
|
+
if @aliases[action] && self.respond_to?(sevn_aliased_action) && self.send(sevn_aliased_action, object, subject)
|
58
|
+
@scoped_abilities[scoped_abilities_key(object, subject)] << action
|
59
|
+
else
|
60
|
+
# Return empty array to avoid breaking the interface
|
61
|
+
Sevn::Constants::EMPTY_ARRAY
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def abilities_check(abilities)
|
66
|
+
raise Sevn::Errors::InvalidPackAbilitiesType.new unless abilities.kind_of?(Array)
|
67
|
+
end
|
68
|
+
|
69
|
+
def scoped_abilities_key(object, subject)
|
70
|
+
"o#{object.object_id}_s#{subject.object_id}".to_sym
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/sevn/version.rb
ADDED
data/lib/sevn.rb
ADDED
data/sevn.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "sevn/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'sevn'
|
7
|
+
s.version = Sevn::VERSION
|
8
|
+
s.date = '2015-03-29'
|
9
|
+
s.summary = 'Sevn is an authorization gem inspired by Six'
|
10
|
+
s.description = 'Mid-weigth authorization gem'
|
11
|
+
s.authors = ["Miguel Cervera"]
|
12
|
+
s.email = 'miguel@cervera.me'
|
13
|
+
s.files = []
|
14
|
+
s.homepage = 'https://github.com/mikeki/sevn'
|
15
|
+
s.license = 'MIT'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency 'rspec'
|
23
|
+
s.add_development_dependency 'guard-rspec'
|
24
|
+
s.add_development_dependency 'awesome_print'
|
25
|
+
s.add_development_dependency 'simplecov'
|
26
|
+
s.add_development_dependency 'coveralls'
|
27
|
+
s.add_development_dependency 'codeclimate-test-reporter'
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "./spec/spec_helper"
|
2
|
+
require "./lib/sevn"
|
3
|
+
|
4
|
+
describe Sevn, "initialize" do
|
5
|
+
describe "initalization" do
|
6
|
+
before do
|
7
|
+
@jim = Author.new("Jim")
|
8
|
+
@mike = Author.new("Mike")
|
9
|
+
|
10
|
+
@jims_book = Book.new("The Game", @jim)
|
11
|
+
@mikes_book = Book.new("Life", @mike)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should create authorization object" do
|
15
|
+
expect(Sevn::Ability.new).to be_kind_of(Sevn::Ability)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should raise error if invalid argument passed" do
|
19
|
+
expect(lambda { Sevn::Ability.new("wrong argument") }).to raise_error Sevn::Errors::InitializeArgumentError
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should create authorization object" do
|
23
|
+
expect(Sevn::Ability.new(:book_rules => BookRules.new)).to be_kind_of(Sevn::Ability)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should create authorization object" do
|
27
|
+
expect(Sevn::Ability.new(:book0 => BookRules.new, :book1 => BookRules.new)).to be_kind_of(Sevn::Ability)
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "passing rules on initialization" do
|
31
|
+
it_should_behave_like :valid_abilities do
|
32
|
+
let(:abilities) { Sevn::Ability.new(:book => BookRules.new) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "./spec/spec_helper"
|
2
|
+
require "./lib/sevn"
|
3
|
+
|
4
|
+
describe Sevn do
|
5
|
+
# define abilities object
|
6
|
+
let (:abilities) { Sevn::Ability.new }
|
7
|
+
|
8
|
+
describe "Rules Packs" do
|
9
|
+
let(:rules) { BookRules.new }
|
10
|
+
|
11
|
+
describe :add_pack do
|
12
|
+
it { expect(abilities.send(:add_pack, :global, rules)).to be_truthy }
|
13
|
+
it { expect(lambda { abilities.send(:add_pack, :wrong, nil)}).to raise_error(Sevn::Errors::InvalidPackPassed) }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe :valid_rules_pack? do
|
17
|
+
let (:invalid) do
|
18
|
+
Object.new
|
19
|
+
end
|
20
|
+
|
21
|
+
it { expect(abilities.send(:valid_rules_pack?, BookRules.new)).to be_truthy }
|
22
|
+
it { expect(abilities.send(:valid_rules_pack?, invalid)).to be_falsey }
|
23
|
+
it { expect(abilities.send(:valid_rules_pack?, Book.new("Book", "Miguel"))).to be_falsey }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe :pack_exist? do
|
27
|
+
before { abilities.send(:add_pack, :global, rules) }
|
28
|
+
|
29
|
+
it { expect(abilities.send(:pack_exist?, :global)).to be_truthy }
|
30
|
+
it { expect(abilities.send(:pack_exist?,:ufo)).to be_falsey }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/spec/sevn_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'codeclimate-test-reporter'
|
2
|
+
CodeClimate::TestReporter.start
|
3
|
+
|
4
|
+
require 'simplecov'
|
5
|
+
require 'coveralls'
|
6
|
+
require 'sevn'
|
7
|
+
|
8
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
9
|
+
SimpleCov::Formatter::HTMLFormatter,
|
10
|
+
Coveralls::SimpleCov::Formatter
|
11
|
+
]
|
12
|
+
SimpleCov.start do
|
13
|
+
add_filter '/spec/'
|
14
|
+
end
|
15
|
+
|
16
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
17
|
+
# in spec/support/ and its subdirectories.
|
18
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
19
|
+
|
20
|
+
Coveralls.wear!
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class BookRules < Sevn::RulesPack
|
2
|
+
def abilities(author, book)
|
3
|
+
# check for correct class & nil
|
4
|
+
return [] unless author.instance_of?(Author) && book.instance_of?(Book)
|
5
|
+
|
6
|
+
rules = []
|
7
|
+
rules << :read_book if book.public || book.author?(author)
|
8
|
+
rules << :rate_book if book.public && !book.author?(author)
|
9
|
+
rules << :edit_book if book.author?(author)
|
10
|
+
rules << :publish_book if book.author?(author) && !book.public
|
11
|
+
rules
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
shared_examples :valid_abilities do
|
2
|
+
describe :allowed? do
|
3
|
+
before do
|
4
|
+
@jim = Author.new("Jim")
|
5
|
+
@mike = Author.new("Mike")
|
6
|
+
|
7
|
+
@jims_book = Book.new("The Game", @jim)
|
8
|
+
@mikes_book = Book.new("Life", @mike)
|
9
|
+
end
|
10
|
+
|
11
|
+
def allowed?(action, object, subject)
|
12
|
+
abilities.allowed?(action, object, subject)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "should return true or false depend on access" do
|
16
|
+
context :read_book do
|
17
|
+
it { expect(allowed?(@jim, :read_book, @jims_book)).to be_truthy }
|
18
|
+
it { expect(allowed?(@mike, :read_book, @mikes_book)).to be_truthy }
|
19
|
+
it { expect(allowed?(@jim, :read_book, @mikes_book)).to be_truthy }
|
20
|
+
it { expect(allowed?(@mike, :read_book, @jims_book)).to be_truthy }
|
21
|
+
end
|
22
|
+
|
23
|
+
context :rate_book do
|
24
|
+
it { expect(allowed?(@jim, :rate_book, @jims_book)).to be_falsey }
|
25
|
+
it { expect(allowed?(@mike, :rate_book, @mikes_book)).to be_falsey }
|
26
|
+
it { expect(allowed?(@jim, :rate_book, @mikes_book)).to be_truthy }
|
27
|
+
it { expect(allowed?(@mike, :rate_book, @jims_book)).to be_truthy }
|
28
|
+
end
|
29
|
+
|
30
|
+
context :edit_book do
|
31
|
+
it { expect(allowed?(@jim, :edit_book, @jims_book)).to be_truthy }
|
32
|
+
it { expect(allowed?(@mike,:edit_book, @mikes_book)).to be_truthy }
|
33
|
+
it { expect(allowed?(@jim, :edit_book, @mikes_book)).to be_falsey }
|
34
|
+
it { expect(allowed?(@mike,:edit_book, @jims_book)).to be_falsey }
|
35
|
+
end
|
36
|
+
|
37
|
+
context :publish_book do
|
38
|
+
it { expect(allowed?(@jim, :publish_book, @jims_book)).to be_falsey }
|
39
|
+
it { expect(allowed?(@mike,:publish_book, @mikes_book)).to be_falsey }
|
40
|
+
it { expect(allowed?(@jim, :publish_book, @mikes_book)).to be_falsey }
|
41
|
+
it { expect(allowed?(@mike,:publish_book, @jims_book)).to be_falsey }
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'passing multiple actions' do
|
45
|
+
it { expect(allowed?(@jim, [:read_book, :edit_book], @jims_book)).to be_truthy }
|
46
|
+
it { expect(allowed?(@jim, [:ead_book, :publish_book, :edit_book], @jims_book)).to be_falsey }
|
47
|
+
it { expect(allowed?(@mike, [:read_book, :edit_book], @mikes_book)).to be_truthy }
|
48
|
+
it { expect(allowed?(@mike, [:rate_book, :publish_book, :edit_book], @mikes_book)).to be_falsey }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sevn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miguel Cervera
|
@@ -9,13 +9,120 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
date: 2015-03-29 00:00:00.000000000 Z
|
12
|
-
dependencies:
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: guard-rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: awesome_print
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: coveralls
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: codeclimate-test-reporter
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
13
97
|
description: Mid-weigth authorization gem
|
14
98
|
email: miguel@cervera.me
|
15
99
|
executables: []
|
16
100
|
extensions: []
|
17
101
|
extra_rdoc_files: []
|
18
|
-
files:
|
102
|
+
files:
|
103
|
+
- ".coveralls.yml"
|
104
|
+
- ".gitignore"
|
105
|
+
- ".travis.yml"
|
106
|
+
- CHANGELOG
|
107
|
+
- Gemfile
|
108
|
+
- Guardfile
|
109
|
+
- LICENSE
|
110
|
+
- README.md
|
111
|
+
- lib/sevn.rb
|
112
|
+
- lib/sevn/ability.rb
|
113
|
+
- lib/sevn/constants.rb
|
114
|
+
- lib/sevn/errors.rb
|
115
|
+
- lib/sevn/rules_pack.rb
|
116
|
+
- lib/sevn/version.rb
|
117
|
+
- sevn.gemspec
|
118
|
+
- spec/sevn_initialize_spec.rb
|
119
|
+
- spec/sevn_rules_packs_spec.rb
|
120
|
+
- spec/sevn_spec.rb
|
121
|
+
- spec/spec_helper.rb
|
122
|
+
- spec/support/author.rb
|
123
|
+
- spec/support/book.rb
|
124
|
+
- spec/support/book_rules.rb
|
125
|
+
- spec/support/valid_abilities_example.rb
|
19
126
|
homepage: https://github.com/mikeki/sevn
|
20
127
|
licenses:
|
21
128
|
- MIT
|
@@ -40,4 +147,12 @@ rubygems_version: 2.2.2
|
|
40
147
|
signing_key:
|
41
148
|
specification_version: 4
|
42
149
|
summary: Sevn is an authorization gem inspired by Six
|
43
|
-
test_files:
|
150
|
+
test_files:
|
151
|
+
- spec/sevn_initialize_spec.rb
|
152
|
+
- spec/sevn_rules_packs_spec.rb
|
153
|
+
- spec/sevn_spec.rb
|
154
|
+
- spec/spec_helper.rb
|
155
|
+
- spec/support/author.rb
|
156
|
+
- spec/support/book.rb
|
157
|
+
- spec/support/book_rules.rb
|
158
|
+
- spec/support/valid_abilities_example.rb
|