credentials 1.0.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|