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 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