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 ADDED
@@ -0,0 +1,2 @@
1
+ credentials-*.gem
2
+ coverage
data/Rakefile CHANGED
@@ -1,20 +1 @@
1
- require 'rake'
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
@@ -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,7 @@
1
+ module Credentials
2
+ class AllowRule < Rule
3
+ def allow?(*args)
4
+ self.match?(*args)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Credentials
2
+ class DenyRule < Rule
3
+ def deny?(*args)
4
+ self.match?(*args)
5
+ end
6
+ end
7
+ end
@@ -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
@@ -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
- attr_reader :rules
7
+ attr_accessor :klass
8
+ attr_accessor :options
9
+ attr_accessor :rules
4
10
 
5
- def initialize(klass, rules = [])
6
- @rules = rules
7
- @klass = klass
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 can(verb, *args)
11
- @rules << Credentials::Rules::Can.new(@klass, verb, *args)
37
+ def cannot(*args)
38
+ self.rules << DenyRule.new(klass, *args)
12
39
  end
13
40
 
14
- def cannot(verb, *args)
15
- @rules << Credentials::Rules::Cannot.new(@klass, verb, *args)
41
+ def default
42
+ options[:default] && options[:default].to_sym
16
43
  end
17
44
 
18
- def can?(actor, verb, *args)
19
- result = @klass.credential_options[:allow_by_default] || false
20
- @rules.each do |rule|
21
- result = true if rule.allow?(actor, verb, *args)
22
- result = false if rule.deny?(actor, verb, *args)
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
- result
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/class_methods"
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 :extend, Credentials::ClassMethods
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
@@ -0,0 +1,5 @@
1
+ $: << File.dirname(__FILE__) + "/../lib"
2
+ require "credentials"
3
+ require "spec"
4
+
5
+ require File.join(File.dirname(__FILE__), "domain.rb")
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: 1.0.1
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-04-23 00:00:00 +12:00
12
+ date: 2009-11-11 00:00:00 +13:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
- description: Credentials is a generic actor/resource permission framework based on rules, not objects.
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
- - generators/credentials/credentials_generator.rb
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
- - LICENSE
39
- - Manifest.txt
40
- - Rakefile
41
- - README.rdoc
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: credentials
74
+ rubyforge_project:
68
75
  rubygems_version: 1.3.5
69
76
  signing_key:
70
77
  specification_version: 3
71
- summary: Credentials is a generic actor/resource permission framework based on rules, not objects.
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
@@ -1,8 +0,0 @@
1
- Description:
2
- Explain the generator
3
-
4
- Example:
5
- ./script/generate credentials Thing
6
-
7
- This will create:
8
- what/will/it/create
@@ -1,8 +0,0 @@
1
- class CredentialsGenerator < Rails::Generator::NamedBase
2
- def manifest
3
- record do |m|
4
- # m.directory "lib"
5
- # m.template 'README', "README"
6
- end
7
- end
8
- end
@@ -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,6 +0,0 @@
1
- module Credentials
2
- module Rules
3
- class Can < Rule
4
- end
5
- end
6
- 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