canard 0.1.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 +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
|