credentials 1.0.1 → 2.0.0
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/.gitignore +2 -0
- data/Rakefile +1 -20
- data/VERSION +1 -0
- data/credentials.gemspec +69 -0
- data/lib/credentials/allow_rule.rb +7 -0
- data/lib/credentials/deny_rule.rb +7 -0
- data/lib/credentials/object_extensions.rb +38 -0
- data/lib/credentials/rule.rb +44 -0
- data/lib/credentials/rulebook.rb +52 -15
- data/lib/credentials.rb +2 -7
- data/spec/.gitignore +0 -0
- data/spec/credentials_spec.rb +99 -0
- data/spec/domain.rb +46 -0
- data/spec/rule_spec.rb +43 -0
- data/spec/rulebook_spec.rb +10 -0
- data/spec/spec_helper.rb +5 -0
- data/tasks/gems.rake +17 -0
- data/tasks/spec.rake +45 -0
- data/tasks/stats.rake +117 -0
- metadata +35 -24
- data/Manifest.txt +0 -107
- data/generators/credentials/USAGE +0 -8
- data/generators/credentials/credentials_generator.rb +0 -8
- data/lib/credentials/actor.rb +0 -57
- data/lib/credentials/class_methods.rb +0 -25
- data/lib/credentials/inflector.rb +0 -133
- data/lib/credentials/rules/can.rb +0 -6
- data/lib/credentials/rules/cannot.rb +0 -20
- data/lib/credentials/rules/rule.rb +0 -46
data/.gitignore
ADDED
data/Rakefile
CHANGED
@@ -1,20 +1 @@
|
|
1
|
-
|
2
|
-
require 'spec/rake/spectask'
|
3
|
-
require 'rcov/rcovtask'
|
4
|
-
|
5
|
-
desc 'Default: run specs.'
|
6
|
-
task :default => :spec
|
7
|
-
|
8
|
-
desc 'Run the specs'
|
9
|
-
Spec::Rake::SpecTask.new(:spec) do |t|
|
10
|
-
t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
|
11
|
-
t.spec_files = FileList['spec/**/*_spec.rb']
|
12
|
-
end
|
13
|
-
|
14
|
-
desc 'Output test coverage of plugin.'
|
15
|
-
Rcov::RcovTask.new(:rcov) do |rcov|
|
16
|
-
rcov.pattern = 'spec/**/*_spec.rb'
|
17
|
-
rcov.output_dir = 'rcov'
|
18
|
-
rcov.verbose = true
|
19
|
-
rcov.rcov_opts << '--exclude "test_app/config/*"'
|
20
|
-
end
|
1
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0
|
data/credentials.gemspec
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{credentials}
|
8
|
+
s.version = "2.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Matt Powell"]
|
12
|
+
s.date = %q{2009-11-11}
|
13
|
+
s.description = %q{A generic actor/resource permission framework based on rules, not objects.}
|
14
|
+
s.email = %q{fauxparse@gmail.com.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"History.txt",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"credentials.gemspec",
|
27
|
+
"init.rb",
|
28
|
+
"install.rb",
|
29
|
+
"lib/credentials.rb",
|
30
|
+
"lib/credentials/allow_rule.rb",
|
31
|
+
"lib/credentials/deny_rule.rb",
|
32
|
+
"lib/credentials/object_extensions.rb",
|
33
|
+
"lib/credentials/rule.rb",
|
34
|
+
"lib/credentials/rulebook.rb",
|
35
|
+
"spec/.gitignore",
|
36
|
+
"spec/credentials_spec.rb",
|
37
|
+
"spec/domain.rb",
|
38
|
+
"spec/rule_spec.rb",
|
39
|
+
"spec/rulebook_spec.rb",
|
40
|
+
"spec/spec_helper.rb",
|
41
|
+
"tasks/gems.rake",
|
42
|
+
"tasks/spec.rake",
|
43
|
+
"tasks/stats.rake",
|
44
|
+
"uninstall.rb"
|
45
|
+
]
|
46
|
+
s.homepage = %q{http://github.com/fauxparse/credentials}
|
47
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubygems_version = %q{1.3.5}
|
50
|
+
s.summary = %q{A generic actor/resource permission framework based on rules, not objects.}
|
51
|
+
s.test_files = [
|
52
|
+
"spec/credentials_spec.rb",
|
53
|
+
"spec/domain.rb",
|
54
|
+
"spec/rule_spec.rb",
|
55
|
+
"spec/rulebook_spec.rb",
|
56
|
+
"spec/spec_helper.rb"
|
57
|
+
]
|
58
|
+
|
59
|
+
if s.respond_to? :specification_version then
|
60
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
61
|
+
s.specification_version = 3
|
62
|
+
|
63
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
64
|
+
else
|
65
|
+
end
|
66
|
+
else
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Credentials
|
2
|
+
module ObjectExtensions #:nodoc
|
3
|
+
module ClassMethods
|
4
|
+
def credentials(options = nil)
|
5
|
+
@credentials ||= Credentials::Rulebook.new(self)
|
6
|
+
if block_given?
|
7
|
+
@credentials.options.merge!(options) unless options.nil?
|
8
|
+
yield @credentials
|
9
|
+
else
|
10
|
+
raise ArgumentError, "you can only set options with a block" unless options.nil?
|
11
|
+
end
|
12
|
+
@credentials
|
13
|
+
end
|
14
|
+
|
15
|
+
def inherited_with_credentials(child_class) #:nodoc
|
16
|
+
inherited_without_credentials(child_class) if child_class.respond_to? :inherited_without_credentials
|
17
|
+
child_class.instance_variable_set("@credentials", Rulebook.for(child_class))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module InstanceMethods
|
22
|
+
def can?(*args)
|
23
|
+
self.class.credentials.allow? self, *args
|
24
|
+
end
|
25
|
+
alias_method :able_to?, :can?
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.included(receiver) #:nodoc
|
29
|
+
receiver.extend ClassMethods
|
30
|
+
receiver.send :include, InstanceMethods
|
31
|
+
|
32
|
+
class << receiver
|
33
|
+
alias_method :inherited_without_credentials, :inherited if respond_to? :inherited
|
34
|
+
alias_method :inherited, :inherited_with_credentials
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Credentials
|
2
|
+
class Rule
|
3
|
+
attr_accessor :parameters
|
4
|
+
attr_accessor :options
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
self.options = args.last.is_a?(Hash) ? args.pop : {}
|
8
|
+
self.parameters = args
|
9
|
+
end
|
10
|
+
|
11
|
+
def arity
|
12
|
+
parameters.length
|
13
|
+
end
|
14
|
+
|
15
|
+
def match?(*args)
|
16
|
+
return false unless arity == args.length
|
17
|
+
|
18
|
+
parameters.zip(args).each do |expected, actual|
|
19
|
+
return false unless expected === actual
|
20
|
+
end
|
21
|
+
result = true
|
22
|
+
result = result && evaluate_condition(options[:if], :|, *args) unless options[:if].nil?
|
23
|
+
result = result && !evaluate_condition(options[:unless], :&, *args) unless options[:unless].nil?
|
24
|
+
result
|
25
|
+
end
|
26
|
+
|
27
|
+
def evaluate_condition(conditions, op, *args)
|
28
|
+
receiver = args.shift
|
29
|
+
args.reject! { |arg| arg.is_a? Symbol }
|
30
|
+
Array(conditions).inject(op == :| ? false : true) do |memo, condition|
|
31
|
+
memo = memo.send op, case condition
|
32
|
+
when Symbol
|
33
|
+
return false unless receiver.respond_to? condition
|
34
|
+
!!receiver.send(condition, *args[0, receiver.method(condition).arity])
|
35
|
+
when Proc
|
36
|
+
raise ArgumentError, "wrong number of arguments to condition (#{args.size} to #{condition.arity})" unless args.size + 1 == condition.arity
|
37
|
+
!!condition.call(receiver, *args)
|
38
|
+
else
|
39
|
+
raise ArgumentError, "invalid :if or :unless option (expected Symbol or Proc, or array thereof; got #{condition.class})"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/credentials/rulebook.rb
CHANGED
@@ -1,27 +1,64 @@
|
|
1
|
+
require "credentials/rule"
|
2
|
+
require "credentials/allow_rule"
|
3
|
+
require "credentials/deny_rule"
|
4
|
+
|
1
5
|
module Credentials
|
2
6
|
class Rulebook
|
3
|
-
|
7
|
+
attr_accessor :klass
|
8
|
+
attr_accessor :options
|
9
|
+
attr_accessor :rules
|
4
10
|
|
5
|
-
|
6
|
-
|
7
|
-
|
11
|
+
DEFAULT_OPTIONS = {
|
12
|
+
:default => :deny
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
def initialize(klass)
|
16
|
+
self.klass = klass
|
17
|
+
@rules = []
|
18
|
+
@options = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.for(klass)
|
22
|
+
rulebook = new(klass)
|
23
|
+
if superclass && superclass.respond_to?(:credentials)
|
24
|
+
rulebook.rules = superclass.credentials.rules.dup
|
25
|
+
end
|
26
|
+
rulebook
|
27
|
+
end
|
28
|
+
|
29
|
+
def empty?
|
30
|
+
rules.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
def can(*args)
|
34
|
+
self.rules << AllowRule.new(klass, *args)
|
8
35
|
end
|
9
36
|
|
10
|
-
def
|
11
|
-
|
37
|
+
def cannot(*args)
|
38
|
+
self.rules << DenyRule.new(klass, *args)
|
12
39
|
end
|
13
40
|
|
14
|
-
def
|
15
|
-
|
41
|
+
def default
|
42
|
+
options[:default] && options[:default].to_sym
|
16
43
|
end
|
17
44
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
45
|
+
def allow?(*args)
|
46
|
+
allowed = allow_rules.inject(false) { |memo, rule| memo || rule.allow?(*args) }
|
47
|
+
denied = deny_rules.inject(false) { |memo, rule| memo || rule.deny?(*args) }
|
48
|
+
|
49
|
+
if default == :allow
|
50
|
+
allowed or !denied
|
51
|
+
else
|
52
|
+
allowed and !denied
|
23
53
|
end
|
24
|
-
|
54
|
+
end
|
55
|
+
|
56
|
+
def allow_rules
|
57
|
+
rules.select { |rule| rule.respond_to? :allow? }
|
58
|
+
end
|
59
|
+
|
60
|
+
def deny_rules
|
61
|
+
rules.select { |rule| rule.respond_to? :deny? }
|
25
62
|
end
|
26
63
|
end
|
27
|
-
end
|
64
|
+
end
|
data/lib/credentials.rb
CHANGED
@@ -1,9 +1,4 @@
|
|
1
|
-
require "credentials/actor"
|
2
1
|
require "credentials/rulebook"
|
3
|
-
require "credentials/
|
4
|
-
require "credentials/inflector"
|
5
|
-
require "credentials/rules/rule"
|
6
|
-
Dir.glob(File.dirname(__FILE__) + "/credentials/rules/*.rb").each { |f| require f }
|
7
|
-
Dir.glob(File.dirname(__FILE__) + "/credentials/support/*.rb").each { |f| require f } unless defined?(ActiveSupport)
|
2
|
+
require "credentials/object_extensions"
|
8
3
|
|
9
|
-
Object.send :
|
4
|
+
Object.send :include, Credentials::ObjectExtensions
|
data/spec/.gitignore
ADDED
File without changes
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require "time"
|
3
|
+
|
4
|
+
describe Animal do
|
5
|
+
before :each do
|
6
|
+
@sheep = Animal.new("Sheep")
|
7
|
+
@cow = Animal.new("Cow")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should not be able to eat other animals" do
|
11
|
+
@sheep.should_not be_able_to :eat, @cow
|
12
|
+
end
|
13
|
+
|
14
|
+
it "shouldn't be able to do anything without explicit permission" do
|
15
|
+
@cow.should_not be_able_to :jump, "Moon"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Carnivore do
|
20
|
+
before :each do
|
21
|
+
@antelope = Prey.new("Antelope")
|
22
|
+
@toucan = Bird.new("Toucan")
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "(lazy)" do
|
26
|
+
before :each do
|
27
|
+
@lion = Carnivore.new("Lion")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should not be able to eat another animal" do
|
31
|
+
@lion.should_not be_able_to :eat, @antelope
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "(hungry)" do
|
36
|
+
before :each do
|
37
|
+
@lion = Carnivore.new("Lion", true)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should be able to eat another animal" do
|
41
|
+
@lion.should be_able_to :eat, @antelope
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should not be able to eat a bird" do
|
45
|
+
@lion.should_not be_able_to :eat, @toucan
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "(fast)" do
|
50
|
+
before :each do
|
51
|
+
@lion = Carnivore.new("Lion", false, true)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should not be able to eat another animal" do
|
55
|
+
@lion.should_not be_able_to :eat, @antelope
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should not be able to eat a bird" do
|
59
|
+
@lion.should_not be_able_to :eat, @toucan
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "(hungry AND fast)" do
|
64
|
+
before :each do
|
65
|
+
@lion = Carnivore.new("Lion", true, true)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should be able to eat another animal" do
|
69
|
+
@lion.should be_able_to :eat, @antelope
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should be able to eat a bird" do
|
73
|
+
@lion.should be_able_to :eat, @toucan
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe Man do
|
79
|
+
before :each do
|
80
|
+
@man = Man.new
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should be able to do anything it wants" do
|
84
|
+
@man.should be_able_to :do_a_cartwheel
|
85
|
+
@man.should be_able_to :eat, "ice cream"
|
86
|
+
@man.should be_able_to :stay, :up, :past, Time.parse("10:00")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe WhiteMan do
|
91
|
+
before :each do
|
92
|
+
@white_man = WhiteMan.new
|
93
|
+
end
|
94
|
+
|
95
|
+
it "can't jump (sorry)" do
|
96
|
+
@white_man.should_not be_able_to :jump
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
data/spec/domain.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
class Animal < Struct.new(:species, :hungry, :fast)
|
2
|
+
credentials do |animal|
|
3
|
+
end
|
4
|
+
|
5
|
+
def edible?
|
6
|
+
false
|
7
|
+
end
|
8
|
+
|
9
|
+
def hungry?
|
10
|
+
!!hungry
|
11
|
+
end
|
12
|
+
|
13
|
+
def fast?
|
14
|
+
!!fast
|
15
|
+
end
|
16
|
+
|
17
|
+
alias :to_s :species
|
18
|
+
end
|
19
|
+
|
20
|
+
class Prey < Animal
|
21
|
+
def edible?; true; end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Bird < Prey
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
class Carnivore < Animal
|
29
|
+
credentials do |carnivore|
|
30
|
+
carnivore.can :eat, Animal, :if => lambda { |predator, prey| prey.edible? }
|
31
|
+
carnivore.cannot :eat, Animal, :unless => :hungry?
|
32
|
+
carnivore.cannot :eat, Bird, :unless => [ :hungry?, :fast? ]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Man < Animal
|
37
|
+
credentials :default => :allow do |man|
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class WhiteMan < Man
|
43
|
+
credentials :default => :allow do |white_man|
|
44
|
+
white_man.cannot :jump
|
45
|
+
end
|
46
|
+
end
|
data/spec/rule_spec.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Credentials::AllowRule do
|
4
|
+
it "should have the correct arity" do
|
5
|
+
Credentials::AllowRule.new(Animal, :jump).arity.should == 2
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should match the simple case" do
|
9
|
+
antelope = Prey.new("antelope")
|
10
|
+
Credentials::AllowRule.new(Animal, :jump).allow?(antelope, :jump).should == true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should match the subject, verb, object case" do
|
14
|
+
antelope = Prey.new("antelope")
|
15
|
+
lion = Carnivore.new("lion")
|
16
|
+
Credentials::AllowRule.new(Carnivore, :eat, Prey).allow?(lion, :eat, antelope).should == true
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should throw an error when it gets bad arguments" do
|
20
|
+
lambda {
|
21
|
+
lion = Carnivore.new("lion")
|
22
|
+
rule = Credentials::AllowRule.new(Animal, :jump, :if => Date.civil(2010, 4, 1))
|
23
|
+
rule.match?(lion, :jump)
|
24
|
+
}.should raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe Credentials::DenyRule do
|
29
|
+
it "should have the correct arity" do
|
30
|
+
Credentials::DenyRule.new(Animal, :jump).arity.should == 2
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should match the simple case" do
|
34
|
+
elephant = Prey.new("elephant")
|
35
|
+
Credentials::DenyRule.new(Animal, :jump).deny?(elephant, :jump).should == true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should match the subject, verb, object case" do
|
39
|
+
antelope = Prey.new("antelope")
|
40
|
+
lion = Carnivore.new("lion")
|
41
|
+
Credentials::DenyRule.new(Carnivore, :eat, Prey).deny?(lion, :eat, antelope).should == true
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Credentials::Rulebook do
|
4
|
+
it "should duplicate on inheritance" do
|
5
|
+
Animal.credentials.should_not == Carnivore.credentials
|
6
|
+
Animal.credentials.rules.should_not == Carnivore.credentials.rules
|
7
|
+
Animal.credentials.should be_empty
|
8
|
+
Carnivore.credentials.should_not be_empty
|
9
|
+
end
|
10
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/tasks/gems.rake
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gemspec|
|
7
|
+
gemspec.name = "credentials"
|
8
|
+
gemspec.summary = "A generic actor/resource permission framework based on rules, not objects."
|
9
|
+
gemspec.description = "A generic actor/resource permission framework based on rules, not objects."
|
10
|
+
gemspec.email = "fauxparse@gmail.com.com"
|
11
|
+
gemspec.homepage = "http://github.com/fauxparse/credentials"
|
12
|
+
gemspec.authors = ["Matt Powell"]
|
13
|
+
end
|
14
|
+
Jeweler::GemcutterTasks.new
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
17
|
+
end
|
data/tasks/spec.rake
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Don't load rspec if running "rake gems:*"
|
2
|
+
unless ARGV.any? {|a| a =~ /^gems/}
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
rescue MissingSourceFile
|
7
|
+
module Spec
|
8
|
+
module Rake
|
9
|
+
class SpecTask
|
10
|
+
def initialize(name)
|
11
|
+
task name do
|
12
|
+
raise <<-MSG
|
13
|
+
|
14
|
+
#{"*" * 80}
|
15
|
+
* You are trying to run an rspec rake task defined in
|
16
|
+
* #{__FILE__},
|
17
|
+
* but rspec cannot be found.
|
18
|
+
#{"*" * 80}
|
19
|
+
MSG
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
task :default => :spec
|
28
|
+
|
29
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
30
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
31
|
+
t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
|
32
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
33
|
+
end
|
34
|
+
|
35
|
+
namespace :spec do
|
36
|
+
desc "Run all specs in spec directory with RCov"
|
37
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
38
|
+
t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
|
39
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
40
|
+
t.rcov = true
|
41
|
+
t.rcov_opts = ['--text-report --exclude "spec/*"']
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/tasks/stats.rake
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
STATS_DIRECTORIES = [
|
2
|
+
%w(Libraries lib/),
|
3
|
+
%w(Specs spec)
|
4
|
+
].collect { |name, dir| [ name, File.dirname(__FILE__) + "/../#{dir}" ] }.select { |name, dir| File.directory?(dir) }
|
5
|
+
|
6
|
+
desc "Report code statistics (KLOCs, etc) from the plugin"
|
7
|
+
task :stats do
|
8
|
+
CodeStatistics.new(*STATS_DIRECTORIES).to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
class CodeStatistics #:nodoc:
|
12
|
+
|
13
|
+
TEST_TYPES = %w(Units Functionals Unit\ tests Functional\ tests Integration\ tests Specs)
|
14
|
+
|
15
|
+
def initialize(*pairs)
|
16
|
+
@pairs = pairs
|
17
|
+
@statistics = calculate_statistics
|
18
|
+
@total = calculate_total if pairs.length > 1
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
print_header
|
23
|
+
@pairs.each { |pair| print_line(pair.first, @statistics[pair.first]) }
|
24
|
+
print_splitter
|
25
|
+
|
26
|
+
if @total
|
27
|
+
print_line("Total", @total)
|
28
|
+
print_splitter
|
29
|
+
end
|
30
|
+
|
31
|
+
print_code_test_stats
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def calculate_statistics
|
36
|
+
@pairs.inject({}) { |stats, pair| stats[pair.first] = calculate_directory_statistics(pair.last); stats }
|
37
|
+
end
|
38
|
+
|
39
|
+
def calculate_directory_statistics(directory, pattern = /.*\.rb$/)
|
40
|
+
stats = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
|
41
|
+
|
42
|
+
Dir.foreach(directory) do |file_name|
|
43
|
+
if File.stat(directory + "/" + file_name).directory? and (/^\./ !~ file_name)
|
44
|
+
newstats = calculate_directory_statistics(directory + "/" + file_name, pattern)
|
45
|
+
stats.each { |k, v| stats[k] += newstats[k] }
|
46
|
+
end
|
47
|
+
|
48
|
+
next unless file_name =~ pattern
|
49
|
+
|
50
|
+
f = File.open(directory + "/" + file_name)
|
51
|
+
|
52
|
+
while line = f.gets
|
53
|
+
stats["lines"] += 1
|
54
|
+
stats["classes"] += 1 if line =~ /class [A-Z]/
|
55
|
+
stats["methods"] += 1 if line =~ /def [a-z]/
|
56
|
+
stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
stats
|
61
|
+
end
|
62
|
+
|
63
|
+
def calculate_total
|
64
|
+
total = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
|
65
|
+
@statistics.each_value { |pair| pair.each { |k, v| total[k] += v } }
|
66
|
+
total
|
67
|
+
end
|
68
|
+
|
69
|
+
def calculate_code
|
70
|
+
code_loc = 0
|
71
|
+
@statistics.each { |k, v| code_loc += v['codelines'] unless TEST_TYPES.include? k }
|
72
|
+
code_loc
|
73
|
+
end
|
74
|
+
|
75
|
+
def calculate_tests
|
76
|
+
test_loc = 0
|
77
|
+
@statistics.each { |k, v| test_loc += v['codelines'] if TEST_TYPES.include? k }
|
78
|
+
test_loc
|
79
|
+
end
|
80
|
+
|
81
|
+
def print_header
|
82
|
+
print_splitter
|
83
|
+
puts "| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |"
|
84
|
+
print_splitter
|
85
|
+
end
|
86
|
+
|
87
|
+
def print_splitter
|
88
|
+
puts "+----------------------+-------+-------+---------+---------+-----+-------+"
|
89
|
+
end
|
90
|
+
|
91
|
+
def print_line(name, statistics)
|
92
|
+
m_over_c = (statistics["methods"] / statistics["classes"]) rescue m_over_c = 0
|
93
|
+
loc_over_m = (statistics["codelines"] / statistics["methods"]) - 2 rescue loc_over_m = 0
|
94
|
+
|
95
|
+
start = if TEST_TYPES.include? name
|
96
|
+
"| #{name.ljust(20)} "
|
97
|
+
else
|
98
|
+
"| #{name.ljust(20)} "
|
99
|
+
end
|
100
|
+
|
101
|
+
puts start +
|
102
|
+
"| #{statistics["lines"].to_s.rjust(5)} " +
|
103
|
+
"| #{statistics["codelines"].to_s.rjust(5)} " +
|
104
|
+
"| #{statistics["classes"].to_s.rjust(7)} " +
|
105
|
+
"| #{statistics["methods"].to_s.rjust(7)} " +
|
106
|
+
"| #{m_over_c.to_s.rjust(3)} " +
|
107
|
+
"| #{loc_over_m.to_s.rjust(5)} |"
|
108
|
+
end
|
109
|
+
|
110
|
+
def print_code_test_stats
|
111
|
+
code = calculate_code
|
112
|
+
tests = calculate_tests
|
113
|
+
|
114
|
+
puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f/code)}"
|
115
|
+
puts ""
|
116
|
+
end
|
117
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: credentials
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Powell
|
@@ -9,36 +9,44 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-11-11 00:00:00 +13:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description:
|
17
|
-
email: fauxparse@gmail.com
|
16
|
+
description: A generic actor/resource permission framework based on rules, not objects.
|
17
|
+
email: fauxparse@gmail.com.com
|
18
18
|
executables: []
|
19
19
|
|
20
20
|
extensions: []
|
21
21
|
|
22
|
-
extra_rdoc_files:
|
23
|
-
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.rdoc
|
24
25
|
files:
|
25
|
-
-
|
26
|
-
- generators/credentials/USAGE
|
26
|
+
- .gitignore
|
27
27
|
- History.txt
|
28
|
+
- LICENSE
|
29
|
+
- README.rdoc
|
30
|
+
- Rakefile
|
31
|
+
- VERSION
|
32
|
+
- credentials.gemspec
|
28
33
|
- init.rb
|
29
34
|
- install.rb
|
30
|
-
- lib/credentials/actor.rb
|
31
|
-
- lib/credentials/class_methods.rb
|
32
|
-
- lib/credentials/inflector.rb
|
33
|
-
- lib/credentials/rulebook.rb
|
34
|
-
- lib/credentials/rules/can.rb
|
35
|
-
- lib/credentials/rules/cannot.rb
|
36
|
-
- lib/credentials/rules/rule.rb
|
37
35
|
- lib/credentials.rb
|
38
|
-
-
|
39
|
-
-
|
40
|
-
-
|
41
|
-
-
|
36
|
+
- lib/credentials/allow_rule.rb
|
37
|
+
- lib/credentials/deny_rule.rb
|
38
|
+
- lib/credentials/object_extensions.rb
|
39
|
+
- lib/credentials/rule.rb
|
40
|
+
- lib/credentials/rulebook.rb
|
41
|
+
- spec/.gitignore
|
42
|
+
- spec/credentials_spec.rb
|
43
|
+
- spec/domain.rb
|
44
|
+
- spec/rule_spec.rb
|
45
|
+
- spec/rulebook_spec.rb
|
46
|
+
- spec/spec_helper.rb
|
47
|
+
- tasks/gems.rake
|
48
|
+
- tasks/spec.rake
|
49
|
+
- tasks/stats.rake
|
42
50
|
- uninstall.rb
|
43
51
|
has_rdoc: true
|
44
52
|
homepage: http://github.com/fauxparse/credentials
|
@@ -46,7 +54,6 @@ licenses: []
|
|
46
54
|
|
47
55
|
post_install_message:
|
48
56
|
rdoc_options:
|
49
|
-
- --inline-source
|
50
57
|
- --charset=UTF-8
|
51
58
|
require_paths:
|
52
59
|
- lib
|
@@ -64,10 +71,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
71
|
version:
|
65
72
|
requirements: []
|
66
73
|
|
67
|
-
rubyforge_project:
|
74
|
+
rubyforge_project:
|
68
75
|
rubygems_version: 1.3.5
|
69
76
|
signing_key:
|
70
77
|
specification_version: 3
|
71
|
-
summary:
|
72
|
-
test_files:
|
73
|
-
|
78
|
+
summary: A generic actor/resource permission framework based on rules, not objects.
|
79
|
+
test_files:
|
80
|
+
- spec/credentials_spec.rb
|
81
|
+
- spec/domain.rb
|
82
|
+
- spec/rule_spec.rb
|
83
|
+
- spec/rulebook_spec.rb
|
84
|
+
- spec/spec_helper.rb
|
data/Manifest.txt
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
credentials.gemspec
|
2
|
-
generators/credentials/credentials_generator.rb
|
3
|
-
generators/credentials/USAGE
|
4
|
-
History.txt
|
5
|
-
init.rb
|
6
|
-
install.rb
|
7
|
-
lib/credentials/actor.rb
|
8
|
-
lib/credentials/class_methods.rb
|
9
|
-
lib/credentials/inflector.rb
|
10
|
-
lib/credentials/rulebook.rb
|
11
|
-
lib/credentials/rules/can.rb
|
12
|
-
lib/credentials/rules/cannot.rb
|
13
|
-
lib/credentials/rules/rule.rb
|
14
|
-
lib/credentials.rb
|
15
|
-
LICENSE
|
16
|
-
Manifest.txt
|
17
|
-
Rakefile
|
18
|
-
README.rdoc
|
19
|
-
uninstall.rb
|
20
|
-
tt@Yavin:credentials[master]$ find . -type f | grep -v ".git"./credentials.gemspec
|
21
|
-
generators/credentials/credentials_generator.rb
|
22
|
-
generators/credentials/USAGE
|
23
|
-
History.txt
|
24
|
-
init.rb
|
25
|
-
install.rb
|
26
|
-
lib/credentials/actor.rb
|
27
|
-
lib/credentials/class_methods.rb
|
28
|
-
lib/credentials/inflector.rb
|
29
|
-
lib/credentials/rulebook.rb
|
30
|
-
lib/credentials/rules/can.rb
|
31
|
-
lib/credentials/rules/cannot.rb
|
32
|
-
lib/credentials/rules/rule.rb
|
33
|
-
lib/credentials.rb
|
34
|
-
LICENSE
|
35
|
-
Manifest.txt
|
36
|
-
Rakefile
|
37
|
-
README.rdoc
|
38
|
-
spec/credentials_spec.rb
|
39
|
-
spec/debug.log
|
40
|
-
spec/inflector_spec.rb
|
41
|
-
spec/spec_helper.rb
|
42
|
-
spec/test_app/app/controllers/application.rb
|
43
|
-
spec/test_app/app/models/group.rb
|
44
|
-
spec/test_app/app/models/headmaster.rb
|
45
|
-
spec/test_app/app/models/house.rb
|
46
|
-
spec/test_app/app/models/school.rb
|
47
|
-
spec/test_app/app/models/student.rb
|
48
|
-
spec/test_app/app/models/teacher.rb
|
49
|
-
spec/test_app/app/models/user.rb
|
50
|
-
spec/test_app/config/boot.rb
|
51
|
-
spec/test_app/config/database.yml
|
52
|
-
spec/test_app/config/environment.rb
|
53
|
-
spec/test_app/config/environments/development.rb
|
54
|
-
spec/test_app/config/environments/production.rb
|
55
|
-
spec/test_app/config/environments/test.rb
|
56
|
-
spec/test_app/config/initializers/inflections.rb
|
57
|
-
spec/test_app/config/initializers/mime_types.rb
|
58
|
-
spec/test_app/config/initializers/new_rails_defaults.rb
|
59
|
-
spec/test_app/config/locales/en.yml
|
60
|
-
spec/test_app/config/routes.rb
|
61
|
-
spec/test_app/db/development.sqlite3
|
62
|
-
spec/test_app/db/migrate/20081128211345_create_users.rb
|
63
|
-
spec/test_app/db/migrate/20081128213041_create_groups.rb
|
64
|
-
spec/test_app/db/migrate/20081129031929_create_students.rb
|
65
|
-
spec/test_app/db/migrate/20081129101832_create_schools.rb
|
66
|
-
spec/test_app/db/migrate/20081129105013_create_houses.rb
|
67
|
-
spec/test_app/db/schema.rb
|
68
|
-
spec/test_app/db/test.sqlite3
|
69
|
-
spec/test_app/lib/tasks/rspec.rake
|
70
|
-
spec/test_app/log/test.log
|
71
|
-
spec/test_app/Rakefile
|
72
|
-
spec/test_app/README
|
73
|
-
spec/test_app/script/about
|
74
|
-
spec/test_app/script/autospec
|
75
|
-
spec/test_app/script/console
|
76
|
-
spec/test_app/script/dbconsole
|
77
|
-
spec/test_app/script/destroy
|
78
|
-
spec/test_app/script/generate
|
79
|
-
spec/test_app/script/performance/benchmarker
|
80
|
-
spec/test_app/script/performance/profiler
|
81
|
-
spec/test_app/script/performance/request
|
82
|
-
spec/test_app/script/plugin
|
83
|
-
spec/test_app/script/process/inspector
|
84
|
-
spec/test_app/script/process/reaper
|
85
|
-
spec/test_app/script/process/spawner
|
86
|
-
spec/test_app/script/runner
|
87
|
-
spec/test_app/script/server
|
88
|
-
spec/test_app/script/spec
|
89
|
-
spec/test_app/script/spec_server
|
90
|
-
spec/test_app/spec/fixtures/groups.yml
|
91
|
-
spec/test_app/spec/fixtures/houses.yml
|
92
|
-
spec/test_app/spec/fixtures/schools.yml
|
93
|
-
spec/test_app/spec/fixtures/users.yml
|
94
|
-
spec/test_app/spec/models/group_spec.rb
|
95
|
-
spec/test_app/spec/models/headmaster_spec.rb
|
96
|
-
spec/test_app/spec/models/house_spec.rb
|
97
|
-
spec/test_app/spec/models/school_spec.rb
|
98
|
-
spec/test_app/spec/models/student_spec.rb
|
99
|
-
spec/test_app/spec/models/teacher_spec.rb
|
100
|
-
spec/test_app/spec/models/user_spec.rb
|
101
|
-
spec/test_app/spec/rcov.opts
|
102
|
-
spec/test_app/spec/spec.opts
|
103
|
-
spec/test_app/spec/spec_helper.rb
|
104
|
-
spec/test_app/stories/all.rb
|
105
|
-
spec/test_app/stories/helper.rb
|
106
|
-
spec/test_app/vendor/plugins/credentials/init.rb
|
107
|
-
uninstall.rb
|
data/lib/credentials/actor.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
module Credentials
|
2
|
-
module Actor
|
3
|
-
def self.included(base) #:nodoc:
|
4
|
-
base.send :extend, ClassMethods
|
5
|
-
end
|
6
|
-
|
7
|
-
# Returns true if the receiver has permission to perform the action ‘<tt>verb</tt>’ with the given <tt>args</tt>.
|
8
|
-
def can?(verb, *args)
|
9
|
-
self.class.can?(self, verb, *args)
|
10
|
-
end
|
11
|
-
alias_method :able_to?, :can?
|
12
|
-
|
13
|
-
module ClassMethods
|
14
|
-
# Returns true if the given <tt>actor</tt> has permission to perform the action ‘<tt>verb</tt>’ with the given <tt>args</tt>.
|
15
|
-
def can?(actor, verb, *args)
|
16
|
-
rulebook.can?(actor, verb, *args) ||
|
17
|
-
can_by_association?(actor, verb, *args) ||
|
18
|
-
can_by_actor_group?(actor, verb, *args)
|
19
|
-
end
|
20
|
-
|
21
|
-
# Returns true if any magic methods give the requested permission.
|
22
|
-
# For example, <tt>by_association?(user, :edit, post)</tt> would try the following (in order):
|
23
|
-
# * <tt>user.is_editor_of?(post)</tt>
|
24
|
-
# * <tt>user.is_editor_for?(post)</tt>
|
25
|
-
# * <tt>user.is_editor_on?(post)</tt>
|
26
|
-
# * <tt>user.is_editor_at?(post)</tt>
|
27
|
-
# * <tt>user.is_editor_in?(post)</tt>
|
28
|
-
# * <tt>post.editor == user</tt>
|
29
|
-
# * <tt>post.editors.include?(user)</tt>
|
30
|
-
def can_by_association?(actor, verb, *args)
|
31
|
-
return false unless args.size == 1
|
32
|
-
noun = verb.to_s.actorize
|
33
|
-
object = args.first
|
34
|
-
%w(of for on at in).each do |prep|
|
35
|
-
return true if actor.respond_to?(method = "is_#{noun}_#{prep}?".to_sym) and actor.send(method, object)
|
36
|
-
end
|
37
|
-
return true if object.respond_to?(method = noun.to_sym) and object.send(method) == actor
|
38
|
-
return true if object.respond_to?(method = noun.pluralize.to_sym) and object.send(method).include?(actor)
|
39
|
-
false
|
40
|
-
end
|
41
|
-
|
42
|
-
# Returns true if the actor belongs to any groups that have the requested permission.
|
43
|
-
def can_by_actor_group?(actor, verb, *args)
|
44
|
-
groups_for(actor).any? { |group| group.respond_to?(:can?) && group.can?(verb, *args) }
|
45
|
-
end
|
46
|
-
|
47
|
-
# Returns a list of the groups the user belongs to, according to the <tt>:groups</tt> option to <tt>has_credentials</tt>.
|
48
|
-
def groups_for(actor)
|
49
|
-
case true
|
50
|
-
when !credential_options[:groups].blank? then Array(credential_options[:groups]).map(&:to_sym).collect { |g| actor.send(g) }.flatten.uniq
|
51
|
-
when actor.respond_to?(:groups) then actor.groups.flatten.uniq
|
52
|
-
else []
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module Credentials
|
2
|
-
module ClassMethods
|
3
|
-
# Defines the set of credentials common to members of a class.
|
4
|
-
def credentials(options = {}, &block)
|
5
|
-
unless included_modules.include? Actor
|
6
|
-
class_inheritable_reader :rulebook
|
7
|
-
class_inheritable_reader :credential_options
|
8
|
-
include Actor
|
9
|
-
end
|
10
|
-
write_inheritable_attribute :credential_options, merge_credential_options(read_inheritable_attribute(:credential_options), options)
|
11
|
-
old_rulebook = read_inheritable_attribute(:rulebook)
|
12
|
-
write_inheritable_attribute :rulebook, Rulebook.new(self, old_rulebook ? old_rulebook.rules : [])
|
13
|
-
yield rulebook if block_given?
|
14
|
-
end
|
15
|
-
|
16
|
-
protected
|
17
|
-
# Merges the set of options inherited from a parent class (if any)
|
18
|
-
def merge_credential_options(a, b)
|
19
|
-
a ||= {}
|
20
|
-
b ||= {}
|
21
|
-
a[:groups] = (Array(a[:groups]) + Array(b.delete(:groups))).uniq if b[:groups]
|
22
|
-
a.merge(b)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,133 +0,0 @@
|
|
1
|
-
require "singleton"
|
2
|
-
|
3
|
-
module Credentials
|
4
|
-
module Inflector
|
5
|
-
extend self
|
6
|
-
|
7
|
-
class Inflections
|
8
|
-
include Singleton
|
9
|
-
|
10
|
-
attr_reader :actors
|
11
|
-
|
12
|
-
def actors
|
13
|
-
@actors ||= []
|
14
|
-
end
|
15
|
-
|
16
|
-
def actor(rule, replacement)
|
17
|
-
actors.insert 0, [ rule, replacement ]
|
18
|
-
end
|
19
|
-
|
20
|
-
unless defined?(ActiveSupport)
|
21
|
-
attr_reader :plurals, :singulars, :uncountables
|
22
|
-
|
23
|
-
def initialize
|
24
|
-
@plurals, @singulars, @uncountables = [], [], []
|
25
|
-
end
|
26
|
-
|
27
|
-
def plurals
|
28
|
-
@plurals ||= []
|
29
|
-
end
|
30
|
-
|
31
|
-
def plural(rule, replacement)
|
32
|
-
plurals.insert 0, [ rule, replacement ]
|
33
|
-
end
|
34
|
-
def plural(rule, replacement)
|
35
|
-
@uncountables.delete(rule) if rule.is_a?(String)
|
36
|
-
@uncountables.delete(replacement)
|
37
|
-
@plurals.insert(0, [rule, replacement])
|
38
|
-
end
|
39
|
-
|
40
|
-
def singular(rule, replacement)
|
41
|
-
@uncountables.delete(rule) if rule.is_a?(String)
|
42
|
-
@uncountables.delete(replacement)
|
43
|
-
@singulars.insert(0, [rule, replacement])
|
44
|
-
end
|
45
|
-
|
46
|
-
def irregular(singular, plural)
|
47
|
-
@uncountables.delete(singular)
|
48
|
-
@uncountables.delete(plural)
|
49
|
-
if singular[0,1].upcase == plural[0,1].upcase
|
50
|
-
plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
|
51
|
-
singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
|
52
|
-
else
|
53
|
-
plural(Regexp.new("#{singular[0,1].upcase}(?i)#{singular[1..-1]}$"), plural[0,1].upcase + plural[1..-1])
|
54
|
-
plural(Regexp.new("#{singular[0,1].downcase}(?i)#{singular[1..-1]}$"), plural[0,1].downcase + plural[1..-1])
|
55
|
-
singular(Regexp.new("#{plural[0,1].upcase}(?i)#{plural[1..-1]}$"), singular[0,1].upcase + singular[1..-1])
|
56
|
-
singular(Regexp.new("#{plural[0,1].downcase}(?i)#{plural[1..-1]}$"), singular[0,1].downcase + singular[1..-1])
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def uncountable(*words)
|
61
|
-
(@uncountables << words).flatten!
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def inflections
|
67
|
-
if block_given?
|
68
|
-
yield Inflections.instance
|
69
|
-
else
|
70
|
-
Inflections.instance
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def actorize(word)
|
75
|
-
result = word.to_s.dup
|
76
|
-
inflections.actors.each { |(rule, replacement)| break if result.gsub!(rule, replacement) } unless result.empty?
|
77
|
-
result
|
78
|
-
end
|
79
|
-
|
80
|
-
unless defined?(ActiveSupport)
|
81
|
-
def pluralize(word)
|
82
|
-
result = word.to_s.dup
|
83
|
-
|
84
|
-
if word.empty? || inflections.uncountables.include?(result.downcase)
|
85
|
-
result
|
86
|
-
else
|
87
|
-
inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
|
88
|
-
result
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def singularize(word)
|
93
|
-
result = word.to_s.dup
|
94
|
-
|
95
|
-
if inflections.uncountables.include?(result.downcase)
|
96
|
-
result
|
97
|
-
else
|
98
|
-
inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
|
99
|
-
result
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
module StringExtensions
|
106
|
-
def actorize
|
107
|
-
Credentials::Inflector.actorize(self)
|
108
|
-
end
|
109
|
-
|
110
|
-
unless defined?(ActiveSupport)
|
111
|
-
def pluralize
|
112
|
-
Credentials::Inflector.pluralize(self)
|
113
|
-
end
|
114
|
-
|
115
|
-
def singularize
|
116
|
-
Credentials::Inflector.singularize(self)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
String.send :include, Credentials::StringExtensions
|
123
|
-
|
124
|
-
Credentials::Inflector.inflections do |inflect|
|
125
|
-
inflect.actor(/$/, 'er')
|
126
|
-
inflect.actor(/e$/, 'er')
|
127
|
-
inflect.actor(/ate$/, 'ator')
|
128
|
-
inflect.actor(/([^aeiou])([aeiou])([^aeioux])$/, '\1\2\3\3er')
|
129
|
-
inflect.actor(/ct$/, 'ctor')
|
130
|
-
inflect.actor(/^(improvi[sz])e$/, '\1or')
|
131
|
-
inflect.actor(/^(authori)[sz]e$/, '\1ty')
|
132
|
-
inflect.actor(/^administer$/, 'administrator')
|
133
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Credentials
|
2
|
-
module Rules
|
3
|
-
class Cannot < Can
|
4
|
-
def allow?(actor, verb, *args)
|
5
|
-
return false unless match? actor, verb, *args
|
6
|
-
result = false
|
7
|
-
result ||= evaluate(@options[:unless], actor, *args) if @options[:unless]
|
8
|
-
result
|
9
|
-
end
|
10
|
-
|
11
|
-
def deny?(actor, verb, *args)
|
12
|
-
return false unless match? actor, verb, *args
|
13
|
-
result = true
|
14
|
-
result &&= evaluate(@options[:if], actor, *args) if @options[:if]
|
15
|
-
result &&= !evaluate(@options[:unless], actor, *args) if @options[:unless]
|
16
|
-
result
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module Credentials
|
2
|
-
module Rules
|
3
|
-
class Rule
|
4
|
-
attr_accessor :verb
|
5
|
-
attr_accessor :options
|
6
|
-
|
7
|
-
def initialize(klass, verb, *args)
|
8
|
-
@klass = klass
|
9
|
-
@verb = verb.to_sym
|
10
|
-
@options = args.last.is_a?(Hash) ? args.pop : {}
|
11
|
-
@pattern = Array(args)
|
12
|
-
end
|
13
|
-
|
14
|
-
def match?(actor, verb, *args)
|
15
|
-
return false unless actor == @klass or actor.is_a?(@klass)
|
16
|
-
return false unless @verb == :any or @verb == verb.to_sym
|
17
|
-
return false unless args.size == @pattern.size
|
18
|
-
@pattern.zip(args).each { |pattern, arg| return false unless !pattern.is_a?(Class) or arg == pattern or arg.is_a?(pattern) }
|
19
|
-
end
|
20
|
-
|
21
|
-
def allow?(actor, verb, *args)
|
22
|
-
return false unless match? actor, verb, *args
|
23
|
-
result = true
|
24
|
-
result &&= evaluate(@options[:if], actor, *args) if @options[:if]
|
25
|
-
result &&= !evaluate(@options[:unless], actor, *args) if @options[:unless]
|
26
|
-
result
|
27
|
-
end
|
28
|
-
|
29
|
-
def deny?(actor, verb, *args)
|
30
|
-
return false unless match? actor, verb, *args
|
31
|
-
result = false
|
32
|
-
result ||= evaluate(@options[:unless], actor, *args) if @options[:unless]
|
33
|
-
result
|
34
|
-
end
|
35
|
-
|
36
|
-
protected
|
37
|
-
def evaluate(fn, actor, *args)
|
38
|
-
case fn
|
39
|
-
when Proc then fn.call(actor, *args)
|
40
|
-
when Symbol, String then actor.send(fn.to_sym, *args)
|
41
|
-
else raise ArgumentError, "expected a proc or a symbol"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|