canard 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +41 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +128 -0
- data/Rakefile +9 -0
- data/TODO +5 -0
- data/canard.gemspec +26 -0
- data/lib/ability.rb +41 -0
- data/lib/canard.rb +12 -0
- data/lib/canard/find_abilities.rb +31 -0
- data/lib/canard/railtie.rb +20 -0
- data/lib/canard/user_model.rb +15 -0
- data/lib/canard/version.rb +3 -0
- data/lib/generators/ability_definition.rb +43 -0
- data/lib/generators/canard/ability/USAGE +3 -0
- data/lib/generators/canard/ability/ability_generator.rb +27 -0
- data/lib/generators/canard/ability/templates/abilities.rb.erb +32 -0
- data/lib/generators/rspec/ability/ability_generator.rb +31 -0
- data/lib/generators/rspec/ability/templates/abilities_spec.rb.erb +55 -0
- data/test/abilities/admins.rb +9 -0
- data/test/canard_test.rb +50 -0
- data/test/models/user.rb +4 -0
- data/test/models/user_without_role.rb +5 -0
- data/test/models/user_without_role_mask.rb +4 -0
- data/test/test_helper.rb +58 -0
- data/test/user_model_test.rb +58 -0
- metadata +134 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
canard (0.0.1)
|
5
|
+
cancan
|
6
|
+
role_model
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activemodel (3.1.0)
|
12
|
+
activesupport (= 3.1.0)
|
13
|
+
bcrypt-ruby (~> 3.0.0)
|
14
|
+
builder (~> 3.0.0)
|
15
|
+
i18n (~> 0.6)
|
16
|
+
activerecord (3.1.0)
|
17
|
+
activemodel (= 3.1.0)
|
18
|
+
activesupport (= 3.1.0)
|
19
|
+
arel (~> 2.2.1)
|
20
|
+
tzinfo (~> 0.3.29)
|
21
|
+
activesupport (3.1.0)
|
22
|
+
multi_json (~> 1.0)
|
23
|
+
arel (2.2.1)
|
24
|
+
bcrypt-ruby (3.0.0)
|
25
|
+
builder (3.0.0)
|
26
|
+
cancan (1.6.5)
|
27
|
+
i18n (0.6.0)
|
28
|
+
minitest (2.5.1)
|
29
|
+
multi_json (1.0.3)
|
30
|
+
role_model (0.7.0)
|
31
|
+
sqlite3 (1.3.4)
|
32
|
+
tzinfo (0.3.29)
|
33
|
+
|
34
|
+
PLATFORMS
|
35
|
+
ruby
|
36
|
+
|
37
|
+
DEPENDENCIES
|
38
|
+
activerecord
|
39
|
+
canard!
|
40
|
+
minitest (~> 2)
|
41
|
+
sqlite3
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 [name of plugin creator]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
= Canard
|
2
|
+
|
3
|
+
Canard brings CanCan and RoleModel together to make role based authorization in Rails easy. Your ability
|
4
|
+
definitions gain their own folder and a little structure. The easiest way to get started is with the
|
5
|
+
Canard generator. Canard progressively enhances the abilities of the model by applying role abilities on
|
6
|
+
top of the models base abilities.
|
7
|
+
|
8
|
+
A User model with :admin and :manger roles would be defined:
|
9
|
+
|
10
|
+
class User < ActiveRecord::Base
|
11
|
+
|
12
|
+
acts_as_user :roles => :admin, :manager
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
Lets generate some abilities for the User.
|
17
|
+
|
18
|
+
$ rails g canard:ability user can:[read,create]:[account,statement] cannot:destroy:account
|
19
|
+
create abilities/users.rb
|
20
|
+
invoke rspec
|
21
|
+
create spec/abilities/user_spec.rb
|
22
|
+
|
23
|
+
Generates an ability folder in Rails root and an associated spec;
|
24
|
+
|
25
|
+
abilities/
|
26
|
+
users.rb
|
27
|
+
spec/abilities/
|
28
|
+
users_spec.rb
|
29
|
+
|
30
|
+
The resulting abilities/users.rb will look something like this;
|
31
|
+
|
32
|
+
abilities_for(:user) do
|
33
|
+
|
34
|
+
can [:read, :create], Account
|
35
|
+
cannot [:destroy], Account
|
36
|
+
can [:read, :create], Statement
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
And it's associated test spec/abilities/users_spec.rb;
|
41
|
+
|
42
|
+
require_relative '../spec_helper'
|
43
|
+
require "cancan/matchers"
|
44
|
+
|
45
|
+
describe Ability, "for :user" do
|
46
|
+
|
47
|
+
before do
|
48
|
+
@user = Factory.create(:user_user)
|
49
|
+
end
|
50
|
+
|
51
|
+
subject { Ability.new(@user) }
|
52
|
+
|
53
|
+
describe 'on Account' do
|
54
|
+
|
55
|
+
before do
|
56
|
+
@account = Factory.create(:account)
|
57
|
+
end
|
58
|
+
|
59
|
+
it { should be_able_to( :read, @account ) }
|
60
|
+
it { should be_able_to( :create, @account ) }
|
61
|
+
it { should_not be_able_to( :destroy, @account ) }
|
62
|
+
|
63
|
+
end
|
64
|
+
# on Account
|
65
|
+
|
66
|
+
describe 'on Statement' do
|
67
|
+
|
68
|
+
before do
|
69
|
+
@statement = Factory.create(:statement)
|
70
|
+
end
|
71
|
+
|
72
|
+
it { should be_able_to( :read, @statement ) }
|
73
|
+
it { should be_able_to( :create, @statement ) }
|
74
|
+
|
75
|
+
end
|
76
|
+
# on Statement
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
Now lets generate some abilities for the manager and admin.
|
81
|
+
|
82
|
+
$ rails g canard:ability admin can:manage:[account,statement]
|
83
|
+
$ rails g canard:ability manager can:edit:statement
|
84
|
+
|
85
|
+
Will give us two new sets of abilities in the abilities folder. Canard will apply these abilities by first
|
86
|
+
loading the ability for the User model and then apply the abilities for each role the current user has.
|
87
|
+
|
88
|
+
Canard also creates a guest ability by default so:
|
89
|
+
|
90
|
+
$ rails g canard:ability guest can:create:user
|
91
|
+
|
92
|
+
Would generate an ability for a not logged in user to signup.
|
93
|
+
|
94
|
+
Obviously the generators are just a starting point and should not be used only to get you going. I strongly
|
95
|
+
suggest that every new model you create you add to the abilities as the specs are so easy to write and CanCan
|
96
|
+
definitions are so clear and simple.
|
97
|
+
|
98
|
+
== Installation
|
99
|
+
|
100
|
+
=== Rails 3.x
|
101
|
+
|
102
|
+
Add the canard gem to your Gemfile. In Gemfile:
|
103
|
+
|
104
|
+
gem "canard"
|
105
|
+
|
106
|
+
That's it!
|
107
|
+
|
108
|
+
=== Rails 2.x
|
109
|
+
|
110
|
+
Sorry you are out of luck with Rails 2.x Canard has only been written and tested with Rails 3.x. I'll be happy
|
111
|
+
to accept pull requests for tested Rails 2.x updates if anybody is game.
|
112
|
+
|
113
|
+
== Note on Patches/Pull Request
|
114
|
+
|
115
|
+
* Fork the project.
|
116
|
+
* Make your feature addition or bug fix.
|
117
|
+
* Add tests for it (when I have some). This is important so I don't break it in a future version unintentionally.
|
118
|
+
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but
|
119
|
+
bump version in a commit by itself I can ignore it when I pull)
|
120
|
+
* Send me a pull request. Bonus points for topic branches.
|
121
|
+
|
122
|
+
== Credits
|
123
|
+
|
124
|
+
Thanks to Ryan Bates for creating the awesome CanCan (http://wiki.github.com/ryanb/cancan/role-based-authorization)
|
125
|
+
and Martin Rehfeld for implementing Role Based Authorization in the form of RoleModel (http://github.com/martinrehfeld/role_model).
|
126
|
+
|
127
|
+
== Copyright
|
128
|
+
Copyright (c) 2011 James McCarthy, released under the MIT license
|
data/Rakefile
ADDED
data/TODO
ADDED
data/canard.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "canard/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "canard"
|
7
|
+
s.version = Canard::VERSION
|
8
|
+
s.authors = ["James McCarthy"]
|
9
|
+
s.email = ["james2mccarthy@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Adds RoleModel roles to CanCan.}
|
12
|
+
s.description = %q{Wraps CanCan and RoleModel up with some scopes}
|
13
|
+
|
14
|
+
s.rubyforge_project = "canard"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "minitest", "~> 2"
|
22
|
+
s.add_development_dependency "sqlite3"
|
23
|
+
s.add_development_dependency "activerecord"
|
24
|
+
s.add_runtime_dependency "cancan"
|
25
|
+
s.add_runtime_dependency "role_model"
|
26
|
+
end
|
data/lib/ability.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
class Ability
|
2
|
+
|
3
|
+
include CanCan::Ability
|
4
|
+
|
5
|
+
def initialize(object=nil)
|
6
|
+
|
7
|
+
# If a user was passed set the user from it.
|
8
|
+
@user = object.is_a?(Account) ? object.user : object
|
9
|
+
|
10
|
+
if @user
|
11
|
+
# Add the base user abilities.
|
12
|
+
load_abilities @user.class.name.underscore.to_sym
|
13
|
+
else
|
14
|
+
# If user not set then lets create a guest
|
15
|
+
@user = Object.new
|
16
|
+
load_abilities :guest
|
17
|
+
end
|
18
|
+
|
19
|
+
# If user has roles get those abilities
|
20
|
+
if @user.respond_to?(:roles)
|
21
|
+
# Add roles on top of the base user abilities
|
22
|
+
@user.roles.each { |role| load_abilities(role) }
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def user
|
30
|
+
@user
|
31
|
+
end
|
32
|
+
|
33
|
+
def ability_definitions
|
34
|
+
Canard.ability_definitions
|
35
|
+
end
|
36
|
+
|
37
|
+
def load_abilities(role)
|
38
|
+
instance_eval(&ability_definitions[role]) if ability_definitions.has_key?(role)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/lib/canard.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'cancan'
|
2
|
+
require 'role_model'
|
3
|
+
require "canard/version"
|
4
|
+
require "canard/find_abilities"
|
5
|
+
require "ability"
|
6
|
+
|
7
|
+
module Canard
|
8
|
+
autoload :UserModel, 'canard/user_model'
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'canard/railtie' if defined?(Rails) && Rails::VERSION::MAJOR >= 3
|
12
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Canard
|
2
|
+
|
3
|
+
class << self
|
4
|
+
# A string specifying the location that should be searched for ability
|
5
|
+
# definitions. By default, Canard will attempt to load abilities from
|
6
|
+
# Rails.root + /abilities/.
|
7
|
+
attr_accessor :abilities_path
|
8
|
+
|
9
|
+
def ability_definitions
|
10
|
+
@ability_definitions ||= {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def abilities_for(role, &block)
|
14
|
+
ability_definitions[role] = block
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.find_abilities #:nodoc:
|
20
|
+
|
21
|
+
absolute_abilities_path = File.expand_path(abilities_path)
|
22
|
+
|
23
|
+
if File.directory? absolute_abilities_path
|
24
|
+
Dir[File.join(absolute_abilities_path, '**', '*.rb')].sort.each do |file|
|
25
|
+
self.class_eval File.read(file)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'canard'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
module Canard
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
|
7
|
+
initializer "canard.active_record" do |app|
|
8
|
+
ActiveSupport.on_load :active_record do
|
9
|
+
extend Canard::UserModel
|
10
|
+
Canard.abilities_path ||= File.expand_path('abilities', Rails.root)
|
11
|
+
Canard.find_abilities
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
initializer "canard.abilities_reloading", :after => "action_dispatch.configure" do |app|
|
16
|
+
ActionDispatch::Reloader.to_prepare { Canard.find_abilities }
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Canard
|
2
|
+
|
3
|
+
module UserModel
|
4
|
+
|
5
|
+
def acts_as_user(*args)
|
6
|
+
include RoleModel
|
7
|
+
|
8
|
+
options = args.extract_options!.symbolize_keys
|
9
|
+
|
10
|
+
roles options[:roles] if options.has_key?(:roles) && column_names.include?(roles_attribute_name.to_s)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
|
3
|
+
class AbilityDefinition
|
4
|
+
|
5
|
+
attr_accessor :cans, :cannots
|
6
|
+
|
7
|
+
def self.parse(definitions)
|
8
|
+
@@ability_definitions ||= {}
|
9
|
+
limitation, ability_names, model_names = *definitions.split(':')
|
10
|
+
abilities, models = extract(ability_names), extract(model_names)
|
11
|
+
models.each do |model|
|
12
|
+
definition = @@ability_definitions[model] || AbilityDefinition.new
|
13
|
+
definition.merge(limitation.pluralize, abilities)
|
14
|
+
@@ability_definitions[model] = definition
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.extract(string)
|
19
|
+
return *string.gsub(/[\[\]\s]/, '').split(',')
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.models
|
23
|
+
@@ability_definitions
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@cans, @cannots = [], []
|
28
|
+
end
|
29
|
+
|
30
|
+
def merge(limitation, abilities)
|
31
|
+
combined_abilities = instance_variable_get("@#{limitation}") | abilities
|
32
|
+
instance_variable_set("@#{limitation}", combined_abilities)
|
33
|
+
end
|
34
|
+
|
35
|
+
def can
|
36
|
+
@cans
|
37
|
+
end
|
38
|
+
|
39
|
+
def cannot
|
40
|
+
@cannots
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative '../../ability_definition'
|
2
|
+
|
3
|
+
module Canard
|
4
|
+
module Generators
|
5
|
+
class AbilityGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
argument :ability_definitions, :type => :array, :default => [], :banner => "can:[read,update]:[user,account] cannot:[create,destroy]:user"
|
8
|
+
|
9
|
+
def generate_ability
|
10
|
+
template "abilities.rb.erb", Canard.abilities_path + "/#{file_name.pluralize}.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
hook_for :test_framework, :as => 'ability'
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def definitions(&block)
|
18
|
+
ability_definitions.each { |definition| AbilityDefinition.parse(definition) }
|
19
|
+
|
20
|
+
AbilityDefinition.models.sort.each do |model, definition|
|
21
|
+
yield model, definition
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
abilities_for(<%= ":#{name}" -%>) do
|
2
|
+
|
3
|
+
<% if ability_definitions.empty? -%>
|
4
|
+
# Define abilities for the user role here. For example:
|
5
|
+
#
|
6
|
+
# if user.admin?
|
7
|
+
# can :manage, :all
|
8
|
+
# else
|
9
|
+
# can :read, :all
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# The first argument to `can` is the action you are giving the user permission to do.
|
13
|
+
# If you pass :manage it will apply to every action. Other common actions here are
|
14
|
+
# :read, :create, :update and :destroy.
|
15
|
+
#
|
16
|
+
# The second argument is the resource the user can perform the action on. If you pass
|
17
|
+
# :all it will apply to every resource. Otherwise pass a Ruby class of the resource.
|
18
|
+
#
|
19
|
+
# The third argument is an optional hash of conditions to further filter the objects.
|
20
|
+
# For example, here the user can only update published articles.
|
21
|
+
#
|
22
|
+
# can :update, Article, :published => true
|
23
|
+
#
|
24
|
+
# See the wiki for details: https://github.com/ryanb/cancan/wiki/Defining-Abilities
|
25
|
+
<% else -%>
|
26
|
+
<% definitions do |model, definition| -%>
|
27
|
+
<%= "can".ljust(8, ' ') + "#{definition.cans.map(&:to_sym)}, #{model.classify}" unless definition.cans.empty? %>
|
28
|
+
<%= "cannot".ljust(8, ' ') + "#{definition.cannots.map(&:to_sym)}, #{model.classify}" unless definition.cannots.empty? %>
|
29
|
+
<% end -%>
|
30
|
+
<% end -%>
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'generators/rspec'
|
2
|
+
require_relative '../../ability_definition'
|
3
|
+
|
4
|
+
module Rspec
|
5
|
+
module Generators
|
6
|
+
class AbilityGenerator < Base
|
7
|
+
@_rspec_source_root = File.expand_path('../templates', __FILE__)
|
8
|
+
argument :ability_definitions, :type => :array, :default => [], :banner => "can:abilities:models cannot:abilities:models"
|
9
|
+
|
10
|
+
def generate_ability_spec
|
11
|
+
template "abilities_spec.rb.erb", "spec/abilities/#{file_name}_spec.rb"
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def add_new_abilities
|
17
|
+
gsub_file "spec/abilities/#{file_name}_spec.rb", /^(\s*end\s*\Z)/, 'wibble' + '\1'
|
18
|
+
end
|
19
|
+
|
20
|
+
def definitions(&block)
|
21
|
+
ability_definitions.each { |definition| AbilityDefinition.parse(definition) }
|
22
|
+
|
23
|
+
AbilityDefinition.models.sort.each do |model, definition|
|
24
|
+
yield model, definition
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
require "cancan/matchers"
|
4
|
+
|
5
|
+
describe Ability, "for :<%= name %>" do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@<%= name %> = Factory.create(:<%= name %>_user)
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { Ability.new(@<%= name -%>) }
|
12
|
+
|
13
|
+
<% if ability_definitions.empty? -%>
|
14
|
+
# Define your ability tests thus;
|
15
|
+
#
|
16
|
+
# describe 'on Activity' do
|
17
|
+
#
|
18
|
+
# before do
|
19
|
+
# @activity = Factory.create(:activity)
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# it { should be_able_to( :index, Activity ) }
|
23
|
+
# it { should be_able_to( :show, @activity ) }
|
24
|
+
# it { should be_able_to( :read, @activity ) }
|
25
|
+
# it { should be_able_to( :new, @activity ) }
|
26
|
+
# it { should be_able_to( :create, @activity ) }
|
27
|
+
# it { should be_able_to( :edit, @activity ) }
|
28
|
+
# it { should be_able_to( :update, @activity ) }
|
29
|
+
# it { should be_able_to( :destroy, @activity ) }
|
30
|
+
#
|
31
|
+
# end
|
32
|
+
# # on Activity
|
33
|
+
<% else -%>
|
34
|
+
<% definitions do |model, definition| -%>
|
35
|
+
|
36
|
+
describe 'on <%= model.camelize -%>' do
|
37
|
+
|
38
|
+
before do
|
39
|
+
@<%= model -%> = Factory.create(:<%= model -%>)
|
40
|
+
end
|
41
|
+
|
42
|
+
<% definition.cans.each do |can| -%>
|
43
|
+
it { should be_able_to( <%= ":#{can},".ljust(12, ' ') + (can == 'index' ? model.camelize : "@#{model}") -%> ) }
|
44
|
+
<% end -%>
|
45
|
+
<%- definition.cannots.each do |cannot| -%>
|
46
|
+
it { should_not be_able_to( <%= ":#{cannot},".ljust(12, ' ') + (cannot == 'index' ? model.camelize : "@#{model}") -%> ) }
|
47
|
+
<% end -%>
|
48
|
+
|
49
|
+
end
|
50
|
+
# on <%= model.camelize %>
|
51
|
+
<% end -%>
|
52
|
+
|
53
|
+
<% end -%>
|
54
|
+
end
|
55
|
+
|
data/test/canard_test.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require_relative '../lib/canard.rb'
|
3
|
+
|
4
|
+
describe Canard do
|
5
|
+
|
6
|
+
before do
|
7
|
+
class User < ActiveRecord::Base
|
8
|
+
end
|
9
|
+
|
10
|
+
Canard.abilities_path = File.expand_path('../abilities', __FILE__)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Sanity test
|
14
|
+
it "must be an user" do
|
15
|
+
user = User.new
|
16
|
+
user.must_be_instance_of User
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "abilities_path" do
|
20
|
+
|
21
|
+
it "should be mutable" do
|
22
|
+
Canard.abilities_path = 'app/abilities'
|
23
|
+
Canard.abilities_path.must_equal 'app/abilities'
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "ability_definitions" do
|
29
|
+
|
30
|
+
it "should be an accessor" do
|
31
|
+
Canard.must_respond_to(:ability_definitions)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should be a hash" do
|
35
|
+
Canard.ability_definitions.must_be_instance_of Hash
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "find_abilities" do
|
41
|
+
|
42
|
+
it "should load the abilities into ability_definitions" do
|
43
|
+
Canard.find_abilities
|
44
|
+
|
45
|
+
Canard.ability_definitions.keys.must_include :admin
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
data/test/models/user.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'minitest'
|
3
|
+
require 'active_record'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
module MiniTestWithHooks
|
7
|
+
class Unit < MiniTest::Unit
|
8
|
+
def before_suites
|
9
|
+
end
|
10
|
+
|
11
|
+
def after_suites
|
12
|
+
end
|
13
|
+
|
14
|
+
def _run_suites(suites, type)
|
15
|
+
begin
|
16
|
+
before_suites
|
17
|
+
super(suites, type)
|
18
|
+
ensure
|
19
|
+
after_suites
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module MiniTestWithActiveRecord
|
26
|
+
class Unit < MiniTestWithHooks::Unit
|
27
|
+
|
28
|
+
def before_suites
|
29
|
+
super
|
30
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
31
|
+
ActiveRecord::Migration.verbose = false
|
32
|
+
|
33
|
+
@migration = Class.new(ActiveRecord::Migration) do
|
34
|
+
|
35
|
+
def change
|
36
|
+
create_table :users, :force => true do |t|
|
37
|
+
t.string :roles_mask
|
38
|
+
end
|
39
|
+
create_table :user_without_roles, :force => true do |t|
|
40
|
+
t.string :roles_mask
|
41
|
+
end
|
42
|
+
create_table :user_without_role_masks, :force => true do |t|
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
@migration.new.migrate(:up)
|
49
|
+
end
|
50
|
+
|
51
|
+
def after_suites
|
52
|
+
@migration.new.migrate(:down)
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
MiniTest::Unit.runner = MiniTestWithActiveRecord::Unit.new
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'canard'
|
3
|
+
|
4
|
+
describe Canard::UserModel do
|
5
|
+
|
6
|
+
before do
|
7
|
+
Canard.abilities_path = 'abilities'
|
8
|
+
require 'models/user'
|
9
|
+
require 'models/user_without_role'
|
10
|
+
require 'models/user_without_role_mask'
|
11
|
+
end
|
12
|
+
|
13
|
+
# Sanity test
|
14
|
+
it "must be an user" do
|
15
|
+
user = User.new
|
16
|
+
user.must_be_instance_of User
|
17
|
+
user = UserWithoutRole.new
|
18
|
+
user.must_be_instance_of UserWithoutRole
|
19
|
+
user = UserWithoutRoleMask.new
|
20
|
+
user.must_be_instance_of UserWithoutRoleMask
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'acts_as_user' do
|
24
|
+
|
25
|
+
it 'should add role_model to this model' do
|
26
|
+
User.included_modules.must_include RoleModel
|
27
|
+
User.must_respond_to :roles
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'on a model with a role mask' do
|
31
|
+
|
32
|
+
describe 'and :roles => [] specified' do
|
33
|
+
|
34
|
+
it 'should set the valid_roles for the class' do
|
35
|
+
User.valid_roles.must_equal [:admin, :author, :viewer]
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'with no :roles => [] specified' do
|
41
|
+
|
42
|
+
it 'should not set any roles' do
|
43
|
+
UserWithoutRole.valid_roles.must_equal []
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'with no roles_mask' do
|
50
|
+
|
51
|
+
it 'should not set any roles' do
|
52
|
+
UserWithoutRole.valid_roles.must_equal []
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: canard
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- James McCarthy
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-02 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: minitest
|
16
|
+
requirement: &2153074000 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2153074000
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: sqlite3
|
27
|
+
requirement: &2153073580 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2153073580
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: activerecord
|
38
|
+
requirement: &2153073120 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2153073120
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: cancan
|
49
|
+
requirement: &2153072700 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2153072700
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: role_model
|
60
|
+
requirement: &2153072280 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2153072280
|
69
|
+
description: Wraps CanCan and RoleModel up with some scopes
|
70
|
+
email:
|
71
|
+
- james2mccarthy@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- Gemfile.lock
|
79
|
+
- MIT-LICENSE
|
80
|
+
- README.rdoc
|
81
|
+
- Rakefile
|
82
|
+
- TODO
|
83
|
+
- canard.gemspec
|
84
|
+
- lib/ability.rb
|
85
|
+
- lib/canard.rb
|
86
|
+
- lib/canard/find_abilities.rb
|
87
|
+
- lib/canard/railtie.rb
|
88
|
+
- lib/canard/user_model.rb
|
89
|
+
- lib/canard/version.rb
|
90
|
+
- lib/generators/ability_definition.rb
|
91
|
+
- lib/generators/canard/ability/USAGE
|
92
|
+
- lib/generators/canard/ability/ability_generator.rb
|
93
|
+
- lib/generators/canard/ability/templates/abilities.rb.erb
|
94
|
+
- lib/generators/rspec/ability/ability_generator.rb
|
95
|
+
- lib/generators/rspec/ability/templates/abilities_spec.rb.erb
|
96
|
+
- test/abilities/admins.rb
|
97
|
+
- test/canard_test.rb
|
98
|
+
- test/models/user.rb
|
99
|
+
- test/models/user_without_role.rb
|
100
|
+
- test/models/user_without_role_mask.rb
|
101
|
+
- test/test_helper.rb
|
102
|
+
- test/user_model_test.rb
|
103
|
+
homepage: ''
|
104
|
+
licenses: []
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project: canard
|
123
|
+
rubygems_version: 1.8.6
|
124
|
+
signing_key:
|
125
|
+
specification_version: 3
|
126
|
+
summary: Adds RoleModel roles to CanCan.
|
127
|
+
test_files:
|
128
|
+
- test/abilities/admins.rb
|
129
|
+
- test/canard_test.rb
|
130
|
+
- test/models/user.rb
|
131
|
+
- test/models/user_without_role.rb
|
132
|
+
- test/models/user_without_role_mask.rb
|
133
|
+
- test/test_helper.rb
|
134
|
+
- test/user_model_test.rb
|