moulin_rouge 0.0.1.beta1 → 0.0.1.beta2

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.
@@ -1,6 +1,11 @@
1
1
  CHANGELOG
2
2
  =========
3
3
 
4
+ 0.0.1.beta2 (Mar 28, 2011)
5
+
6
+ * Instead of declarate the authorization in plain ruby file, that could break spec and other things, manage the scope to the MoulinRouge::Authorization class
7
+ * Changing the name of the generator to match the name changes
8
+
4
9
  0.0.1.beta (Mar 16, 2011)
5
10
 
6
11
  * Implementing the generators
@@ -1,4 +1,4 @@
1
- Copyright 2012 YOURNAME
1
+ Copyright 2012 Edson Hilios
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  Moulin Rouge
2
2
  ============
3
3
 
4
- **Moulin Rouge** is a DSL to manage your permissions and groups of access outside the [CanCan](https://github.com/ryanb/cancan) Ability class. It will help you organize and declare your permissions with has much ruby files you judge necessary, that are automatically pushed to CanCan authorization system. It is also decoupled from the role system.
4
+ **Moulin Rouge** offers a custom and easy DSL to manage your authorizations and groups of access with [CanCan](https://github.com/ryanb/cancan). The main feature is the ability to split your authorizations in many ruby files, that are automatically pushed to CanCan authorization system. It is also decoupled from any role system giving you flexibility.
5
5
 
6
- There are a bunch of examples bellow to show you how to implement.
6
+ There are a bunch of examples bellow to show you how to get started and explaining all features.
7
7
 
8
8
  Installation
9
9
  ------------
@@ -22,13 +22,15 @@ Run the generator to install the roles and permissions structure:
22
22
 
23
23
  Generate a permission file:
24
24
 
25
- rails g moulin_rouge:permission <name>
25
+ rails g moulin_rouge:auth <name>
26
26
 
27
27
  Add your permissions to newly created file:
28
28
 
29
29
  ```ruby
30
- role :name do
31
- can :read, :something
30
+ class UserAuthorization < MoulinRouge::Authorization
31
+ role :name do
32
+ can :read, :something
33
+ end
32
34
  end
33
35
  ```
34
36
 
@@ -41,33 +43,35 @@ First of all, you have to accept that the role registering belongs to the ruby c
41
43
 
42
44
  When you run:
43
45
 
44
- bundle g moulinrouge:install
46
+ bundle g moulin_rouge:install
45
47
 
46
48
  This will create the following folder structure:
47
49
 
48
50
  root
49
51
  | app/
50
- | | permissions/
52
+ | | authorizations/
51
53
  | config/
52
54
  | | initalizers
53
55
  | | | moulin_rouge.rb
54
56
 
55
57
  ### Defining roles ###
56
58
 
57
- All your permission files will be stored inside the `app/permissions` folder. Just create a ruby file inside and the definitions will be automatically defined.
59
+ All your authorization files will be stored inside the `app/authorizations` folder. Just create a ruby file inside and the definitions will be automatically defined.
58
60
 
59
61
  ```ruby
60
- role :superuser do
61
- can :manage, :all
62
- end
62
+ class UserAuthorization < MoulinRouge::Authorization
63
+ role :superuser do
64
+ can :manage, :all
65
+ end
63
66
 
64
- role :editors do
65
- can :manage, Articles
66
- end
67
+ role :editors do
68
+ can :manage, Articles
69
+ end
67
70
 
68
- role :authors do
69
- can :manage, Article do |article|
70
- article.user_id == current_user.id
71
+ role :authors do
72
+ can :manage, Article do |article|
73
+ article.user_id == current_user.id
74
+ end
71
75
  end
72
76
  end
73
77
  ```
@@ -78,20 +82,22 @@ Also, the others CanCan methods are avaliable (`cannot`, `can?`, `cannot?`) and
78
82
 
79
83
  ### Groups ###
80
84
 
81
- A group is an easy way to organize your permissions, no matter where file the definition is. All groups with the same name, will have their abilities and permissions nested together.
85
+ A group is an easy way to organize your authorization. All groups with the same name, will have their abilities and authorizations nested together.
82
86
 
83
- The group will delegate all abilities defined into, to their childrens, so any children role or group will have the abilities defined in the parent. Also the group is not an avaliable role, they only serve has namespaces.
87
+ The group will delegate all abilities defined inside of it, to their childrens, so any role or group will have the same abilities defined in the parent. Also the group is not an avaliable role, they only serve has namespaces.
84
88
 
85
89
  ```ruby
86
- group :marketing do
87
- can :read, Dashboard
90
+ class UserAuthorization < MoulinRouge::Authorization
91
+ group :marketing do
92
+ can :read, Dashboard
88
93
 
89
- role :manager do
90
- can :manage, Proposal
91
- end
94
+ role :manager do
95
+ can :manage, Proposal
96
+ end
92
97
 
93
- role :salesman do
94
- can :manage, Proposal, :user_id => current_user.id
98
+ role :salesman do
99
+ can :manage, Proposal, :user_id => current_user.id
100
+ end
95
101
  end
96
102
  end
97
103
  ```
@@ -101,7 +107,7 @@ To avoid name conflicts, whenever you have a nested roles or groups, their name
101
107
  Following the example above, will generate two roles:
102
108
 
103
109
  ```ruby
104
- MoulinRouge::Permission.list
110
+ MoulinRouge::Authorization.defined_roles
105
111
  # => [:marketing_manager, :marketing_salesman]
106
112
  # => :marketing_manager => can :read, Dashboard, can :manage, Proposal
107
113
  # => :marketing_salesman => can :read, Dashboard, can :manage, Proposal, :user_id => current_user.id
@@ -112,11 +118,13 @@ MoulinRouge::Permission.list
112
118
  When you have nested rules, they will act has namespaces, no ability will be shared unless is explicited with the `include` method.
113
119
 
114
120
  ```ruby
115
- role :marketing do
116
- can :manage, Proposal
121
+ class UserAuthorization < MoulinRouge::Authorization
122
+ role :marketing do
123
+ can :manage, Proposal
117
124
 
118
- role :salesman do
119
- can :read, Proposal
125
+ role :salesman do
126
+ can :read, Proposal
127
+ end
120
128
  end
121
129
  end
122
130
  ```
@@ -124,7 +132,7 @@ end
124
132
  Following the example above, this will generate two roles with the abilities:
125
133
 
126
134
  ```ruby
127
- MoulinRouge::Permission.list
135
+ MoulinRouge::Authorization.defined_roles
128
136
  # => [:marketing, :marketing_salesman]
129
137
  # => :marketing => can :manage, Proposal
130
138
  # => :marketing_salesman => can :read, Proposal
@@ -132,19 +140,21 @@ MoulinRouge::Permission.list
132
140
 
133
141
  ### Extending ###
134
142
 
135
- Many times you want to extend a role from another one, **MoulinRouge** let you `include` the abilities from one role to another, all the abilities from the target will be appended to the caller.
143
+ If you want extend the abilities from a role to another, **MoulinRouge** let you `include` them automatically. All the abilities from the target will be appended to the caller.
136
144
 
137
- Only roles can be included, and if you provide a name that isn't defined, a `RoleNotFound` will be raised. Notice by the example bellow, that you should provide the full name of the role in order to find the correct one.
145
+ Only roles can be included, and if you provide a name that is not defined, a `RoleNotFound` will be raised. *Notice* by the example bellow, that you should provide the full name of the role in order to find them.
138
146
 
139
147
  ```ruby
140
- group :marketing do
141
- role :admin do
142
- can :do, :something
148
+ class UserAuthorization < MoulinRouge::Authorization
149
+ group :marketing do
150
+ role :admin do
151
+ can :do, :something
152
+ end
143
153
  end
144
- end
145
154
 
146
- role :super do
147
- include :marketing_admin
155
+ role :super do
156
+ include :marketing_admin
157
+ end
148
158
  end
149
159
  ```
150
160
 
@@ -153,15 +163,15 @@ Configuration
153
163
 
154
164
  ```ruby
155
165
  MoulinRouge.configure do |config|
156
- # Cache permissions
166
+ # Cache authorizations
157
167
  config.cache = Rails.env.production?
158
- # The search path for permissions
159
- config.path = 'app/permissions/**/*.rb'
160
- # The method that will test the permission
168
+ # Path for search the authorizations files
169
+ config.path = 'app/authorizations/**/*.rb'
170
+ # Method name that will send to the user to test if the role is assigned to him
161
171
  config.test_method = :is?
162
- # The class of the model
172
+ # Your user model
163
173
  config.model = User
164
- # How you like to call the active user model
174
+ # The method name that will access the current user information
165
175
  config.model_instance = :current_user
166
176
  end
167
177
  ```
@@ -169,7 +179,7 @@ end
169
179
  Goodies
170
180
  -------
171
181
 
172
- For those who like I dislikes the `load_and_authorize_resource` method from CanCan, here is provided a cleaner and more flexible solution through `ActionController::Responder`, the `MoulinRouge::CanCan::Responder` bellow there are instruction to activate them.
182
+ For those who does not like the `load_and_authorize_resource` method from CanCan, here is provided a cleaner and more flexible solution through `ActionController::Responder`, the `MoulinRouge::CanCan::Responder` bellow there are instruction to activate them.
173
183
 
174
184
  Create the file `lib/application_responder.rb` with the following:
175
185
 
@@ -198,8 +208,17 @@ More about the `Responder` class:
198
208
  * http://blog.plataformatec.com.br/2009/08/embracing-rest-with-mind-body-and-soul/
199
209
  * http://archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with/
200
210
 
211
+ Testing
212
+ -------
213
+
214
+ This gem uses the [RSpec-2](https://www.relishapp.com/rspec) lib for BDD testing, with the help of [Guard](https://github.com/guard/guard) to autotest. For development just execute the following line:
215
+
216
+ bundle exec guard
217
+
218
+ And it will perform all tests, and reload every time you implement something new. Also you can follow the test coverage by [simplecov](https://github.com/colszowka/simplecov).
219
+
201
220
  Thanks
202
- =======
221
+ ------
203
222
 
204
223
  * [Troles](https://github.com/kristianmandrup/trole)
205
224
  * [CanTango](https://github.com/kristianmandrup/cantango)
@@ -209,7 +228,9 @@ Thanks
209
228
 
210
229
  Mouling Rouge is a cabaret in Paris best know as the birthplace on modern [CanCan](https://github.com/ryanb/cancan) second to [Wikipedia](http://en.wikipedia.org/wiki/Moulin_Rouge).
211
230
 
212
- Credits
213
- =======
231
+ Copyrights
232
+ ----------
233
+
234
+ Copyrights 2012 [**Edson Hilios**](http://edson.hilios.com.br) edson (at) hilios (dot) com (dot) br
214
235
 
215
- **Edson Hilios** <edson (at) hilios (dot) com (dot) br>
236
+ This software is licensed under [MIT-LICENSE](https://github.com/hilios/moulin_rouge/blob/master/MIT-LICENSE)
@@ -0,0 +1,18 @@
1
+ require 'rails/generators'
2
+
3
+ module MoulinRouge
4
+ module Generators
5
+ class AuthGenerator < ::Rails::Generators::Base
6
+
7
+ source_root File.expand_path('../templates', __FILE__)
8
+
9
+ desc "Creates a new authorization file"
10
+
11
+ argument :name
12
+
13
+ def creates_an_authorization_file
14
+ copy_file("authorization.rb", "app/authorizations/#{name}_authorization.rb")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -6,11 +6,11 @@ module MoulinRouge
6
6
 
7
7
  source_root File.expand_path('../templates', __FILE__)
8
8
 
9
- desc "Installs the gem folder structure for the app"
9
+ desc "Installs the gem folder structure"
10
10
 
11
11
  def generate_folder_structure
12
- directory("install", "./")
13
- generate("moulin_rouge:permission", "admin")
12
+ initializer("moulin_rouge.rb", "initializer.rb")
13
+ generate("moulin_rouge:permission", "user")
14
14
  end
15
15
  end
16
16
  end
@@ -0,0 +1,21 @@
1
+ class <%= name.camelize %>Authorization < MoulinRouge::Authorization
2
+ # can :read, Post
3
+ # can :read, Comment
4
+ # can :manage, Comment do |comment|
5
+ # comment.user_id == current_user.id
6
+ # end
7
+ #
8
+ # role :admin do
9
+ # can :manage, :all
10
+ # end
11
+ #
12
+ # group :main do
13
+ # role :editor do
14
+ # can :manage, Post
15
+ # end
16
+ #
17
+ # role :author do
18
+ # can :manage, Post, :user_id => current_user.id
19
+ # end
20
+ # end
21
+ end
@@ -0,0 +1,14 @@
1
+ MoulinRouge.configure do |config|
2
+ # Cache authorizations
3
+ config.cache = Rails.env.production?
4
+ # Path for search the authorizations files
5
+ config.path = 'app/authorizations/**/*.rb'
6
+ # Method name that will send to the user to test if the role is assigned to him
7
+ config.test_method = :is?
8
+ # Your user model
9
+ config.model = User
10
+ # The method name that will access the current user information
11
+ config.model_instance = :current_user
12
+ end
13
+
14
+ MoulinRouge.run! # Creates the Ability class
@@ -23,7 +23,7 @@ module MoulinRouge
23
23
 
24
24
  # Import all permission files in the configuration
25
25
  def self.load!
26
- MoulinRouge::Permission.main.import(MoulinRouge.configuration.path)
26
+ MoulinRouge::Authorization.compile!
27
27
  end
28
28
 
29
29
  # Returns true if the run! method was called and false oterwise
@@ -39,6 +39,6 @@ module MoulinRouge
39
39
 
40
40
  # Reset all constants
41
41
  def self.reset! #:nodoc:
42
- MoulinRouge::Permission.reset!
42
+ MoulinRouge::Authorization.reset!
43
43
  end
44
44
  end
@@ -1,7 +1,7 @@
1
1
  module MoulinRouge
2
2
  class RoleNotFound < Exception; end
3
- # A wrapper to catch and store the DSL methods
4
- class Permission
3
+ # The CanCan wrapper with the custom DSL methods
4
+ class Ability
5
5
  CANCAN_METHODS = [:can, :cannot, :can?, :cannot?]
6
6
  # Returns a string with the given name
7
7
  attr_reader :singular_name
@@ -22,11 +22,12 @@ module MoulinRouge
22
22
  @is_group = options.delete(:group)
23
23
  abilities.concat(parent.abilities) if not parent.nil? and parent.group?
24
24
  instance_eval(&block) if block_given?
25
- # Store this permission
26
- self.class.add(self) unless parent.nil? or @is_group
25
+ # Register this ability
26
+ MoulinRouge::Authorization.register(self) unless parent.nil? or group?
27
27
  end
28
28
 
29
- def method_missing(name, *args, &block)
29
+ # Stores the CanCan methods and current_user method to later evaluation
30
+ def method_missing(name, *args, &block) #:nodoc:
30
31
  return store_method(name, *args, &block) if CANCAN_METHODS.include?(name)
31
32
  return MoulinRouge::ModelDouble.new if MoulinRouge.configuration.model_instance == name
32
33
  super(name, *args, &block)
@@ -34,7 +35,7 @@ module MoulinRouge
34
35
 
35
36
  # Define a new role inside this scope. If exists a role with the
36
37
  # same name evaluate the block inside them instead of create a new one
37
- def role(name, options = {}, &block)
38
+ def role(name = :main, options = {}, &block)
38
39
  if children = find(name)
39
40
  children.instance_eval(&block)
40
41
  children
@@ -50,11 +51,37 @@ module MoulinRouge
50
51
  role(name, options, &block)
51
52
  end
52
53
 
54
+ # Appends all childrens and abilities from one object to another,
55
+ # raises an error if could not found a match.
56
+ def include(name)
57
+ unless from = MoulinRouge::Authorization.abilities[name]
58
+ raise RoleNotFound
59
+ end
60
+ from.childrens.each { |children| childrens << children.dup }
61
+ from.abilities.each { |ability| abilities << ability.dup }
62
+ end
63
+
64
+ # Returns a symbol with the name appended with the parents separeted by a underscore
65
+ def name
66
+ unless @name
67
+ @name = []
68
+ @name << self.parent.name.to_s if not self.parent.nil? and not self.parent.parent.nil?
69
+ @name << self.singular_name.to_s
70
+ @name = @name.join('_')
71
+ end
72
+ @name.to_sym
73
+ end
74
+
53
75
  # Returns true if is a group
54
76
  def group?
55
77
  @is_group
56
78
  end
57
79
 
80
+ # Returns true if is a role
81
+ def role?
82
+ !group?
83
+ end
84
+
58
85
  # Add the given parameters to the authorizations list
59
86
  def store_method(name, *args, &block)
60
87
  abilities << MoulinRouge::CanCan::Method.new(name, *args, &block)
@@ -71,70 +98,16 @@ module MoulinRouge
71
98
  @abilities ||= []
72
99
  end
73
100
 
74
- # Returns all abilities for this permission.
75
- # If this is a group, grab the abilities from parent.
101
+ # Returns an array with the abilities collected from this node and from
102
+ # their childrens.
76
103
  def inherithed_abilities
77
104
  abilities.concat(childrens.map(&:inherithed_abilities).flatten).uniq
78
105
  end
79
106
 
80
- # Execute all files in the given path in the class scope
81
- def import(path)
82
- Dir[path].each { |file| instance_eval(File.open(file).read) }
83
- end
84
-
85
107
  # Returns the instance of the children with the given name if exists and nil otherwise
86
108
  def find(name)
87
109
  childrens.each { |children| return children if children.name == name or children.singular_name == name }
88
110
  return nil
89
111
  end
90
-
91
- # Appends all childrens and abilities from one object to another,
92
- # raises an error if could not found a match.
93
- def include(name)
94
- unless from = self.class.all[name]
95
- raise RoleNotFound
96
- end
97
- from.childrens.each { |children| childrens << children.dup }
98
- from.abilities.each { |ability| abilities << ability.dup }
99
- end
100
-
101
- # Returns a symbol with the name appended with the parents separeted by a underscore
102
- def name
103
- unless @name
104
- @name = []
105
- @name << self.parent.name.to_s if not self.parent.nil? and not self.parent.parent.nil?
106
- @name << self.singular_name.to_s
107
- @name = @name.join('_')
108
- end
109
- @name.to_sym
110
- end
111
-
112
- class << self
113
- # The instance of the main container, if don't exist create one
114
- def main
115
- @main ||= self.new(:main)
116
- end
117
- # Returns an array with the name of all roles created
118
- def list
119
- @list ||= []
120
- end
121
-
122
- # Returns an hash with all permissions defined
123
- def all
124
- @all ||= {}
125
- end
126
-
127
- # Stores the instance on the all hash and add the name to the list
128
- def add(instance)
129
- name = instance.name
130
- self.all[name] = instance
131
- self.list << name unless self.list.include?(name)
132
- end
133
-
134
- # Reset all constants
135
- def reset! #:nodoc:
136
- @main, @list, @all = nil
137
- end
138
- end
139
112
  end
140
113
  end