├── .github
├── dependabot.yml
└── workflows
│ ├── activerecord.yml
│ └── mongoid.yml
├── .gitignore
├── .hakiri.yml
├── Appraisals
├── CHANGELOG.rdoc
├── CONTRIBUTORS
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── UPGRADE.rdoc
├── gemfiles
├── activerecord_4.gemfile
├── activerecord_5.gemfile
├── activerecord_6.gemfile
├── activerecord_7.gemfile
├── mongoid_5.gemfile
├── mongoid_6.gemfile
└── mongoid_7.gemfile
├── lib
├── generators
│ ├── active_record
│ │ ├── rolify_generator.rb
│ │ └── templates
│ │ │ ├── README
│ │ │ ├── migration.rb
│ │ │ └── model.rb
│ ├── mongoid
│ │ ├── rolify_generator.rb
│ │ └── templates
│ │ │ └── README-mongoid
│ └── rolify
│ │ ├── rolify_generator.rb
│ │ ├── templates
│ │ ├── README
│ │ ├── initializer.rb
│ │ ├── role-active_record.rb
│ │ └── role-mongoid.rb
│ │ └── user_generator.rb
├── rolify.rb
└── rolify
│ ├── adapters
│ ├── active_record
│ │ ├── resource_adapter.rb
│ │ ├── role_adapter.rb
│ │ └── scopes.rb
│ ├── base.rb
│ └── mongoid
│ │ ├── resource_adapter.rb
│ │ ├── role_adapter.rb
│ │ └── scopes.rb
│ ├── configure.rb
│ ├── dynamic.rb
│ ├── finders.rb
│ ├── matchers.rb
│ ├── railtie.rb
│ ├── resource.rb
│ ├── role.rb
│ ├── utils.rb
│ └── version.rb
├── rolify.gemspec
└── spec
├── README.rdoc
├── common_helper.rb
├── generators
└── rolify
│ ├── rolify_activerecord_generator_spec.rb
│ └── rolify_mongoid_generator_spec.rb
├── generators_helper.rb
├── rolify
├── config_spec.rb
├── coverage
│ ├── .last_run.json
│ ├── .resultset.json
│ └── .resultset.json.lock
├── custom_spec.rb
├── matchers_spec.rb
├── namespace_spec.rb
├── resource_spec.rb
├── resourcifed_and_rolifed_spec.rb
├── role_spec.rb
├── shared_contexts.rb
├── shared_examples
│ ├── shared_examples_for_add_role.rb
│ ├── shared_examples_for_callbacks.rb
│ ├── shared_examples_for_dynamic.rb
│ ├── shared_examples_for_finders.rb
│ ├── shared_examples_for_has_all_roles.rb
│ ├── shared_examples_for_has_any_role.rb
│ ├── shared_examples_for_has_role.rb
│ ├── shared_examples_for_only_has_role.rb
│ ├── shared_examples_for_remove_role.rb
│ ├── shared_examples_for_roles.rb
│ └── shared_examples_for_scopes.rb
└── utils_spec.rb
├── spec_helper.rb
└── support
├── adapters
├── active_record.rb
├── mongoid.rb
├── mongoid_5.yml
├── mongoid_6.yml
├── mongoid_7.yml
└── utils
│ ├── active_record.rb
│ └── mongoid.rb
├── data.rb
├── schema.rb
└── stream_helpers.rb
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 |
--------------------------------------------------------------------------------
/.github/workflows/activerecord.yml:
--------------------------------------------------------------------------------
1 | name: activerecord
2 | on: [push, pull_request]
3 | jobs:
4 | ubuntu:
5 | runs-on: ubuntu-latest
6 | continue-on-error: true
7 | strategy:
8 | matrix:
9 | gemfile: [activerecord_4, activerecord_5, activerecord_6]
10 | ruby: [2.5.9, 2.6.10, 2.7.7]
11 | include:
12 | - gemfile: activerecord_7
13 | ruby: '3.2'
14 | - gemfile: activerecord_7
15 | ruby: '3.1'
16 | - gemfile: activerecord_7
17 | ruby: '3.0'
18 | - gemfile: activerecord_6
19 | ruby: '3.0'
20 | env:
21 | BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
22 | ADAPTER: active_record
23 | steps:
24 | - uses: actions/checkout@v3
25 | - run: sudo apt-get install -y libsqlite3-dev
26 | - name: Setup ruby
27 | uses: ruby/setup-ruby@v1
28 | with:
29 | ruby-version: ${{ matrix.ruby }}
30 | bundler-cache: true
31 | - name: Run Tests
32 | run: |
33 | bundle exec rake
34 |
--------------------------------------------------------------------------------
/.github/workflows/mongoid.yml:
--------------------------------------------------------------------------------
1 | name: mongoid
2 | on: [push, pull_request]
3 | jobs:
4 | ubuntu:
5 | runs-on: ubuntu-latest
6 | continue-on-error: true
7 | services:
8 | mongodb:
9 | image: mongo:3.4.23
10 | ports:
11 | - 27017:27017
12 | strategy:
13 | matrix:
14 | gemfile: [mongoid_5]
15 | ruby: [2.5.9, 2.6.10, 2.7.7]
16 | env:
17 | BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
18 | ADAPTER: mongoid
19 | steps:
20 | - uses: actions/checkout@v3
21 | - run: sudo apt-get install -y libsqlite3-dev
22 | - name: Setup ruby
23 | uses: ruby/setup-ruby@v1
24 | with:
25 | ruby-version: ${{ matrix.ruby }}
26 | bundler-cache: true
27 | - name: Run Tests
28 | run: |
29 | bundle exec rake
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gem
2 | .bundle
3 | Gemfile.lock
4 | gemfiles/*.lock
5 | pkg/*
6 | tmp/*
7 | coverage/*
8 | log*/*
9 | .rbx/*
10 | .rspec
11 | *.swp
12 |
--------------------------------------------------------------------------------
/.hakiri.yml:
--------------------------------------------------------------------------------
1 | dependency_source: gemspec_file
2 |
--------------------------------------------------------------------------------
/Appraisals:
--------------------------------------------------------------------------------
1 | appraise 'mongoid-5' do
2 | gem "mongoid", "~> 5"
3 | gem "mongo", "< 2.17"
4 | gem "bson_ext", "1.5.1"
5 | gem 'bigdecimal', '1.4.2'
6 | end
7 |
8 | appraise 'mongoid-6' do
9 | gem "mongoid", "~> 6"
10 | gem "bson_ext", "1.5.1"
11 | end
12 |
13 | appraise 'mongoid-7' do
14 | gem "mongoid", "~> 7"
15 | gem "bson_ext", "1.5.1"
16 | gem "railties", "5.2.4.1"
17 | end
18 |
19 | appraise 'activerecord-4' do
20 | gem "sqlite3", "~> 1.3.6"
21 | gem "activerecord", "~> 4.2.11", :require => "active_record"
22 | gem 'bigdecimal', '1.4.2'
23 | end
24 |
25 | appraise 'activerecord-5' do
26 | gem "sqlite3", "~> 1.3.6"
27 | gem "activerecord", "~> 5.2.4", :require => "active_record"
28 |
29 | # Ammeter dependencies:
30 | gem "actionpack", "~> 5.2.4"
31 | gem "activemodel", "~> 5.2.4"
32 | gem "railties", "~> 5.2.4"
33 | end
34 |
35 | appraise 'activerecord-6' do
36 | gem "sqlite3", "~> 1.4", :platform => "ruby"
37 | gem "activerecord", ">= 6.0.0", :require => "active_record"
38 |
39 | # Ammeter dependencies:
40 | gem "actionpack", ">= 6.0.0"
41 | gem "activemodel", ">= 6.0.0"
42 | gem "railties", ">= 6.0.0"
43 | end
44 |
--------------------------------------------------------------------------------
/CHANGELOG.rdoc:
--------------------------------------------------------------------------------
1 | == 6.0.1
2 |
3 | * Fix with_role with :any resource
4 |
5 | = 6.0.0 (April 2, 2021)
6 |
7 | Breaking changes:
8 |
9 | * Support strict with_role queries. Note this changes behaviour of with_role when running in strict mode to behave as previously documented. #543 describes the behaviour change.
10 | * Dropped support for Ruby 2.3 and 2.4
11 |
12 | Improvements:
13 |
14 | * Updated ActiveRecord adapters implementation of in to utilise a subquery instead of two queries
15 |
16 | = 5.3.0 (June 1, 2020)
17 |
18 | 5.3.0 will be the last version to support Ruby < 2.5 and Rails < 5.2. Support for these will be dropped in the next major release.
19 |
20 | * Fix deprecation warning in Ruby 2.7
21 | * Add Rails 6 support to migration generator
22 | * Significant ActiveRecord performance improvements to add_role and without_role
23 | * Mongoid fix and performance improvement and to roles_name
24 | * Make it safe to call Thing.with_role(:admin, user) with new record
25 |
26 | = 5.2.0 (Dec 14, 2017)
27 | * Fix regression in generator around belongs_to options compatibility
28 | * Update version of database_cleaner
29 | * Update initializer.rb to include the remove_role_if_empty option and description
30 | * Allow inverse_of option on rolify method
31 | * Fix the code-climate-reporter issue that's causing travis to fail
32 | * Remove a separate index for the name column
33 | * Fix migration generator for AR 5.x
34 | * Fixed ambiguous column error
35 |
36 | = 5.1.0 (Mar 19, 2016)
37 | * Rails 5 Support (thanks @lorefnon)
38 | * Fix user handling in generator (thanks @lorefnon)
39 | * Fix quoting issues (thanks @lorefnon)
40 | * Improvements to dynamic module loading (thanks to @DmitryKK)
41 |
42 | = 5.0.0 (Nov 17, 2015)
43 | * Fix migration warning showing when it shouldn't
44 | * Add role lazy-loading
45 | * Add has_cached_role and has_cached_strict_role to project.
46 | See: https://github.com/RolifyCommunity/rolify#cached-roles-to-avoid-n1-issue
47 | * Update specs to pass with all Mongoid version.
48 |
49 | = 4.1.1 (Aug 06, 2015)
50 | * Fix a regression in the dynamic method loader.
51 |
52 | = 4.1.0 (Aug 04, 2015)
53 | * added `without_role` method for resources and classes
54 | * fix `has_role?` with :any and an unsaved user
55 | * rename the `with_role` method on a resource to `find_as`
56 | * add a strict parameter to check only roles that were set without supers.
57 |
58 | = 4.0.0 (Feb 12, 2015)
59 | * Increasing version number to 4.0.0 for semantic versioning since `has_role` was removed in 3.5.0
60 | * Fix spec to pass.
61 | * Fix dynamic shortcuts being set before migration.
62 |
63 | = 3.5.2 (Jan 14, 2015)
64 | * Fixed regression in RolifyGenerator
65 | * Updated dependencies
66 |
67 | = 3.5.0 (Jan 08, 2015)
68 | * Removed `has_role` method alias for `add_role`
69 | * Fixed regression in caching system
70 | * Fix deprecation warning about timestamp on specs
71 | * Copy Kernel#capture helper from Rails
72 | * Add validation on Role.resource_type
73 |
74 | = 3.4.1 (Sep 08, 2014)
75 | * Fixed issue with migrations being generated without a file extension.
76 | * Updated spec tests to work with Travis CI on Ruby up to 2.1.2 and Rails 4.1.x
77 | * Made it possible for inheritance of resources.
78 | * Fixed small bugs throughout project.
79 |
80 | = 3.4 (Jan 28, 2014)
81 | * fixed an initializer bug preventing the rails app to boot
82 | * enhanced documentation regarding with_role method (thanks to @vicomte)
83 | * added select(:id) in SQL subquery used by in method in ActiveRecord adapter (thanks to @ryanaip and @badaboda)
84 | * improved speed when removing roles using LIMIT(1) instead of COUNT (thanks to @yankovski)
85 | * fixed travis builds for rubinius and mongoid
86 | * fixed sanity check running before Rolify.config to ensure roles table exists
87 | * fixed has_any_role? to work with unsaved records (thanks to @mhw)
88 | * fixed specs for Mongoid
89 |
90 | = 3.3 (Jan 26, 2014)
91 | * DEPRECATION NOTICE:Rails 3.1 support dropped: if you use Rails 3.1, please stick to rolify 3.2
92 | * code cleanup in finders methods
93 | * generators rewritten entirely. now using ActiveRecord/Mongoid model generator to create Role model
94 | * added rspec matchers for detailed spec error messages (thanks to @delwyn)
95 | * clean up specs (thanks to @delwyn), removed subject and let declarations in before(:all) block
96 | * roles query needs 1 DB hit instead of 1 up to 3 (thanks to @terraplane)
97 | * remove nil entries from ResourceAdapter#resources_find when using Mongoid adapter (thanks to @daviscabral)
98 | * fixed a bug regarding redundant index for Mongoid Role model (thanks to @rschultheis)
99 | * added support for rolify and resourcify methods on the same model class (specs by @amer)
100 | * added support for namespaced models (thanks to @intrica)
101 | * fixed compatibility issue with squeel when using symbols as role parameters (hint by @f3ndot)
102 | * now raises a warning in the initializer if migration has not been run
103 | * add support for primary key different than 'id' for resource Model (thanks to @rafaeldl)
104 | * Rails 4 (thanks to @adammathys) and ruby 2.0 compliant
105 | * configured travis-ci to run the specs on Rails 3.2/4.0 and Rubies 1.9.3/2.0/rbx/jruby
106 | * added code climate to check for code smell
107 |
108 | = 3.2 (Aug 7, 2012)
109 | * DEPRECATION NOTICE: Ruby 1.8 support dropped ! Mongoid 3.0 only supports MRI 1.9.3, and HEAD, and JRuby 1.6.0+ in 1.9 mode
110 | * removed dynamic_shortcuts arguments from the generator
111 | * to use dynamic shortcuts feature when you're using ActiveRecord, you have to enable it _after_ running rake db:migrate as it relies on the roles table
112 | * support for Mongoid 3.x (thanks to @Leonas)
113 | * new class methods on the User class to find users depending on roles they have
114 | * added scopes to Role class to be able to fetch global, class scoped and instance scoped roles for a specific user
115 | * deletions of n-n relation are unreliable with Mongoid. Removing ids instead (thanks to @nfo)
116 | * has_role? method now supports new instance (i.e. record not saved in the database yet) (thanks to @demental)
117 | * added association callbacks (before|after)_add, (before|after)_remove on rolify method (thanks to @shekibobo)
118 | * added ability to pass an array of roles to Resource.with_role(), aliased by Resource.with_roles() (thanks to @lukes)
119 | * added option to have roles be destroyed by default if parent resource is destroyed (thanks to @treydock)
120 | * added new method only_has_role? to check if user has only a specific role (thanks to @jalcine)
121 | * better edge cases covering in the specs
122 | * fixed a bug regarding the loading order of the railtie when using Mongoid ORM and other gems using initializer files (thanks to @stigi)
123 | * fixed double quote syntax when using MySQL
124 | * fixed a nasty bug regarding class level queries (thanks to @kamrulhassan)
125 | * fixed uninitialized constant error in scopify method
126 | * documentation improvement
127 |
128 | = 3.1 (Apr 6, 2012)
129 | * Mongoid adapter optimization
130 | * adapter code refactoring
131 | * generator now adds the role class name to the rolify method injected in the user class
132 | * fixed a bug on the generator when using a 2 words Camel case for the Role class name
133 | * DEPRECATION NOTICE: has_role and has_no_role have been depecrated. They are replaced by add_role and remove_role
134 | * some internals cleanup (backward compatible)
135 | * stop requiring active_record in rolify.rb to prevent other gems ORM detection issue
136 | * fixed a bug when removing a role to the user using Mongoid adapter
137 | * added indexes to generator for mongoid (thanks to @stigi)
138 | * fixed a bug regarding **with_role** method on resource classes (thanks to @nfo)
139 |
140 | = 3.0 (Apr 2, 2012)
141 | * support for Mongoid
142 | * roles search on resources on instance level (e.g. Forum.first.roles) and class level (e.g. Forum.with_role("admin", user))
143 | * heavy lifting and redesign of the library, code and specs refactoring
144 | * enhanced drastically specs coverage: 1001 examples !
145 |
146 | = 2.2.2 (Feb 17, 2012)
147 | * fixed another bug occurring when dynamic shortcuts is enabled
148 | * display now a README file after running the generator to show the next setup steps
149 |
150 | = 2.2.1 (Jan 24, 2012)
151 | * fixed a backward incompatible change introduced in Rails 3.2 release (find_or_create_by_* generated methods)
152 |
153 | = 2.2 (Jan 18, 2012)
154 | * fixed a bug in the initializer file regarding dynamic shortcuts
155 |
156 | = 2.1 (Nov 30, 2011)
157 | * added syntactic sugar: grant and revoke are aliases for has_role and has_no_role
158 | * check if RUBY_ENGINE is defined in the gemspec to be able to use jdbc with JRuby for SQLite
159 |
160 | = 2.0 (Nov 10, 2011)
161 | * improved performance of has_all_roles? method using one single DB query instead of doing one DB lookup per argument
162 | * significant speed-up when requesting with many arguments
163 | * database choice can mitigate the results
164 | * clean up the initializer code
165 | * using a DSL to configure the library
166 | * setting defaults for User and Role classes
167 | * dynamic shortcuts feature is now disabled by default. To turn it on:
168 | * set it to true in the initializer file
169 | * uncomment the extend Rolify::Dynamic line in the User class
170 | * detecting if it's loaded by Rails::Server or Rails::Console
171 | * now also running on Rubinius, JRuby, REE and Ruby 1.8. all specs pass successfully, yeah !
172 |
173 | = 1.2 (Nov 4, 2011)
174 | * fixed a strange bug, probably rails related (thanks to @scottkf)
175 | * when using rails in development mode, the config.cache_classes = false makes the role class to be loaded at every call and can lead to a AssociationTypeMismatch
176 | * use of role_ids array instead of the roles association
177 | * now running on JRuby (specs are still failing for JRuby though)
178 |
179 | = 1.1 (Oct 14, 2011)
180 | * added a spec to test the rails generator using ammeter gem
181 | * Gemfile cleanup, moved all dependencies in gemspec instead
182 | * edited the dependency to Rails 3.1 and newer, now that Rails 3.1 has been released
183 | * new role scoping capabilities
184 | * instance level : user.has_role "moderator", Forum.first (already supported in previous release). user has the moderator role only on that Forum in particular
185 | * class level : user.has_role "moderator", Forum. User has the moderator role on all instances of Forum
186 | * global level : user.has_role "moderator" (already supported in previous release). User has the moderator role globally (e.q. on all resources)
187 | * new scoped query capabilities
188 | * user.has_role? "moderator", Forum.first (already supported in previous release). asks if the user has the moderator role on Forum.first instance
189 | * user.has_role? "moderator", Forum. asks if the user has the moderator role on all Forum instances
190 | * user.has_role? "moderator" (already supported in previous release). asks if the user has the global moderator role
191 | * user.has_role? "moderator", :any. asks if the user has at least one moderator role no matter the scope is (instance, class or global).
192 |
193 | = 1.0 (Aug 25, 2011)
194 | * added a new parameter to disable dynamic shortcut methods due to potential incompatibility with other gems using method_missing with the same pattern
195 | * add Rolify.dynamic_shortcuts = false in the initializer file or
196 | * use the generator command with a third parameter:
197 | * rails g rolify:role Role User false
198 | * removed the railtie as it created more problems than it solved
199 | * code refactoring to do some speed improvements and code clean up
200 | * added a lot of specs to improve tests coverage
201 | * wrote a tutorial showing how to use rolify with CanCan and Devise
202 | * rolify is now on travis-ci to monitor build status
203 |
204 | = 0.7 (June 20, 2011)
205 | * added a method_missing to catch newly created role outside the current ruby process (i.e. dynamic shortcut methods are not defined within this process)
206 | * dynamic shortcut is created on the fly in the method_missing to avoid extra method_missing for the same dynamic shortcut
207 | * check if the role actually exists in the database before defining the new method
208 | * first call is slower due to method_missing but next calls are fast
209 | * avoid strange bugs when spawning many ruby processes as the dynamic shortcut methods were only defined in the process that used the has_role command
210 |
211 | = 0.6 (June 19, 2011)
212 | * custom User and Role class names support
213 | * can now use other class names for Role and User classes
214 | * fixed generators and templates
215 | * join table is explicitly set to avoid alphabetical order issue
216 | * created a new railtie to load the dynamic shortcuts at startup
217 |
218 | = 0.5.1 (June 07, 2011)
219 | * fixed a nasty typo on a variable name and added a spec to make it never happen again
220 |
221 | = 0.5 (June 07, 2011)
222 | * dynamic shortcuts support
223 | * creates automatically new methods upon new role creation (or at startup for a Rails app)
224 | * has_role "admin" will create a method called is_admin?
225 | * has_role "moderator", Forum.first will create 2 methods:
226 | * is_moderator_of?(resource)
227 | * is_moderator?
228 |
229 | = v0.4 (June 07, 2011)
230 | * removing role support
231 | * has_no_role removes a global role or a role scoped to a resource
232 | * Please note that trying to remove a global role whereas the user a role with the same name on a resource will remove that scoped role
233 | * Trying to remove a role scoped to a resource whereas the user has a global role won't remove it
234 |
235 | = v0.3 (June 06, 2011)
236 | * multiple roles check:
237 | * has_all_roles? returns true if the user has ALL the roles in arguments
238 | * has_any_role? returns true if the user has ANY the roles in arguments
239 |
240 | = v0.2 (June 04, 2011)
241 | * fixed the generator to include the lib
242 | * fixed the migration file with missing polymorphic field
243 | * added some examples in documentation
244 |
245 | = v0.1 (June 04, 2011)
246 | * first release
247 |
--------------------------------------------------------------------------------
/CONTRIBUTORS:
--------------------------------------------------------------------------------
1 | Florent Monbillard (@EppO) - Original Author
2 | Wellington Cordeiro (@wldcordeiro)
3 | Joel Azemar (@joel)
4 | Alex Klim (@AlexKlim)
5 | Mauro George (@MauroGeorge)
6 | Cheri Allen(@cherimarie)
7 | Gaurab Paul (@lorefnon)
8 | Dmitry Krakosevich (@DmitryKK)
9 | Michael Watts (@mikwat)
10 | Derek Ethier (@ethier)
11 | Michael (@mibamur)
12 | Undo1 (@Undo1)
13 | Hitabis Engineering (@Hitabis)
14 | Sergey Alekseev (@sergey-alekseev)
15 | Sankalp Kulshreshtha (@sankalpk)
16 | Kirill Sevastyanenko (@kirillseva)
17 | Denis Shevchenko (@SimplySorc)
18 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | group :test do
4 | gem 'codeclimate-test-reporter', require: nil
5 | gem 'coveralls', require: false
6 | gem 'database_cleaner', '~> 1.6.2'
7 | gem 'its'
8 | gem 'test-unit' # Implicitly loaded by ammeter
9 |
10 | gem 'byebug'
11 | gem 'pry'
12 | gem 'pry-byebug'
13 | end
14 |
15 | gemspec
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 Florent Monbillard
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.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # rolify [](http://badge.fury.io/rb/rolify) [](http://travis-ci.org/RolifyCommunity/rolify) [](https://codeclimate.com/github/RolifyCommunity/rolify) [](https://coveralls.io/github/RolifyCommunity/rolify?branch=master)
2 |
3 | Very simple Roles library without any authorization enforcement supporting scope on resource object.
4 |
5 | Let's see an example:
6 |
7 | ```ruby
8 | user.has_role?(:moderator, @forum)
9 | => false # if user is moderator of another Forum
10 | ```
11 |
12 | This library can be easily integrated with any authentication gem ([devise](https://github.com/plataformatec/devise), [Authlogic](https://github.com/binarylogic/authlogic), [Clearance](https://github.com/thoughtbot/clearance)) and authorization gem* ([CanCanCan](https://github.com/CanCanCommunity/cancancan), [authority](https://github.com/nathanl/authority), [Pundit](https://github.com/elabs/pundit))
13 |
14 | *: authorization gem that doesn't provide a role class
15 |
16 | ## Requirements
17 |
18 | * Rails >= 4.2
19 | * ActiveRecord >= 4.2 or Mongoid >= 4.0
20 | * supports ruby 2.2+, JRuby 1.6.0+ (in 1.9 mode) and Rubinius 2.0.0dev (in 1.9 mode)
21 | * support of ruby 1.8 has been dropped due to Mongoid >=3.0 that only supports 1.9 new hash syntax
22 |
23 | ## Installation
24 |
25 | Add this to your Gemfile and run the `bundle` command.
26 |
27 | ```ruby
28 | gem "rolify"
29 | ```
30 |
31 | ## Getting Started
32 |
33 | ### 1. Generate Role Model
34 |
35 | First, use the generator to setup Rolify. Role and User class are the default names. However, you can specify any class name you want. For the User class name, you would probably use the one provided by your authentication solution.
36 |
37 | If you want to use Mongoid instead of ActiveRecord, just add `--orm=mongoid` argument, and skip to step #3.
38 |
39 | ```
40 | rails g rolify Role User
41 | ```
42 |
43 | **NB** for versions of Rolify prior to 3.3, use:
44 |
45 | ```
46 | rails g rolify:role Role User
47 | ```
48 |
49 | The generator will create your Role model, add a migration file, and update your User class with new class methods.
50 |
51 | ### 2. Run the migration (only required when using ActiveRecord)
52 |
53 | Let's migrate!
54 |
55 | ```
56 | rake db:migrate
57 | ```
58 |
59 | ### 3.1 Configure your user model
60 |
61 | This gem adds the `rolify` method to your User class. You can also specify optional callbacks on the User class for when roles are added or removed:
62 |
63 | ```ruby
64 | class User < ActiveRecord::Base
65 | rolify :before_add => :before_add_method
66 |
67 | def before_add_method(role)
68 | # do something before it gets added
69 | end
70 | end
71 | ```
72 |
73 | The `rolify` method accepts the following callback options:
74 |
75 | - `before_add`
76 | - `after_add`
77 | - `before_remove`
78 | - `after_remove`
79 |
80 | Mongoid callbacks are also supported and works the same way.
81 |
82 | The `rolify` method also accepts the `inverse_of` option if you need to disambiguate the relationship.
83 |
84 | ### 3.2 Configure your resource models
85 |
86 | In the resource models you want to apply roles on, just add ``resourcify`` method.
87 | For example, on this ActiveRecord class:
88 |
89 | ```ruby
90 | class Forum < ActiveRecord::Base
91 | resourcify
92 | end
93 | ```
94 |
95 | ### 3.3 Assign default role
96 |
97 | ```ruby
98 | class User < ActiveRecord::Base
99 | after_create :assign_default_role
100 |
101 | def assign_default_role
102 | self.add_role(:newuser) if self.roles.blank?
103 | end
104 | end
105 | ```
106 |
107 | ### 4. Add a role to a user
108 |
109 | To define a global role:
110 |
111 | ```ruby
112 | user = User.find(1)
113 | user.add_role :admin
114 | ```
115 |
116 | To define a role scoped to a resource instance:
117 |
118 | ```ruby
119 | user = User.find(2)
120 | user.add_role :moderator, Forum.first
121 | ```
122 |
123 | To define a role scoped to a resource class:
124 |
125 | ```ruby
126 | user = User.find(3)
127 | user.add_role :moderator, Forum
128 | ```
129 |
130 | Remove role:
131 | ```ruby
132 | user = User.find(3)
133 | user.remove_role :moderator
134 | ```
135 |
136 | That's it!
137 |
138 | ### 5. Role queries
139 |
140 | To check if a user has a global role:
141 |
142 | ```ruby
143 | user = User.find(1)
144 | user.add_role :admin # sets a global role
145 | user.has_role? :admin
146 | => true
147 | ```
148 |
149 | To check if a user has a role scoped to a resource instance:
150 |
151 | ```ruby
152 | user = User.find(2)
153 | user.add_role :moderator, Forum.first # sets a role scoped to a resource instance
154 | user.has_role? :moderator, Forum.first
155 | => true
156 | user.has_role? :moderator, Forum.last
157 | => false
158 | ```
159 |
160 | To check if a user has a role scoped to a resource class:
161 |
162 | ```ruby
163 | user = User.find(3)
164 | user.add_role :moderator, Forum # sets a role scoped to a resource class
165 | user.has_role? :moderator, Forum
166 | => true
167 | user.has_role? :moderator, Forum.first
168 | => true
169 | user.has_role? :moderator, Forum.last
170 | => true
171 | ```
172 |
173 | A global role overrides resource role request:
174 |
175 | ```ruby
176 | user = User.find(4)
177 | user.add_role :moderator # sets a global role
178 | user.has_role? :moderator, Forum.first
179 | => true
180 | user.has_role? :moderator, Forum.last
181 | => true
182 | ```
183 |
184 | To check if a user has the exact role scoped to a resource class:
185 |
186 | ```ruby
187 | user = User.find(5)
188 | user.add_role :moderator # sets a global role
189 | user.has_role? :moderator, Forum.first
190 | => true
191 | user.has_strict_role? :moderator, Forum.last
192 | => false
193 | ```
194 |
195 | ### 6. Resource roles querying
196 |
197 | Starting from rolify 3.0, you can search roles on instance level or class level resources.
198 |
199 | #### Instance level
200 |
201 | ```ruby
202 | forum = Forum.first
203 | forum.roles
204 | # => [ list of roles that are only bound to forum instance ]
205 | forum.applied_roles
206 | # => [ list of roles bound to forum instance and to the Forum class ]
207 | ```
208 |
209 | #### Class level
210 |
211 | ```ruby
212 | Forum.with_role(:admin)
213 | # => [ list of Forum instances that have role "admin" bound to them ]
214 | Forum.without_role(:admin)
215 | # => [ list of Forum instances that do NOT have role "admin" bound to them ]
216 | Forum.with_role(:admin, current_user)
217 | # => [ list of Forum instances that have role "admin" bound to them and belong to current_user roles ]
218 | Forum.with_roles([:admin, :user], current_user)
219 | # => [ list of Forum instances that have role "admin" or "user" bound to them and belong to current_user roles ]
220 |
221 | User.with_any_role(:user, :admin)
222 | # => [ list of User instances that have role "admin" or "user" bound to them ]
223 | User.with_role(:site_admin, current_site)
224 | # => [ list of User instances that have a scoped role of "site_admin" to a site instance ]
225 | User.with_role(:site_admin, :any)
226 | # => [ list of User instances that have a scoped role of "site_admin" for any site instances ]
227 | User.with_all_roles(:site_admin, :admin)
228 | # => [ list of User instances that have a role of "site_admin" and a role of "admin" bound to it ]
229 |
230 | Forum.find_roles
231 | # => [ list of roles that are bound to any Forum instance or to the Forum class ]
232 | Forum.find_roles(:admin)
233 | # => [ list of roles that are bound to any Forum instance or to the Forum class, with "admin" as a role name ]
234 | Forum.find_roles(:admin, current_user)
235 | # => [ list of roles that are bound to any Forum instance, or to the Forum class with "admin" as a role name, and belongs to current_user ]
236 | ```
237 |
238 | ### Strict Mode
239 |
240 | ```ruby
241 | class User < ActiveRecord::Base
242 | rolify strict: true
243 | end
244 |
245 | @user = User.first
246 |
247 | @user.add_role(:forum, Forum)
248 | @user.add_role(:forum, Forum.first)
249 |
250 | @user.has_role?(:forum, Forum) #=> true
251 | @user.has_role?(:forum, Forum.first) #=> true
252 | @user.has_role?(:forum, Forum.last) #=> false
253 | ```
254 | I.e. you get true only on a role that you manually add.
255 |
256 | ### Cached Roles (to avoid N+1 issue)
257 |
258 | ```ruby
259 | @user.add_role :admin, Forum
260 | @user.add_role :member, Forum
261 |
262 | users = User.with_role(:admin, Forum).preload(:roles)
263 | users.each do |user|
264 | user.has_cached_role?(:member, Forum) # no extra queries
265 | end
266 | ```
267 |
268 | This method should be used with caution. If you don't preload the roles, the `has_cached_role?` might return `false`. In the above example, it would return `false` for `@user.has_cached_role?(:member, Forum)`, because `User.with_role(:admin, Forum)` will load only the `:admin` roles.
269 |
270 | ## Resources
271 |
272 | * [Wiki](https://github.com/RolifyCommunity/rolify/wiki)
273 | * [Usage](https://github.com/RolifyCommunity/rolify/wiki/Usage): all the available commands
274 | * [Tutorials](https://github.com/RolifyCommunity/rolify/wiki#wiki-tutorials):
275 | * [How-To use rolify with Devise and CanCanCan](https://github.com/RolifyCommunity/rolify/wiki/Devise---CanCanCan---rolify-Tutorial)
276 | * [Using rolify with Devise and Authority](https://github.com/RolifyCommunity/rolify/wiki/Using-rolify-with-Devise-and-Authority)
277 | * [Step-by-step tutorial](http://railsapps.github.com/tutorial-rails-bootstrap-devise-cancan.html) provided by [RailsApps](http://railsapps.github.com/)
278 |
279 | ## Upgrade from previous versions
280 |
281 | Please read the [upgrade instructions](UPGRADE.rdoc).
282 |
283 | ## Known issues
284 |
285 | * If you are using Mongoid and/or less-rails gem, please read [this](https://github.com/RolifyCommunity/rolify/wiki/FAQ#when-i-start-rails-using-server-console-whatever-i-get-this-error)
286 | * Moped library (ruby driver for Mongodb used by Mongoid) doesn't support rubinius 2.2 yet (see https://github.com/mongoid/moped/issues/231)
287 | * If you use Rails 4 and Mongoid, use Mongoid ~> 4. rolify is fully tested with Rails 4 and Mongoid 4.
288 |
289 | ## Questions or Problems?
290 |
291 | If you have any issue or feature request with/for rolify, please create an new [issue on GitHub](https://github.com/RolifyCommunity/rolify/issues) **specifying the ruby runtime, rails and rolify versions you're using and the gems listed in your Gemfile**, or fork the project and send a pull request.
292 |
293 | To get the specs running you should call `bundle` and then `rake`. See the spec/README for more information.
294 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'bundler'
2 | require 'rspec/core/rake_task'
3 | require 'coveralls/rake/task'
4 | require 'appraisal'
5 |
6 | Bundler::GemHelper.install_tasks
7 |
8 | Coveralls::RakeTask.new
9 |
10 | RSpec::Core::RakeTask.new(:generators) do |task|
11 | task.pattern = 'spec/generators/**/*_spec.rb'
12 | end
13 |
14 | RSpec::Core::RakeTask.new(:rolify) do |task|
15 | task.pattern = 'spec/rolify/**/*_spec.rb'
16 | end
17 |
18 | if !ENV["APPRAISAL_INITIALIZED"] && !ENV["CI"]
19 | task :default => :appraisal
20 | else
21 | task :default => [ :spec, 'coveralls:push' ]
22 | end
23 |
24 | desc 'Run all specs'
25 | task 'spec' do
26 | Rake::Task['generators'].invoke
27 | return_code1 = $?.exitstatus
28 | Rake::Task['rolify'].invoke
29 | return_code2 = $?.exitstatus
30 | fail if return_code1 != 0 || return_code2 != 0
31 | end
32 |
33 | desc 'Run specs for all adapters'
34 | task :spec_all do
35 | %w[active_record mongoid].each do |model_adapter|
36 | puts "ADAPTER = #{model_adapter}"
37 | system "ADAPTER=#{model_adapter} rake"
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/UPGRADE.rdoc:
--------------------------------------------------------------------------------
1 | = Upgrade instructions for Rolify library
2 |
3 | == From a previous rolify installation (1.x or 2.x)
4 |
5 | The easiest way is to re-run the generator using rails g Rolify:Role command, and overwrite the initializer file. Both the migration file and the role.rb haven't changed.
6 | In the config/initializers/rolify.rb file, here are the deprecated settings:
7 | * role_cname
8 | * user_cname
9 | By default, these settings were commented out, so you can safely remove them.
10 | If you changed them, you can remove them in the initializer file too. user_cname is no longer used in 3.x, you don't need it anymore.
11 | Add your custom role_cname setting as argument of the rolify method you use in your User class.
12 | For instance, if you use Privilege as Role class, you should add this to your whatever your User class is, let's say Client for the sake of example:
13 | class Client < ActiveRecord::Base
14 | rolify :role_cname => "Privilege"
15 | end
16 | If you use the default Role class name, you don't have to specify the :role_cname argument.
17 |
18 | If you use dynamic methods (user.is_admin? like methods), you should turn it on using use_dynamic_shortcuts method starting from rolify 3.0:
19 | Rolify.configure do |c|
20 | c.use_dynamic_shortcuts
21 | end
22 | The old fashion way still works though, but won't work anymore if the setter method name is changed in a possible future. You've been warned :-)
23 |
24 | == From a rolify installation 3.x
25 |
26 | === Dependencies:
27 |
28 | Starting from 3.3 release, rolify supports Rails 3.2 and newer.
29 |
30 | Mongoid callbacks are supported if Mongoid 3.1 and newer is installed.
31 |
32 | === Rails Generators
33 |
34 | Role model template when using Mongoid has been changed, you should re-run the generator.
35 |
36 | Rails generator has been renamed to: rails g rolify and arguments have been changed:
37 | * Role class name is now mandatory, User class name remains optional and its default is still User
38 | * ORM optional argument is now -o or --orm=
39 | For instance, here is a new rolify generator command example: rails g rolify Role
40 | You can use rails g rolify --help to see all available options.
41 |
42 | === Testing
43 |
44 | Starting from rolify 3.3, to run the specs you should run: rake spec or simply rake.
45 |
--------------------------------------------------------------------------------
/gemfiles/activerecord_4.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "sqlite3", "~> 1.3.6"
6 | gem "activerecord", "~> 4.2.11", require: "active_record"
7 | gem "bigdecimal", "1.4.2"
8 |
9 | group :test do
10 | gem "codeclimate-test-reporter", require: nil
11 | gem "coveralls", require: false
12 | gem "database_cleaner", "~> 1.6.2"
13 | gem "its"
14 | gem "test-unit"
15 | gem "byebug"
16 | gem "pry"
17 | gem "pry-byebug"
18 | end
19 |
20 | gemspec path: "../"
21 |
--------------------------------------------------------------------------------
/gemfiles/activerecord_5.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "sqlite3", "~> 1.3.6"
6 | gem "activerecord", "~> 5.2.4", require: "active_record"
7 | gem "actionpack", "~> 5.2.4"
8 | gem "activemodel", "~> 5.2.4"
9 | gem "railties", "~> 5.2.4"
10 |
11 | group :test do
12 | gem "codeclimate-test-reporter", require: nil
13 | gem "coveralls", require: false
14 | gem "database_cleaner", "~> 1.6.2"
15 | gem "its"
16 | gem "test-unit"
17 | gem "byebug"
18 | gem "pry"
19 | gem "pry-byebug"
20 | end
21 |
22 | gemspec path: "../"
23 |
--------------------------------------------------------------------------------
/gemfiles/activerecord_6.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "sqlite3", "~> 1.4", platform: "ruby"
6 | gem "activerecord", "~> 6.1.0", require: "active_record"
7 | gem "actionpack", "~> 6.1.0"
8 | gem "activemodel", "~> 6.1.0"
9 | gem "railties", "~> 6.1.0"
10 |
11 | group :test do
12 | gem "codeclimate-test-reporter", require: nil
13 | gem "coveralls", require: false
14 | gem "database_cleaner", "~> 1.6.2"
15 | gem "its"
16 | gem "test-unit"
17 | gem "byebug"
18 | gem "pry"
19 | gem "pry-byebug"
20 | end
21 |
22 | gemspec path: "../"
23 |
--------------------------------------------------------------------------------
/gemfiles/activerecord_7.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "sqlite3", "~> 1.4", platform: "ruby"
6 | gem "activerecord", "~> 7.0.0", require: "active_record"
7 | gem "actionpack", "~> 7.0.0"
8 | gem "activemodel", "~> 7.0.0"
9 | gem "railties", "~> 7.0.0"
10 |
11 | group :test do
12 | gem "codeclimate-test-reporter", require: nil
13 | gem "coveralls", require: false
14 | gem "database_cleaner", "~> 1.6.2"
15 | gem "its"
16 | gem "test-unit"
17 | gem "byebug"
18 | gem "pry"
19 | gem "pry-byebug"
20 | end
21 |
22 | gemspec path: "../"
23 |
--------------------------------------------------------------------------------
/gemfiles/mongoid_5.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "mongoid", "~> 5"
6 | gem "mongo", "< 2.17"
7 | gem "bson_ext", "1.5.1"
8 | gem "bigdecimal", "1.4.2"
9 |
10 | group :test do
11 | gem "codeclimate-test-reporter", require: nil
12 | gem "coveralls", require: false
13 | gem "database_cleaner", "~> 1.6.2"
14 | gem "its"
15 | gem "test-unit"
16 | gem "byebug"
17 | gem "pry"
18 | gem "pry-byebug"
19 | end
20 |
21 | gemspec path: "../"
22 |
--------------------------------------------------------------------------------
/gemfiles/mongoid_6.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "mongoid", "~> 6"
6 | gem "bson_ext", "1.5.1"
7 |
8 | group :test do
9 | gem "codeclimate-test-reporter", require: nil
10 | gem "coveralls", require: false
11 | gem "database_cleaner", "~> 1.6.2"
12 | gem "its"
13 | gem "test-unit"
14 | gem "byebug"
15 | gem "pry"
16 | gem "pry-byebug"
17 | end
18 |
19 | gemspec path: "../"
20 |
--------------------------------------------------------------------------------
/gemfiles/mongoid_7.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "mongoid", "~> 7"
6 | gem "bson_ext", "1.5.1"
7 | gem "railties", "5.2.4.1"
8 |
9 | group :test do
10 | gem "codeclimate-test-reporter", require: nil
11 | gem "coveralls", require: false
12 | gem "database_cleaner", "~> 1.6.2"
13 | gem "its"
14 | gem "test-unit"
15 | gem "byebug"
16 | gem "pry"
17 | gem "pry-byebug"
18 | end
19 |
20 | gemspec path: "../"
21 |
--------------------------------------------------------------------------------
/lib/generators/active_record/rolify_generator.rb:
--------------------------------------------------------------------------------
1 | require 'rails/generators/active_record'
2 | require 'active_support/core_ext'
3 | require 'erb'
4 |
5 | module ActiveRecord
6 | module Generators
7 | class RolifyGenerator < ActiveRecord::Generators::Base
8 | source_root File.expand_path("../templates", __FILE__)
9 |
10 | argument :user_cname, :type => :string, :default => "User", :banner => "User"
11 |
12 | def ensure_user_class_defined
13 | unless user_class_defined?
14 | prompt_missing_user
15 | abort
16 | end
17 | end
18 |
19 | def generate_model
20 | invoke "active_record:model", [ name ], :migration => false
21 | end
22 |
23 | def inject_role_class
24 | if args[1]=="engine"
25 | if args[2]=="devise"
26 | require 'devise'
27 | require "#{ENGINE_ROOT}/config/initializers/devise.rb"
28 | require "#{ENGINE_ROOT}/app/models/#{user_cname.downcase}.rb"
29 | else
30 | require "#{ENGINE_ROOT}/app/models/#{user_cname.downcase}.rb"
31 | end
32 | end
33 |
34 | inject_into_class(model_path, class_name, model_content)
35 | end
36 |
37 | def copy_rolify_migration
38 | migration_template "migration.rb", "db/migrate/rolify_create_#{table_name}.rb", migration_version: migration_version
39 | end
40 |
41 | private
42 |
43 | def join_table
44 | user_class.table_name + "_" + table_name
45 | end
46 |
47 | def user_reference
48 | user_cname.demodulize.underscore
49 | end
50 |
51 | def role_reference
52 | class_name.demodulize.underscore
53 | end
54 |
55 | def model_path
56 | File.join("app", "models", "#{file_path}.rb")
57 | end
58 |
59 | def model_content
60 | ERB.new(File.read(File.join(__dir__, 'templates/model.rb'))).result(binding)
61 | end
62 |
63 | def user_class
64 | user_cname.constantize
65 | end
66 |
67 | def user_class_defined?
68 | user_class
69 | true
70 | rescue NameError => ex
71 | if ex.missing_name == user_cname
72 | false
73 | else
74 | raise ex
75 | end
76 | end
77 |
78 | def prompt_missing_user
79 | puts <= 5
87 | end
88 |
89 | def migration_version
90 | if versioned_migrations?
91 | "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
92 | end
93 | end
94 |
95 | end
96 | end
97 | end
98 |
--------------------------------------------------------------------------------
/lib/generators/active_record/templates/README:
--------------------------------------------------------------------------------
1 | Now, you just have to run the migration using rake command:
2 |
3 | rake db:migrate
4 |
5 | and you will be able to add the resourcify method inside all models you want
6 | scoped by a role.
7 |
8 | ===============================================================================
9 |
--------------------------------------------------------------------------------
/lib/generators/active_record/templates/migration.rb:
--------------------------------------------------------------------------------
1 | class RolifyCreate<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
2 | def change
3 | create_table(:<%= table_name %>) do |t|
4 | t.string :name
5 | t.references :resource, :polymorphic => true
6 |
7 | t.timestamps
8 | end
9 |
10 | create_table(:<%= join_table %>, :id => false) do |t|
11 | t.references :<%= user_reference %>
12 | t.references :<%= role_reference %>
13 | end
14 | <% if ActiveRecord::Base.connection.class.to_s.demodulize != 'PostgreSQLAdapter' %><%= "\n " %>add_index(:<%= table_name %>, :name)<% end %>
15 | add_index(:<%= table_name %>, [ :name, :resource_type, :resource_id ])
16 | add_index(:<%= join_table %>, [ :<%= user_reference %>_id, :<%= role_reference %>_id ])
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/generators/active_record/templates/model.rb:
--------------------------------------------------------------------------------
1 | has_and_belongs_to_many :<%= user_class.table_name %>, :join_table => :<%= join_table %>
2 | <% if Rails::VERSION::MAJOR < 5 %>
3 | belongs_to :resource,
4 | :polymorphic => true
5 | <% else %>
6 | belongs_to :resource,
7 | :polymorphic => true,
8 | :optional => true
9 | <% end %>
10 |
11 | validates :resource_type,
12 | :inclusion => { :in => Rolify.resource_types },
13 | :allow_nil => true
14 |
15 | scopify
16 |
--------------------------------------------------------------------------------
/lib/generators/mongoid/rolify_generator.rb:
--------------------------------------------------------------------------------
1 | require 'rails/generators/mongoid_generator'
2 | require 'active_support/core_ext'
3 |
4 | module Mongoid
5 | module Generators
6 | class RolifyGenerator < Rails::Generators::NamedBase
7 | source_root File.expand_path("../templates", __FILE__)
8 |
9 | argument :user_cname, :type => :string, :default => "User", :banner => "User"
10 |
11 | def generate_model
12 | invoke "mongoid:model", [ name ]
13 | end
14 |
15 | def inject_role_class
16 | inject_into_file(model_path, model_contents, :after => "include Mongoid::Document\n")
17 | end
18 |
19 | def user_reference
20 | user_cname.demodulize.underscore
21 | end
22 |
23 | def role_reference
24 | class_name.demodulize.underscore
25 | end
26 |
27 | def model_path
28 | File.join("app", "models", "#{file_path}.rb")
29 | end
30 |
31 | def model_contents
32 | content = < true
35 |
36 | field :name, :type => String
37 |
38 | index({
39 | :name => 1,
40 | :resource_type => 1,
41 | :resource_id => 1
42 | },
43 | { :unique => true})
44 |
45 | validates :resource_type,
46 | :inclusion => { :in => Rolify.resource_types },
47 | :allow_nil => true
48 |
49 | scopify
50 | RUBY
51 | content % { :user_cname => user_cname.constantize.collection_name }
52 | end
53 | end
54 | end
55 | end
56 |
--------------------------------------------------------------------------------
/lib/generators/mongoid/templates/README-mongoid:
--------------------------------------------------------------------------------
1 | Now, you are able to add the resourcify method inside all models you want
2 | scoped by a role.
3 |
4 | ===============================================================================
5 |
--------------------------------------------------------------------------------
/lib/generators/rolify/rolify_generator.rb:
--------------------------------------------------------------------------------
1 | module Rolify
2 | module Generators
3 | class RolifyGenerator < Rails::Generators::NamedBase
4 | Rails::Generators::ResourceHelpers
5 |
6 | source_root File.expand_path('../templates', __FILE__)
7 | argument :user_cname, :type => :string, :default => "User"
8 |
9 | namespace :rolify
10 | hook_for :orm, :required => true
11 |
12 | desc "Generates a model with the given NAME and a migration file."
13 |
14 | def self.start(args, config)
15 | user_cname = args.size > 1 ? args[1] : "User"
16 | args.insert(1, user_cname) # 0 being the view name
17 | super
18 | end
19 |
20 | def inject_user_class
21 | invoke "rolify:user", [ user_cname, class_name ], :orm => options.orm
22 | end
23 |
24 | def copy_initializer_file
25 | template "initializer.rb", "config/initializers/rolify.rb"
26 | end
27 |
28 | def show_readme
29 | if behavior == :invoke
30 | readme "README"
31 | end
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/generators/rolify/templates/README:
--------------------------------------------------------------------------------
1 | ===============================================================================
2 |
3 | An initializer file has been created here: config/initializers/rolify.rb, you
4 | can change rolify settings to match your needs.
5 | Defaults values are commented out.
6 |
7 | A Role class has been created in app/models (with the name you gave as
8 | argument otherwise the default is role.rb), you can add your own business logic
9 | inside.
10 |
11 | Inside your User class (or the name you gave as argument otherwise the default
12 | is user.rb), rolify method has been inserted to provide rolify methods.
13 |
14 |
--------------------------------------------------------------------------------
/lib/generators/rolify/templates/initializer.rb:
--------------------------------------------------------------------------------
1 | Rolify.configure<%= "(\"#{class_name.camelize.to_s}\")" if class_name != "Role" %> do |config|
2 | # By default ORM adapter is ActiveRecord. uncomment to use mongoid
3 | <%= "# " if options.orm == :active_record || !options.orm %>config.use_mongoid
4 |
5 | # Dynamic shortcuts for User class (user.is_admin? like methods). Default is: false
6 | # config.use_dynamic_shortcuts
7 |
8 | # Configuration to remove roles from database once the last resource is removed. Default is: true
9 | # config.remove_role_if_empty = false
10 | end
11 |
--------------------------------------------------------------------------------
/lib/generators/rolify/templates/role-active_record.rb:
--------------------------------------------------------------------------------
1 | class <%= role_cname.camelize %> < ActiveRecord::Base
2 | <% if need_table_prefix?(role_cname) %>
3 | def self.table_name_prefix
4 | <%= table_prefix(role_cname) %>_
5 | end
6 | <% end %>
7 | has_and_belongs_to_many :<%= user_cname.tableize %>, :join_table => :<%= "#{table_name(user_cname, true)}_#{table_name(role_cname, true)}" %>
8 | belongs_to :resource, :polymorphic => true
9 |
10 | scopify
11 | end
12 |
--------------------------------------------------------------------------------
/lib/generators/rolify/templates/role-mongoid.rb:
--------------------------------------------------------------------------------
1 | class <%= role_cname.camelize %>
2 | include Mongoid::Document
3 |
4 | has_and_belongs_to_many :<%= user_cname.tableize %>
5 | belongs_to :resource, :polymorphic => true
6 |
7 | field :name, :type => String
8 |
9 | index({
10 | :name => 1,
11 | :resource_type => 1,
12 | :resource_id => 1
13 | },
14 | { :unique => true})
15 |
16 | scopify
17 | end
18 |
--------------------------------------------------------------------------------
/lib/generators/rolify/user_generator.rb:
--------------------------------------------------------------------------------
1 | require 'rails/generators/migration'
2 | require 'active_support/core_ext'
3 |
4 | module Rolify
5 | module Generators
6 | class UserGenerator < Rails::Generators::NamedBase
7 | argument :role_cname, :type => :string, :default => "Role"
8 | class_option :orm, :type => :string, :default => "active_record"
9 |
10 | desc "Inject rolify method in the User class."
11 |
12 | def inject_user_content
13 | inject_into_file(model_path, :after => inject_rolify_method) do
14 | " rolify#{role_association}\n"
15 | end
16 | end
17 |
18 | def inject_rolify_method
19 | if options.orm == :active_record
20 | /class #{class_name.camelize}\n|class #{class_name.camelize} .*\n|class #{class_name.demodulize.camelize}\n|class #{class_name.demodulize.camelize} .*\n/
21 | else
22 | /include Mongoid::Document\n|include Mongoid::Document .*\n/
23 | end
24 | end
25 |
26 | def model_path
27 | File.join("app", "models", "#{file_path}.rb")
28 | end
29 |
30 | def role_association
31 | if role_cname != "Role"
32 | " :role_cname => '#{role_cname.camelize}'"
33 | else
34 | ""
35 | end
36 | end
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/lib/rolify.rb:
--------------------------------------------------------------------------------
1 | require 'rolify/adapters/base'
2 | require 'rolify/configure'
3 | require 'rolify/dynamic'
4 | require 'rolify/railtie' if defined?(Rails)
5 | require 'rolify/resource'
6 | require 'rolify/role'
7 |
8 | module Rolify
9 | extend Configure
10 |
11 | attr_accessor :role_cname, :adapter, :resource_adapter, :role_join_table_name, :role_table_name, :strict_rolify
12 | @@resource_types = []
13 |
14 | def rolify(options = {})
15 | include Role
16 | extend Dynamic if Rolify.dynamic_shortcuts
17 |
18 | options.reverse_merge!({:role_cname => 'Role'})
19 | self.role_cname = options[:role_cname]
20 | self.role_table_name = self.role_cname.tableize.gsub(/\//, "_")
21 |
22 | default_join_table = "#{self.to_s.tableize.gsub(/\//, "_")}_#{self.role_table_name}"
23 | options.reverse_merge!({:role_join_table_name => default_join_table})
24 | self.role_join_table_name = options[:role_join_table_name]
25 |
26 | rolify_options = { :class_name => options[:role_cname].camelize }
27 | rolify_options.merge!({ :join_table => self.role_join_table_name }) if Rolify.orm == "active_record"
28 | rolify_options.merge!(options.reject{ |k,v| ![ :before_add, :after_add, :before_remove, :after_remove, :inverse_of ].include? k.to_sym })
29 |
30 | has_and_belongs_to_many :roles, **rolify_options
31 |
32 | self.adapter = Rolify::Adapter::Base.create("role_adapter", self.role_cname, self.name)
33 |
34 | #use strict roles
35 | self.strict_rolify = true if options[:strict]
36 | end
37 |
38 | def adapter
39 | return self.superclass.adapter unless self.instance_variable_defined? '@adapter'
40 | @adapter
41 | end
42 |
43 | def resourcify(association_name = :roles, options = {})
44 | include Resource
45 |
46 | options.reverse_merge!({ :role_cname => 'Role', :dependent => :destroy })
47 | resourcify_options = { :class_name => options[:role_cname].camelize, :as => :resource, :dependent => options[:dependent] }
48 | self.role_cname = options[:role_cname]
49 | self.role_table_name = self.role_cname.tableize.gsub(/\//, "_")
50 |
51 | has_many association_name, **resourcify_options
52 |
53 | self.resource_adapter = Rolify::Adapter::Base.create("resource_adapter", self.role_cname, self.name)
54 | @@resource_types << self.name
55 | end
56 |
57 | def resource_adapter
58 | return self.superclass.resource_adapter unless self.instance_variable_defined? '@resource_adapter'
59 | @resource_adapter
60 | end
61 |
62 | def scopify
63 | require "rolify/adapters/#{Rolify.orm}/scopes.rb"
64 | extend Rolify::Adapter::Scopes
65 | end
66 |
67 | def role_class
68 | return self.superclass.role_class unless self.instance_variable_defined? '@role_cname'
69 | self.role_cname.constantize
70 | end
71 |
72 | def self.resource_types
73 | @@resource_types
74 | end
75 |
76 | end
77 |
--------------------------------------------------------------------------------
/lib/rolify/adapters/active_record/resource_adapter.rb:
--------------------------------------------------------------------------------
1 | require 'rolify/adapters/base'
2 |
3 | module Rolify
4 | module Adapter
5 | class ResourceAdapter < ResourceAdapterBase
6 | def find_roles(role_name, relation, user)
7 | roles = user && (user != :any) ? user.roles : self.role_class
8 | roles = roles.where('resource_type IN (?)', self.relation_types_for(relation))
9 | roles = roles.where(:name => role_name.to_s) if role_name && (role_name != :any)
10 | roles
11 | end
12 |
13 | def resources_find(roles_table, relation, role_name)
14 | klasses = self.relation_types_for(relation)
15 | relations = klasses.inject('') do |str, klass|
16 | str = "#{str}'#{klass.to_s}'"
17 | str << ', ' unless klass == klasses.last
18 | str
19 | end
20 |
21 | resources = relation.joins("INNER JOIN #{quote_table(roles_table)} ON #{quote_table(roles_table)}.resource_type IN (#{relations}) AND
22 | (#{quote_table(roles_table)}.resource_id IS NULL OR #{quote_table(roles_table)}.resource_id = #{quote_table(relation.table_name)}.#{quote_column(relation.primary_key)})")
23 | resources = resources.where("#{quote_table(roles_table)}.name IN (?) AND #{quote_table(roles_table)}.resource_type IN (?)", Array(role_name), klasses)
24 | resources = resources.select("#{quote_table(relation.table_name)}.*")
25 | resources
26 | end
27 |
28 | def in(relation, user, role_names)
29 | roles = user.roles.where(:name => role_names).select("#{quote_table(role_class.table_name)}.#{quote_column(role_class.primary_key)}")
30 | relation.where("#{quote_table(role_class.table_name)}.#{quote_column(role_class.primary_key)} IN (?) AND ((#{quote_table(role_class.table_name)}.resource_id = #{quote_table(relation.table_name)}.#{quote_column(relation.primary_key)}) OR (#{quote_table(role_class.table_name)}.resource_id IS NULL))", roles)
31 | end
32 |
33 | def applied_roles(relation, children)
34 | if children
35 | relation.role_class.where('resource_type IN (?) AND resource_id IS NULL', self.relation_types_for(relation))
36 | else
37 | relation.role_class.where('resource_type = ? AND resource_id IS NULL', relation.to_s)
38 | end
39 | end
40 |
41 | def all_except(resource, excluded_obj)
42 | prime_key = resource.primary_key.to_sym
43 | resource.where.not(prime_key => excluded_obj.pluck(prime_key))
44 | end
45 |
46 | private
47 |
48 | def quote_column(column)
49 | ActiveRecord::Base.connection.quote_column_name column
50 | end
51 |
52 | def quote_table(table)
53 | ActiveRecord::Base.connection.quote_table_name table
54 | end
55 |
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/lib/rolify/adapters/active_record/role_adapter.rb:
--------------------------------------------------------------------------------
1 | require 'rolify/adapters/base'
2 |
3 | module Rolify
4 | module Adapter
5 | class RoleAdapter < RoleAdapterBase
6 | def where(relation, *args)
7 | conditions, values = build_conditions(relation, args)
8 | relation.where(conditions, *values)
9 | end
10 |
11 | def where_strict(relation, args)
12 | wrap_conditions = relation.name != role_class.name
13 |
14 | conditions = if args[:resource].is_a?(Class)
15 | {:resource_type => args[:resource].to_s, :resource_id => nil }
16 | elsif args[:resource].present?
17 | {:resource_type => args[:resource].class.name, :resource_id => args[:resource].id}
18 | else
19 | {}
20 | end
21 |
22 | conditions.merge!(:name => args[:name])
23 | conditions = wrap_conditions ? { role_table => conditions } : conditions
24 |
25 | relation.where(conditions)
26 | end
27 |
28 | def find_cached(relation, args)
29 | resource_id = (args[:resource].nil? || args[:resource].is_a?(Class) || args[:resource] == :any) ? nil : args[:resource].id
30 | resource_type = args[:resource].is_a?(Class) ? args[:resource].to_s : args[:resource].class.name
31 |
32 | return relation.find_all { |role| role.name == args[:name].to_s } if args[:resource] == :any
33 |
34 | relation.find_all do |role|
35 | (role.name == args[:name].to_s && role.resource_type == nil && role.resource_id == nil) ||
36 | (role.name == args[:name].to_s && role.resource_type == resource_type && role.resource_id == nil) ||
37 | (role.name == args[:name].to_s && role.resource_type == resource_type && role.resource_id == resource_id)
38 | end
39 | end
40 |
41 | def find_cached_strict(relation, args)
42 | resource_id = (args[:resource].nil? || args[:resource].is_a?(Class)) ? nil : args[:resource].id
43 | resource_type = args[:resource].is_a?(Class) ? args[:resource].to_s : args[:resource].class.name
44 |
45 | relation.find_all do |role|
46 | role.resource_id == resource_id && role.resource_type == resource_type && role.name == args[:name].to_s
47 | end
48 | end
49 |
50 | def find_or_create_by(role_name, resource_type = nil, resource_id = nil)
51 | role_class.where(:name => role_name, :resource_type => resource_type, :resource_id => resource_id).first_or_create
52 | end
53 |
54 | def add(relation, role)
55 | relation.roles << role unless relation.roles.include?(role)
56 | end
57 |
58 | def remove(relation, role_name, resource = nil)
59 | cond = { :name => role_name }
60 | cond[:resource_type] = (resource.is_a?(Class) ? resource.to_s : resource.class.name) if resource
61 | cond[:resource_id] = resource.id if resource && !resource.is_a?(Class)
62 | roles = relation.roles.where(cond)
63 | if roles
64 | relation.roles.delete(roles)
65 | roles.each do |role|
66 | role.destroy if role.send(ActiveSupport::Inflector.demodulize(user_class).tableize.to_sym).limit(1).empty?
67 | end if Rolify.remove_role_if_empty
68 | end
69 | roles
70 | end
71 |
72 | def exists?(relation, column)
73 | relation.where("#{column} IS NOT NULL")
74 | end
75 |
76 | def scope(relation, conditions, strict)
77 | query = relation.joins(:roles)
78 | query = strict ? where_strict(query, conditions) : where(query, conditions)
79 | query
80 | end
81 |
82 | def all_except(user, excluded_obj)
83 | user.where.not(user.primary_key => excluded_obj)
84 | end
85 |
86 | private
87 |
88 | def build_conditions(relation, args)
89 | conditions = []
90 | values = []
91 | args.each do |arg|
92 | if arg.is_a? Hash
93 | a, v = build_query(arg[:name], arg[:resource])
94 | elsif arg.is_a?(String) || arg.is_a?(Symbol)
95 | a, v = build_query(arg.to_s)
96 | else
97 | raise ArgumentError, "Invalid argument type: only hash or string or a symbol allowed"
98 | end
99 | conditions << a
100 | values += v
101 | end
102 | conditions = conditions.join(' OR ')
103 | [ conditions, values ]
104 | end
105 |
106 | def build_query(role, resource = nil)
107 | return [ "#{role_table}.name = ?", [ role ] ] if resource == :any
108 | query = "((#{role_table}.name = ?) AND (#{role_table}.resource_type IS NULL) AND (#{role_table}.resource_id IS NULL))"
109 | values = [ role ]
110 | if resource
111 | query.insert(0, "(")
112 | query += " OR ((#{role_table}.name = ?) AND (#{role_table}.resource_type = ?) AND (#{role_table}.resource_id IS NULL))"
113 | values << role << (resource.is_a?(Class) ? resource.to_s : resource.class.name)
114 | if !resource.is_a? Class
115 | query += " OR ((#{role_table}.name = ?) AND (#{role_table}.resource_type = ?) AND (#{role_table}.resource_id = ?))"
116 | values << role << resource.class.name << resource.id
117 | end
118 | query += ")"
119 | end
120 | [ query, values ]
121 | end
122 | end
123 | end
124 | end
125 |
--------------------------------------------------------------------------------
/lib/rolify/adapters/active_record/scopes.rb:
--------------------------------------------------------------------------------
1 | module Rolify
2 | module Adapter
3 | module Scopes
4 | def global
5 | where(:resource_type => nil, :resource_id => nil)
6 | end
7 |
8 | def class_scoped(resource_type = nil)
9 | where_conditions = "resource_type IS NOT NULL AND resource_id IS NULL"
10 | where_conditions = [ "resource_type = ? AND resource_id IS NULL", resource_type.name ] if resource_type
11 | where(where_conditions)
12 | end
13 |
14 | def instance_scoped(resource_type = nil)
15 | where_conditions = "resource_type IS NOT NULL AND resource_id IS NOT NULL"
16 | if resource_type
17 | if resource_type.is_a? Class
18 | where_conditions = [ "resource_type = ? AND resource_id IS NOT NULL", resource_type.name ]
19 | else
20 | where_conditions = [ "resource_type = ? AND resource_id = ?", resource_type.class.name, resource_type.id ]
21 | end
22 | end
23 | where(where_conditions)
24 | end
25 | end
26 | end
27 | end
--------------------------------------------------------------------------------
/lib/rolify/adapters/base.rb:
--------------------------------------------------------------------------------
1 | module Rolify
2 | module Adapter
3 | class Base
4 | def initialize(role_cname, user_cname)
5 | @role_cname = role_cname
6 | @user_cname = user_cname
7 | end
8 |
9 | def role_class
10 | @role_cname.constantize
11 | end
12 |
13 | def user_class
14 | @user_cname.constantize
15 | end
16 |
17 | def role_table
18 | role_class.table_name
19 | end
20 |
21 | def self.create(adapter, role_cname, user_cname)
22 | load "rolify/adapters/#{Rolify.orm}/#{adapter}.rb"
23 | load "rolify/adapters/#{Rolify.orm}/scopes.rb"
24 | Rolify::Adapter.const_get(adapter.camelize.to_sym).new(role_cname, user_cname)
25 | end
26 |
27 | def relation_types_for(relation)
28 | relation.descendants.map(&:to_s).push(relation.to_s)
29 | end
30 | end
31 |
32 | class RoleAdapterBase < Adapter::Base
33 | def where(relation, args)
34 | raise NotImplementedError.new("You must implement where")
35 | end
36 |
37 | def find_or_create_by(role_name, resource_type = nil, resource_id = nil)
38 | raise NotImplementedError.new("You must implement find_or_create_by")
39 | end
40 |
41 | def add(relation, role_name, resource = nil)
42 | raise NotImplementedError.new("You must implement add")
43 | end
44 |
45 | def remove(relation, role_name, resource = nil)
46 | raise NotImplementedError.new("You must implement delete")
47 | end
48 |
49 | def exists?(relation, column)
50 | raise NotImplementedError.new("You must implement exists?")
51 | end
52 | end
53 |
54 | class ResourceAdapterBase < Adapter::Base
55 | def resources_find(roles_table, relation, role_name)
56 | raise NotImplementedError.new("You must implement resources_find")
57 | end
58 |
59 | def in(resources, roles)
60 | raise NotImplementedError.new("You must implement in")
61 | end
62 |
63 | end
64 | end
65 | end
--------------------------------------------------------------------------------
/lib/rolify/adapters/mongoid/resource_adapter.rb:
--------------------------------------------------------------------------------
1 | require 'rolify/adapters/base'
2 |
3 | module Rolify
4 | module Adapter
5 | class ResourceAdapter < ResourceAdapterBase
6 |
7 | def find_roles(role_name, relation, user)
8 | roles = user && (user != :any) ? user.roles : self.role_class
9 | roles = roles.where(:resource_type.in => self.relation_types_for(relation))
10 | roles = roles.where(:name => role_name.to_s) if role_name && (role_name != :any)
11 | roles
12 | end
13 |
14 | def resources_find(roles_table, relation, role_name)
15 | roles = roles_table.classify.constantize.where(:name.in => Array(role_name), :resource_type.in => self.relation_types_for(relation))
16 | resources = []
17 | roles.each do |role|
18 | if role.resource_id.nil?
19 | resources += relation.all
20 | else
21 | resources << role.resource
22 | end
23 | end
24 | resources.compact.uniq
25 | end
26 |
27 | def in(resources, user, role_names)
28 | roles = user.roles.where(:name.in => Array(role_names))
29 | return [] if resources.empty? || roles.empty?
30 | resources.delete_if { |resource| (resource.applied_roles & roles).empty? }
31 | resources
32 | end
33 |
34 | def applied_roles(relation, children)
35 | if children
36 | relation.role_class.where(:resource_type.in => self.relation_types_for(relation), :resource_id => nil)
37 | else
38 | relation.role_class.where(:resource_type => relation.to_s, :resource_id => nil)
39 | end
40 | end
41 |
42 | def all_except(resource, excluded_obj)
43 | resource.not_in(_id: excluded_obj.to_a)
44 | end
45 |
46 | end
47 | end
48 | end
--------------------------------------------------------------------------------
/lib/rolify/adapters/mongoid/role_adapter.rb:
--------------------------------------------------------------------------------
1 | require 'rolify/adapters/base'
2 |
3 | module Rolify
4 | module Adapter
5 | class RoleAdapter < RoleAdapterBase
6 | def where(relation, *args)
7 | conditions = build_conditions(relation, args)
8 | relation.any_of(*conditions)
9 | end
10 |
11 | def where_strict(relation, args)
12 | wrap_conditions = relation.name != role_class.name
13 |
14 | conditions = if args[:resource].is_a?(Class)
15 | {:resource_type => args[:resource].to_s, :resource_id => nil }
16 | elsif args[:resource].present?
17 | {:resource_type => args[:resource].class.name, :resource_id => args[:resource].id}
18 | else
19 | {}
20 | end
21 |
22 | conditions.merge!(:name => args[:name])
23 | conditions = wrap_conditions ? { role_table => conditions } : conditions
24 |
25 | relation.where(conditions)
26 | end
27 |
28 | def find_cached(relation, args)
29 | resource_id = (args[:resource].nil? || args[:resource].is_a?(Class) || args[:resource] == :any) ? nil : args[:resource].id
30 | resource_type = args[:resource].is_a?(Class) ? args[:resource].to_s : args[:resource].class.name
31 |
32 | return relation.find_all { |role| role.name == args[:name].to_s } if args[:resource] == :any
33 |
34 | relation.find_all do |role|
35 | (role.name == args[:name].to_s && role.resource_type == nil && role.resource_id == nil) ||
36 | (role.name == args[:name].to_s && role.resource_type == resource_type && role.resource_id == nil) ||
37 | (role.name == args[:name].to_s && role.resource_type == resource_type && role.resource_id == resource_id)
38 | end
39 | end
40 |
41 | def find_cached_strict(relation, args)
42 | resource_id = (args[:resource].nil? || args[:resource].is_a?(Class)) ? nil : args[:resource].id
43 | resource_type = args[:resource].is_a?(Class) ? args[:resource].to_s : args[:resource].class.name
44 |
45 | relation.find_all do |role|
46 | role.resource_id == resource_id && role.resource_type == resource_type && role.name == args[:name].to_s
47 | end
48 | end
49 |
50 | def find_or_create_by(role_name, resource_type = nil, resource_id = nil)
51 | self.role_class.find_or_create_by(:name => role_name,
52 | :resource_type => resource_type,
53 | :resource_id => resource_id)
54 | end
55 |
56 | def add(relation, role)
57 | relation.roles << role
58 | end
59 |
60 | def remove(relation, role_name, resource = nil)
61 | #roles = { :name => role_name }
62 | #roles.merge!({:resource_type => (resource.is_a?(Class) ? resource.to_s : resource.class.name)}) if resource
63 | #roles.merge!({ :resource_id => resource.id }) if resource && !resource.is_a?(Class)
64 | #roles_to_remove = relation.roles.where(roles)
65 | #roles_to_remove.each do |role|
66 | # # Deletion in n-n relations is unreliable. Sometimes it works, sometimes not.
67 | # # So, this does not work all the time: `relation.roles.delete(role)`
68 | # # @see http://stackoverflow.com/questions/9132596/rails3-mongoid-many-to-many-relation-and-delete-operation
69 | # # We instead remove ids from the Role object and the relation object.
70 | # relation.role_ids.delete(role.id)
71 | # role.send((user_class.to_s.underscore + '_ids').to_sym).delete(relation.id)
72 | #
73 | # role.destroy if role.send(user_class.to_s.tableize.to_sym).empty?
74 | #end
75 | cond = { :name => role_name }
76 | cond[:resource_type] = (resource.is_a?(Class) ? resource.to_s : resource.class.name) if resource
77 | cond[:resource_id] = resource.id if resource && !resource.is_a?(Class)
78 | roles = relation.roles.where(cond)
79 | roles.each do |role|
80 | relation.roles.delete(role)
81 | role.send(ActiveSupport::Inflector.demodulize(user_class).tableize.to_sym).delete(relation)
82 | if Rolify.remove_role_if_empty && role.send(ActiveSupport::Inflector.demodulize(user_class).tableize.to_sym).empty?
83 | role.destroy
84 | end
85 | end if roles
86 | roles
87 | end
88 |
89 | def exists?(relation, column)
90 | relation.where(column.to_sym.ne => nil)
91 | end
92 |
93 | def scope(relation, conditions, strict)
94 | query = strict ? where_strict(role_class, conditions) : where(role_class, conditions)
95 | roles = query.map { |role| role.id }
96 | return [] if roles.size.zero?
97 | query = relation.any_in(:role_ids => roles)
98 | query
99 | end
100 |
101 | def all_except(user, excluded_obj)
102 | user.not_in(_id: excluded_obj.to_a)
103 | end
104 |
105 | private
106 |
107 | def build_conditions(relation, args)
108 | conditions = []
109 | args.each do |arg|
110 | if arg.is_a? Hash
111 | query = build_query(arg[:name], arg[:resource])
112 | elsif arg.is_a?(String) || arg.is_a?(Symbol)
113 | query = build_query(arg)
114 | else
115 | raise ArgumentError, "Invalid argument type: only hash or string or symbol allowed"
116 | end
117 | conditions += query
118 | end
119 | conditions
120 | end
121 |
122 | def build_query(role, resource = nil)
123 | return [{ :name => role }] if resource == :any
124 | query = [{ :name => role, :resource_type => nil, :resource_id => nil }]
125 | if resource
126 | query << { :name => role, :resource_type => (resource.is_a?(Class) ? resource.to_s : resource.class.name), :resource_id => nil }
127 | if !resource.is_a? Class
128 | query << { :name => role, :resource_type => resource.class.name, :resource_id => resource.id }
129 | end
130 | end
131 | query
132 | end
133 | end
134 | end
135 | end
136 |
--------------------------------------------------------------------------------
/lib/rolify/adapters/mongoid/scopes.rb:
--------------------------------------------------------------------------------
1 | module Rolify
2 | module Adapter
3 | module Scopes
4 | def global
5 | where(:resource_type => nil, :resource_id => nil)
6 | end
7 |
8 | def class_scoped(resource_type = nil)
9 | where_conditions = { :resource_type.ne => nil, :resource_id => nil }
10 | where_conditions = { :resource_type => resource_type.name, :resource_id => nil } if resource_type
11 | where(where_conditions)
12 | end
13 |
14 | def instance_scoped(resource_type = nil)
15 | where_conditions = { :resource_type.ne => nil, :resource_id.ne => nil }
16 | if resource_type
17 | if resource_type.is_a? Class
18 | where_conditions = { :resource_type => resource_type.name, :resource_id.ne => nil }
19 | else
20 | where_conditions = { :resource_type => resource_type.class.name, :resource_id => resource_type.id }
21 | end
22 | end
23 | where(where_conditions)
24 | end
25 | end
26 | end
27 | end
--------------------------------------------------------------------------------
/lib/rolify/configure.rb:
--------------------------------------------------------------------------------
1 | module Rolify
2 | module Configure
3 | @@dynamic_shortcuts = false
4 | @@orm = "active_record"
5 | @@remove_role_if_empty = true
6 |
7 | def configure(*role_cnames)
8 | return if !sanity_check(role_cnames)
9 | yield self if block_given?
10 | end
11 |
12 | def dynamic_shortcuts
13 | @@dynamic_shortcuts
14 | end
15 |
16 | def dynamic_shortcuts=(is_dynamic)
17 | @@dynamic_shortcuts = is_dynamic
18 | end
19 |
20 | def orm
21 | @@orm
22 | end
23 |
24 | def orm=(orm)
25 | @@orm = orm
26 | end
27 |
28 | def use_mongoid
29 | self.orm = "mongoid"
30 | end
31 |
32 | def use_dynamic_shortcuts
33 | return if !sanity_check([])
34 | self.dynamic_shortcuts = true
35 | end
36 |
37 | def use_defaults
38 | configure do |config|
39 | config.dynamic_shortcuts = false
40 | config.orm = "active_record"
41 | end
42 | end
43 |
44 | def remove_role_if_empty=(is_remove)
45 | @@remove_role_if_empty = is_remove
46 | end
47 |
48 | def remove_role_if_empty
49 | @@remove_role_if_empty
50 | end
51 |
52 | private
53 |
54 | def sanity_check(role_cnames)
55 | return true if ARGV.reduce(nil) { |acc,arg| arg =~ /assets:/ if acc.nil? } == 0
56 |
57 | role_cnames.each do |role_cname|
58 | role_class = role_cname.constantize
59 | if role_class.superclass.to_s == "ActiveRecord::Base" && role_table_missing?(role_class)
60 | warn "[WARN] table '#{role_cname}' doesn't exist. Did you run the migration? Ignoring rolify config."
61 | return false
62 | end
63 | end
64 | true
65 | end
66 |
67 | def role_table_missing?(role_class)
68 | !role_class.table_exists?
69 | rescue ActiveRecord::NoDatabaseError
70 | true
71 | end
72 |
73 | end
74 | end
75 |
--------------------------------------------------------------------------------
/lib/rolify/dynamic.rb:
--------------------------------------------------------------------------------
1 | require "rolify/configure"
2 |
3 | module Rolify
4 | module Dynamic
5 | def define_dynamic_method(role_name, resource)
6 | class_eval do
7 | define_method("is_#{role_name}?".to_sym) do
8 | has_role?("#{role_name}")
9 | end if !method_defined?("is_#{role_name}?".to_sym) && self.adapter.where_strict(self.role_class, name: role_name).exists?
10 |
11 | define_method("is_#{role_name}_of?".to_sym) do |arg|
12 | has_role?("#{role_name}", arg)
13 | end if !method_defined?("is_#{role_name}_of?".to_sym) && resource && self.adapter.where_strict(self.role_class, name: role_name, resource: resource).exists?
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/rolify/finders.rb:
--------------------------------------------------------------------------------
1 | module Rolify
2 | module Finders
3 | def with_role(role_name, resource = nil)
4 | strict = self.strict_rolify && resource && resource != :any
5 | self.adapter.scope(
6 | self,
7 | { :name => role_name, :resource => resource },
8 | strict
9 | )
10 | end
11 |
12 | def without_role(role_name, resource = nil)
13 | self.adapter.all_except(self, self.with_role(role_name, resource))
14 | end
15 |
16 | def with_all_roles(*args)
17 | users = []
18 | parse_args(args, users) do |users_to_add|
19 | users = users_to_add if users.empty?
20 | users &= users_to_add
21 | return [] if users.empty?
22 | end
23 | users
24 | end
25 |
26 | def with_any_role(*args)
27 | users = []
28 | parse_args(args, users) do |users_to_add|
29 | users += users_to_add
30 | end
31 | users.uniq
32 | end
33 | end
34 |
35 | private
36 |
37 | def parse_args(args, users, &block)
38 | args.each do |arg|
39 | if arg.is_a? Hash
40 | users_to_add = self.with_role(arg[:name], arg[:resource])
41 | elsif arg.is_a?(String) || arg.is_a?(Symbol)
42 | users_to_add = self.with_role(arg)
43 | else
44 | raise ArgumentError, "Invalid argument type: only hash or string or symbol allowed"
45 | end
46 | block.call(users_to_add)
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/lib/rolify/matchers.rb:
--------------------------------------------------------------------------------
1 | require 'rspec/expectations'
2 |
3 | RSpec::Matchers.define :have_role do |*args|
4 | match do |resource|
5 | resource.has_role?(*args)
6 | end
7 |
8 | failure_message do |resource|
9 | "expected to have role #{args.map(&:inspect).join(" ")}"
10 | end
11 |
12 | failure_message_when_negated do |resource|
13 | "expected not to have role #{args.map(&:inspect).join(" ")}"
14 | end
15 | end
16 |
17 | RSpec::Matchers.define :be_the_same_role do |*expected|
18 | match do |actual|
19 | if expected.size > 1
20 | if expected[1].is_a? Class
21 | actual[:name] == expected[0] && actual[:resource_type] == expected[1].to_s
22 | else
23 | actual[:name] == expected[0] &&
24 | actual[:resource_type] == expected[1].class.name &&
25 | actual[:resource_id] == expected[1].id
26 | end
27 | else
28 | actual[:name] == expected[0]
29 | end
30 | end
31 | end
--------------------------------------------------------------------------------
/lib/rolify/railtie.rb:
--------------------------------------------------------------------------------
1 | require 'rolify'
2 | require 'rails'
3 |
4 | module Rolify
5 | class Railtie < Rails::Railtie
6 | initializer 'rolify.initialize' do
7 | ActiveSupport.on_load(:active_record) do
8 | ActiveRecord::Base.send :extend, Rolify
9 | end
10 |
11 | config.before_initialize do
12 | ::Mongoid::Document.module_eval do
13 | def self.included(base)
14 | base.extend Rolify
15 | end
16 | end
17 | end if defined?(Mongoid)
18 | end
19 | end
20 | end
--------------------------------------------------------------------------------
/lib/rolify/resource.rb:
--------------------------------------------------------------------------------
1 | module Rolify
2 | module Resource
3 | def self.included(base)
4 | base.extend ClassMethods
5 | end
6 |
7 | module ClassMethods
8 | def find_roles(role_name = nil, user = nil)
9 | self.resource_adapter.find_roles(role_name, self, user)
10 | end
11 |
12 | def with_role(role_name, user = nil)
13 | if role_name.is_a? Array
14 | role_name = role_name.map(&:to_s)
15 | else
16 | role_name = role_name.to_s
17 | end
18 |
19 | resources = self.resource_adapter.resources_find(self.role_table_name, self, role_name) #.map(&:id)
20 | user ? self.resource_adapter.in(resources, user, role_name) : resources
21 | end
22 | alias :with_roles :with_role
23 | alias :find_as :with_role
24 | alias :find_multiple_as :with_role
25 |
26 |
27 | def without_role(role_name, user = nil)
28 | self.resource_adapter.all_except(self, self.find_as(role_name, user))
29 | end
30 | alias :without_roles :without_role
31 | alias :except_as :without_role
32 | alias :except_multiple_as :without_role
33 |
34 |
35 |
36 | def applied_roles(children = true)
37 | self.resource_adapter.applied_roles(self, children)
38 | end
39 |
40 |
41 |
42 | end
43 |
44 | def applied_roles
45 | #self.roles + self.class.role_class.where(:resource_type => self.class.to_s, :resource_id => nil)
46 | self.roles + self.class.applied_roles(true)
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/lib/rolify/role.rb:
--------------------------------------------------------------------------------
1 | require "rolify/finders"
2 | require "rolify/utils"
3 |
4 | module Rolify
5 | module Role
6 | extend Utils
7 |
8 | def self.included(base)
9 | base.extend Finders
10 | end
11 |
12 | def add_role(role_name, resource = nil)
13 | role = self.class.adapter.find_or_create_by(role_name.to_s,
14 | (resource.is_a?(Class) ? resource.to_s : resource.class.name if resource),
15 | (resource.id if resource && !resource.is_a?(Class)))
16 |
17 | if !roles.include?(role)
18 | self.class.define_dynamic_method(role_name, resource) if Rolify.dynamic_shortcuts
19 | self.class.adapter.add(self, role)
20 | end
21 | role
22 | end
23 | alias_method :grant, :add_role
24 |
25 | def has_role?(role_name, resource = nil)
26 | return has_strict_role?(role_name, resource) if self.class.strict_rolify and resource and resource != :any
27 |
28 | if new_record?
29 | role_array = self.roles.detect { |r|
30 | r.name.to_s == role_name.to_s &&
31 | (r.resource == resource ||
32 | resource.nil? ||
33 | (resource == :any && r.resource.present?))
34 | }
35 | else
36 | role_array = self.class.adapter.where(self.roles, name: role_name, resource: resource)
37 | end
38 |
39 | return false if role_array.nil?
40 | role_array != []
41 | end
42 |
43 | def has_strict_role?(role_name, resource)
44 | self.class.adapter.where_strict(self.roles, name: role_name, resource: resource).any?
45 | end
46 |
47 | def has_cached_role?(role_name, resource = nil)
48 | return has_strict_cached_role?(role_name, resource) if self.class.strict_rolify and resource and resource != :any
49 | self.class.adapter.find_cached(self.roles, name: role_name, resource: resource).any?
50 | end
51 |
52 | def has_strict_cached_role?(role_name, resource = nil)
53 | self.class.adapter.find_cached_strict(self.roles, name: role_name, resource: resource).any?
54 | end
55 |
56 | def has_all_roles?(*args)
57 | args.each do |arg|
58 | if arg.is_a? Hash
59 | return false if !self.has_role?(arg[:name], arg[:resource])
60 | elsif arg.is_a?(String) || arg.is_a?(Symbol)
61 | return false if !self.has_role?(arg)
62 | else
63 | raise ArgumentError, "Invalid argument type: only hash or string or symbol allowed"
64 | end
65 | end
66 | true
67 | end
68 |
69 | def has_any_role?(*args)
70 | if new_record?
71 | args.any? { |r| self.has_role?(r) }
72 | else
73 | self.class.adapter.where(self.roles, *args).size > 0
74 | end
75 | end
76 |
77 | def only_has_role?(role_name, resource = nil)
78 | return self.has_role?(role_name,resource) && self.roles.count == 1
79 | end
80 |
81 | def remove_role(role_name, resource = nil)
82 | self.class.adapter.remove(self, role_name.to_s, resource)
83 | end
84 |
85 | alias_method :revoke, :remove_role
86 | deprecate :has_no_role, :remove_role
87 |
88 | def roles_name
89 | self.roles.pluck(:name)
90 | end
91 |
92 | def method_missing(method, *args, &block)
93 | if method.to_s.match(/^is_(\w+)_of[?]$/) || method.to_s.match(/^is_(\w+)[?]$/)
94 | resource = args.first
95 | self.class.define_dynamic_method $1, resource
96 | return has_role?("#{$1}", resource)
97 | end if Rolify.dynamic_shortcuts
98 | super
99 | end
100 |
101 | def respond_to?(method, include_private = false)
102 | if Rolify.dynamic_shortcuts && (method.to_s.match(/^is_(\w+)_of[?]$/) || method.to_s.match(/^is_(\w+)[?]$/))
103 | query = self.class.role_class.where(:name => $1)
104 | query = self.class.adapter.exists?(query, :resource_type) if method.to_s.match(/^is_(\w+)_of[?]$/)
105 | return true if query.count > 0
106 | false
107 | else
108 | super
109 | end
110 | end
111 | end
112 | end
113 |
--------------------------------------------------------------------------------
/lib/rolify/utils.rb:
--------------------------------------------------------------------------------
1 | module Rolify
2 | module Utils
3 | def deprecate(old_method, new_method)
4 | define_method(old_method) do |*args|
5 | warn "[DEPRECATION] #{caller.first}: `#{old_method}` is deprecated. Please use `#{new_method}` instead."
6 | send(new_method, *args)
7 | end
8 | end
9 | end
10 | end
--------------------------------------------------------------------------------
/lib/rolify/version.rb:
--------------------------------------------------------------------------------
1 | module Rolify
2 | VERSION = "6.0.1"
3 | end
4 |
--------------------------------------------------------------------------------
/rolify.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | $:.push File.expand_path('../lib', __FILE__)
3 | require 'rolify/version'
4 |
5 | Gem::Specification.new do |s|
6 | s.name = 'rolify'
7 | s.summary = %q{Roles library with resource scoping}
8 | s.description = %q{Very simple Roles library without any authorization enforcement supporting scope on resource objects (instance or class). Supports ActiveRecord and Mongoid ORMs.}
9 | s.version = Rolify::VERSION
10 | s.platform = Gem::Platform::RUBY
11 | s.homepage = 'https://github.com/RolifyCommunity/rolify'
12 |
13 | s.license = 'MIT'
14 |
15 | s.authors = [
16 | 'Florent Monbillard',
17 | 'Wellington Cordeiro'
18 | ]
19 | s.email = [
20 | 'f.monbillard@gmail.com',
21 | 'wellington@wellingtoncordeiro.com'
22 | ]
23 |
24 | s.files = `git ls-files`.split("\n")
25 | s.test_files = `git ls-files -- spec/*`.split("\n")
26 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
27 | s.require_paths = ['lib']
28 |
29 | s.required_ruby_version = '>= 2.5'
30 |
31 | s.add_development_dependency 'ammeter', '~> 1.1' # Spec generator
32 | s.add_development_dependency 'appraisal', '~> 2.0'
33 | s.add_development_dependency 'bundler', '~> 2.0' # packaging feature
34 | s.add_development_dependency 'rake', '~> 12.3' # Tasks manager
35 | s.add_development_dependency 'rspec-rails', '~> 3.8'
36 | end
37 |
--------------------------------------------------------------------------------
/spec/README.rdoc:
--------------------------------------------------------------------------------
1 | = Rolify Specs
2 |
3 | == Running the specs
4 |
5 | To run the specs first run the +bundle+ command to install the necessary gems and the +rake+ command to run the specs.
6 |
7 | bundle
8 | rake
9 |
10 | == Model Adapters
11 |
12 | Rolify currently supports 2 different ORMs: ActiveRecord and Mongoid. By default it will use Active Record but you can change this by setting the +ADAPTER+ environment variable before running the specs. You can run the +bundle+ command with this as well to ensure you have all the required gems.
13 |
14 | ADAPTER=mongoid bundle
15 | ADAPTER=mongoid rake
16 |
17 | The different model adapters you can specify are:
18 |
19 | * active_record (default)
20 | * mongoid
21 |
22 | You can also run the +spec_all+ rake task to run specs for each adapter.
23 |
24 | rake spec_all
--------------------------------------------------------------------------------
/spec/common_helper.rb:
--------------------------------------------------------------------------------
1 | require 'test-unit'
2 |
3 | begin
4 | require 'pry'
5 | rescue LoadError
6 | end
7 |
8 | # `Test::Unit::AutoRunner.need_auto_run=` was introduced to the test-unit
9 | # gem in version 2.4.9. Previous to this version `Test::Unit.run=` was
10 | # used. The implementation of test-unit included with Ruby has neither
11 | # method.
12 | if defined? Test::Unit::AutoRunner
13 | Test::Unit::AutoRunner.need_auto_run = false
14 | elsif defined?(Test::Unit)
15 | Test::Unit.run = false
16 | end
17 |
--------------------------------------------------------------------------------
/spec/generators/rolify/rolify_activerecord_generator_spec.rb:
--------------------------------------------------------------------------------
1 | require 'generators_helper'
2 |
3 | # Generators are not automatically loaded by Rails
4 | require 'generators/rolify/rolify_generator'
5 |
6 | describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'active_record' do
7 | # Tell the generator where to put its output (what it thinks of as Rails.root)
8 | destination File.expand_path("../../../../tmp", __FILE__)
9 | teardown :cleanup_destination_root
10 |
11 | let(:adapter) { 'SQLite3Adapter' }
12 | before {
13 | prepare_destination
14 | }
15 |
16 | def cleanup_destination_root
17 | FileUtils.rm_rf destination_root
18 | end
19 |
20 | describe 'specifying only Role class name' do
21 | before(:all) { arguments %w(Role) }
22 |
23 | before {
24 | allow(ActiveRecord::Base).to receive_message_chain(
25 | 'connection.class.to_s.demodulize') { adapter }
26 | capture(:stdout) {
27 | generator.create_file "app/models/user.rb" do
28 | <<-RUBY
29 | class User < ActiveRecord::Base
30 | end
31 | RUBY
32 | end
33 | }
34 | require File.join(destination_root, "app/models/user.rb")
35 | if Rails::VERSION::MAJOR >= 7
36 | run_generator %w(--skip-collision-check)
37 | else
38 | run_generator
39 | end
40 | }
41 |
42 | describe 'config/initializers/rolify.rb' do
43 | subject { file('config/initializers/rolify.rb') }
44 | it { should exist }
45 | it { should contain "Rolify.configure do |config|"}
46 | it { should contain "# config.use_dynamic_shortcuts" }
47 | it { should contain "# config.use_mongoid" }
48 | end
49 |
50 | describe 'app/models/role.rb' do
51 | subject { file('app/models/role.rb') }
52 | it { should exist }
53 | it do
54 | if Rails::VERSION::MAJOR < 5
55 | should contain "class Role < ActiveRecord::Base"
56 | else
57 | should contain "class Role < ApplicationRecord"
58 | end
59 | end
60 | it { should contain "has_and_belongs_to_many :users, :join_table => :users_roles" }
61 | it do
62 | if Rails::VERSION::MAJOR < 5
63 | should contain "belongs_to :resource,\n"
64 | " :polymorphic => true"
65 | else
66 | should contain "belongs_to :resource,\n"
67 | " :polymorphic => true,\n"
68 | " :optional => true"
69 | end
70 | end
71 | it { should contain "belongs_to :resource,\n"
72 | " :polymorphic => true,\n"
73 | " :optional => true"
74 | }
75 | it { should contain "validates :resource_type,\n"
76 | " :inclusion => { :in => Rolify.resource_types },\n"
77 | " :allow_nil => true" }
78 | it { should contain "scopify" }
79 | end
80 |
81 | describe 'app/models/user.rb' do
82 | subject { file('app/models/user.rb') }
83 | it { should contain /class User < ActiveRecord::Base\n rolify\n/ }
84 | end
85 |
86 | describe 'migration file' do
87 | subject { migration_file('db/migrate/rolify_create_roles.rb') }
88 |
89 | it { should be_a_migration }
90 | it { should contain "create_table(:roles) do" }
91 | it { should contain "create_table(:users_roles, :id => false) do" }
92 |
93 | context 'mysql2' do
94 | let(:adapter) { 'Mysql2Adapter' }
95 |
96 | it { expect(subject).to contain('add_index(:roles, :name)') }
97 | end
98 |
99 | context 'sqlite3' do
100 | let(:adapter) { 'SQLite3Adapter' }
101 |
102 | it { expect(subject).to contain('add_index(:roles, :name)') }
103 | end
104 |
105 | context 'pg' do
106 | let(:adapter) { 'PostgreSQLAdapter' }
107 |
108 | it { expect(subject).not_to contain('add_index(:roles, :name)') }
109 | end
110 | end
111 | end
112 |
113 | describe 'specifying User and Role class names' do
114 | before(:all) { arguments %w(AdminRole AdminUser) }
115 |
116 | before {
117 | allow(ActiveRecord::Base).to receive_message_chain(
118 | 'connection.class.to_s.demodulize') { adapter }
119 | capture(:stdout) {
120 | generator.create_file "app/models/admin_user.rb" do
121 | "class AdminUser < ActiveRecord::Base\nend"
122 | end
123 | }
124 | require File.join(destination_root, "app/models/admin_user.rb")
125 | run_generator
126 | }
127 |
128 | describe 'config/initializers/rolify.rb' do
129 | subject { file('config/initializers/rolify.rb') }
130 |
131 | it { should exist }
132 | it { should contain "Rolify.configure(\"AdminRole\") do |config|"}
133 | it { should contain "# config.use_dynamic_shortcuts" }
134 | it { should contain "# config.use_mongoid" }
135 | end
136 |
137 | describe 'app/models/admin_role.rb' do
138 | subject { file('app/models/admin_role.rb') }
139 |
140 | it { should exist }
141 | it do
142 | if Rails::VERSION::MAJOR < 5
143 | should contain "class AdminRole < ActiveRecord::Base"
144 | else
145 | should contain "class AdminRole < ApplicationRecord"
146 | end
147 | end
148 | it { should contain "has_and_belongs_to_many :admin_users, :join_table => :admin_users_admin_roles" }
149 | it { should contain "belongs_to :resource,\n"
150 | " :polymorphic => true,\n"
151 | " :optional => true"
152 | }
153 | end
154 |
155 | describe 'app/models/admin_user.rb' do
156 | subject { file('app/models/admin_user.rb') }
157 |
158 | it { should contain /class AdminUser < ActiveRecord::Base\n rolify :role_cname => 'AdminRole'\n/ }
159 | end
160 |
161 | describe 'migration file' do
162 | subject { migration_file('db/migrate/rolify_create_admin_roles.rb') }
163 |
164 | it { should be_a_migration }
165 | it { should contain "create_table(:admin_roles)" }
166 | it { should contain "create_table(:admin_users_admin_roles, :id => false) do" }
167 |
168 | context 'mysql2' do
169 | let(:adapter) { 'Mysql2Adapter' }
170 |
171 | it { expect(subject).to contain('add_index(:admin_roles, :name)') }
172 | end
173 |
174 | context 'sqlite3' do
175 | let(:adapter) { 'SQLite3Adapter' }
176 |
177 | it { expect(subject).to contain('add_index(:admin_roles, :name)') }
178 | end
179 |
180 | context 'pg' do
181 | let(:adapter) { 'PostgreSQLAdapter' }
182 |
183 | it { expect(subject).not_to contain('add_index(:admin_roles, :name)') }
184 | end
185 | end
186 | end
187 |
188 | describe 'specifying namespaced User and Role class names' do
189 | before(:all) { arguments %w(Admin::Role Admin::User) }
190 |
191 | before {
192 | allow(ActiveRecord::Base).to receive_message_chain(
193 | 'connection.class.to_s.demodulize') { adapter }
194 | capture(:stdout) {
195 | generator.create_file "app/models/admin/user.rb" do
196 | <<-RUBY
197 | module Admin
198 | class User < ActiveRecord::Base
199 | self.table_name_prefix = 'admin_'
200 | end
201 | end
202 | RUBY
203 | end
204 | }
205 | require File.join(destination_root, "app/models/admin/user.rb")
206 | run_generator
207 | }
208 |
209 | describe 'config/initializers/rolify.rb' do
210 | subject { file('config/initializers/rolify.rb') }
211 |
212 | it { should exist }
213 | it { should contain "Rolify.configure(\"Admin::Role\") do |config|"}
214 | it { should contain "# config.use_dynamic_shortcuts" }
215 | it { should contain "# config.use_mongoid" }
216 | end
217 |
218 | describe 'app/models/admin/role.rb' do
219 | subject { file('app/models/admin/role.rb') }
220 |
221 | it { should exist }
222 | it do
223 | if Rails::VERSION::MAJOR < 5
224 | should contain "class Admin::Role < ActiveRecord::Base"
225 | else
226 | should contain "class Admin::Role < ApplicationRecord"
227 | end
228 | end
229 | it { should contain "has_and_belongs_to_many :admin_users, :join_table => :admin_users_admin_roles" }
230 | it { should contain "belongs_to :resource,\n"
231 | " :polymorphic => true,\n"
232 | " :optional => true"
233 | }
234 | end
235 |
236 | describe 'app/models/admin/user.rb' do
237 | subject { file('app/models/admin/user.rb') }
238 |
239 | it { should contain /class User < ActiveRecord::Base\n rolify :role_cname => 'Admin::Role'\n/ }
240 | end
241 |
242 | describe 'migration file' do
243 | subject { migration_file('db/migrate/rolify_create_admin_roles.rb') }
244 |
245 | it { should be_a_migration }
246 | it { should contain "create_table(:admin_roles)" }
247 | it { should contain "create_table(:admin_users_admin_roles, :id => false) do" }
248 | it do
249 | if Rails::VERSION::MAJOR < 5
250 | should contain "< ActiveRecord::Migration"
251 | else
252 | should contain "< ActiveRecord::Migration[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
253 | end
254 | end
255 |
256 | context 'mysql2' do
257 | let(:adapter) { 'Mysql2Adapter' }
258 |
259 | it { expect(subject).to contain('add_index(:admin_roles, :name)') }
260 | end
261 |
262 | context 'sqlite3' do
263 | let(:adapter) { 'SQLite3Adapter' }
264 |
265 | it { expect(subject).to contain('add_index(:admin_roles, :name)') }
266 | end
267 |
268 | context 'pg' do
269 | let(:adapter) { 'PostgreSQLAdapter' }
270 |
271 | it { expect(subject).not_to contain('add_index(:admin_roles, :name)') }
272 | end
273 | end
274 | end
275 | end
276 |
--------------------------------------------------------------------------------
/spec/generators/rolify/rolify_mongoid_generator_spec.rb:
--------------------------------------------------------------------------------
1 | require 'generators_helper'
2 |
3 | # Generators are not automatically loaded by Rails
4 | require 'generators/rolify/rolify_generator'
5 |
6 | describe Rolify::Generators::RolifyGenerator, :if => ENV['ADAPTER'] == 'mongoid' do
7 | # Tell the generator where to put its output (what it thinks of as Rails.root)
8 | destination File.expand_path("../../../../tmp", __FILE__)
9 | teardown :cleanup_destination_root
10 |
11 | before {
12 | prepare_destination
13 | }
14 |
15 | def cleanup_destination_root
16 | FileUtils.rm_rf destination_root
17 | end
18 |
19 | describe 'specifying ORM adapter' do
20 | before(:all) { arguments [ "Role", "User", "--orm=mongoid" ] }
21 |
22 | before {
23 | capture(:stdout) {
24 | generator.create_file "app/models/user.rb" do
25 | <<-RUBY
26 | class User
27 | include Mongoid::Document
28 |
29 | field :login, :type => String
30 | end
31 | RUBY
32 | end
33 | }
34 | require File.join(destination_root, "app/models/user.rb")
35 | run_generator
36 | }
37 |
38 | describe 'config/initializers/rolify.rb' do
39 | subject { file('config/initializers/rolify.rb') }
40 | it { should exist }
41 | it { should contain "Rolify.configure do |config|"}
42 | it { should_not contain "# config.use_mongoid" }
43 | it { should contain "# config.use_dynamic_shortcuts" }
44 | end
45 |
46 | describe 'app/models/role.rb' do
47 | subject { file('app/models/role.rb') }
48 | it { should exist }
49 | it { should contain "class Role\n" }
50 | it { should contain "has_and_belongs_to_many :users\n" }
51 | it { should contain "belongs_to :resource, :polymorphic => true" }
52 | it { should contain "field :name, :type => String" }
53 | it { should contain " index({\n"
54 | " { :name => 1 },\n"
55 | " { :resource_type => 1 },\n"
56 | " { :resource_id => 1 }\n"
57 | " },\n"
58 | " { unique => true })"}
59 | it { should contain "validates :resource_type,\n"
60 | " :inclusion => { :in => Rolify.resource_types },\n"
61 | " :allow_nil => true" }
62 | end
63 |
64 | describe 'app/models/user.rb' do
65 | subject { file('app/models/user.rb') }
66 | it { should contain /class User\n include Mongoid::Document\n rolify\n/ }
67 | end
68 | end
69 |
70 | describe 'specifying namespaced User and Role class names and ORM adapter' do
71 | before(:all) { arguments %w(Admin::Role Admin::User --orm=mongoid) }
72 |
73 | before {
74 | capture(:stdout) {
75 | generator.create_file "app/models/admin/user.rb" do
76 | <<-RUBY
77 | module Admin
78 | class User
79 | include Mongoid::Document
80 | end
81 | end
82 | RUBY
83 | end
84 | }
85 | require File.join(destination_root, "app/models/admin/user.rb")
86 | run_generator
87 | }
88 |
89 | describe 'config/initializers/rolify.rb' do
90 | subject { file('config/initializers/rolify.rb') }
91 |
92 | it { should exist }
93 | it { should contain "Rolify.configure(\"Admin::Role\") do |config|"}
94 | it { should contain "# config.use_dynamic_shortcuts" }
95 | it { should_not contain "# config.use_mongoid" }
96 | end
97 |
98 | describe 'app/models/admin/role.rb' do
99 | subject { file('app/models/admin/role.rb') }
100 |
101 | it { should exist }
102 | it { should contain "class Admin::Role" }
103 | it { should contain "has_and_belongs_to_many :admin_users" }
104 | it { should contain "belongs_to :resource, :polymorphic => true" }
105 | end
106 |
107 | describe 'app/models/admin/user.rb' do
108 | subject { file('app/models/admin/user.rb') }
109 |
110 | it { should contain /class User\n include Mongoid::Document\n rolify :role_cname => 'Admin::Role'\n/ }
111 | end
112 | end
113 | end
114 |
--------------------------------------------------------------------------------
/spec/generators_helper.rb:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require "bundler/setup"
3 |
4 | require 'pry'
5 |
6 | require 'rolify'
7 | require 'rolify/matchers'
8 | require 'rails/all'
9 | require_relative 'support/stream_helpers'
10 | include StreamHelpers
11 |
12 | require 'coveralls'
13 | Coveralls.wear_merged!
14 |
15 | require 'common_helper'
16 |
17 | ENV['ADAPTER'] ||= 'active_record'
18 |
19 | if ENV['ADAPTER'] == 'active_record'
20 | load File.dirname(__FILE__) + '/support/adapters/utils/active_record.rb'
21 | require 'active_record/railtie'
22 | establish_connection
23 | else
24 | load File.dirname(__FILE__) + '/support/adapters/utils/mongoid.rb'
25 | load_mongoid_config
26 | end
27 |
28 | module TestApp
29 | class Application < ::Rails::Application
30 | config.root = File.dirname(__FILE__)
31 | end
32 | end
33 |
34 | require 'ammeter/init'
35 |
--------------------------------------------------------------------------------
/spec/rolify/config_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper"
2 |
3 | if ENV['ADAPTER'] == 'active_record'
4 | class ARUser < ActiveRecord::Base
5 | extend Rolify
6 | end
7 | else
8 | class MUser
9 | include Mongoid::Document
10 | extend Rolify
11 | end
12 | end
13 |
14 | describe Rolify do
15 | before do
16 | Rolify.use_defaults
17 | end
18 |
19 | describe :dynamic_shortcuts do
20 | context "using defaults values" do
21 | subject { Rolify.dynamic_shortcuts }
22 |
23 | it { should be_falsey }
24 | end
25 |
26 | context "using custom values" do
27 | before do
28 | Rolify.dynamic_shortcuts = true
29 | end
30 |
31 | subject { Rolify.dynamic_shortcuts }
32 |
33 | it { should be_truthy }
34 | end
35 | end
36 |
37 | describe :orm do
38 | context "using defaults values", :if => ENV['ADAPTER'] == 'active_record' do
39 | subject { Rolify.orm }
40 |
41 | it { should eq("active_record") }
42 |
43 | context "on the User class" do
44 | before do
45 | subject.rolify
46 | end
47 |
48 | subject { ARUser }
49 |
50 | its("adapter.class") { should be(Rolify::Adapter::RoleAdapter) }
51 | end
52 |
53 | context "on the Forum class" do
54 | before do
55 | subject.resourcify
56 | end
57 |
58 | subject { Forum }
59 |
60 | its("resource_adapter.class") { should be(Rolify::Adapter::ResourceAdapter) }
61 | end
62 | end
63 |
64 | context "using custom values", :if => ENV['ADAPTER'] == 'mongoid' do
65 | context "using :orm setter method" do
66 | before do
67 | Rolify.orm = "mongoid"
68 | end
69 |
70 | subject { Rolify.orm }
71 |
72 | it { should eq("mongoid") }
73 |
74 | context "on the User class" do
75 | before do
76 | MUser.rolify
77 | end
78 |
79 | subject { MUser }
80 |
81 | its("adapter.class") { should be(Rolify::Adapter::RoleAdapter) }
82 | end
83 |
84 | context "on the Forum class" do
85 | before do
86 | Forum.resourcify
87 | end
88 |
89 | subject { Forum }
90 |
91 | its("resource_adapter.class") { should be(Rolify::Adapter::ResourceAdapter) }
92 | end
93 | end
94 |
95 | context "using :use_mongoid method" do
96 | before do
97 | Rolify.use_mongoid
98 | end
99 |
100 | subject { Rolify.orm }
101 |
102 | it { should eq("mongoid") }
103 |
104 | context "on the User class" do
105 | before do
106 | MUser.rolify
107 | end
108 |
109 | subject { MUser }
110 |
111 | its("adapter.class") { should be(Rolify::Adapter::RoleAdapter) }
112 | end
113 |
114 | context "on the Forum class" do
115 | before do
116 | Forum.resourcify
117 | end
118 |
119 | subject { Forum }
120 |
121 | its("resource_adapter.class") { should be(Rolify::Adapter::ResourceAdapter) }
122 | end
123 | end
124 | end
125 |
126 | describe :dynamic_shortcuts do
127 | context "using defaults values" do
128 | subject { Rolify.dynamic_shortcuts }
129 |
130 | it { should be_falsey }
131 | end
132 |
133 | context "using custom values" do
134 | context "using :dynamic_shortcuts setter method" do
135 | before do
136 | Rolify.dynamic_shortcuts = true
137 | end
138 |
139 | subject { Rolify.dynamic_shortcuts }
140 |
141 | it { should be_truthy }
142 | end
143 |
144 | context "using :use_dynamic_shortcuts method" do
145 | before do
146 | Rolify.use_dynamic_shortcuts
147 | end
148 |
149 | subject { Rolify.dynamic_shortcuts }
150 |
151 | it { should be_truthy }
152 | end
153 | end
154 | end
155 | end
156 |
157 | describe :configure do
158 | before do
159 | Rolify.configure do |config|
160 | config.dynamic_shortcuts = true
161 | config.orm = "mongoid"
162 | end
163 | end
164 |
165 | subject { Rolify }
166 |
167 | its(:dynamic_shortcuts) { should be_truthy }
168 | its(:orm) { should eq("mongoid") }
169 |
170 | context "on the User class", :if => ENV['ADAPTER'] == 'mongoid' do
171 | before do
172 | MUser.rolify
173 | end
174 |
175 | subject { MUser }
176 |
177 | it { should satisfy { |u| u.include? Rolify::Role }}
178 | it { should satisfy { |u| u.singleton_class.include? Rolify::Dynamic } }
179 | its("adapter.class") { should be(Rolify::Adapter::RoleAdapter) }
180 | end
181 |
182 | context "on the Forum class" do
183 | before do
184 | Forum.resourcify
185 | end
186 |
187 | subject { Forum }
188 | it { should satisfy { |u| u.include? Rolify::Resource }}
189 | its("resource_adapter.class") { should be(Rolify::Adapter::ResourceAdapter) }
190 | end
191 | end
192 | end
--------------------------------------------------------------------------------
/spec/rolify/coverage/.last_run.json:
--------------------------------------------------------------------------------
1 | {
2 | "result": {
3 | "covered_percent": 100.0
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/spec/rolify/coverage/.resultset.json:
--------------------------------------------------------------------------------
1 | {
2 | "RSpec": {
3 | "coverage": {
4 | },
5 | "timestamp": 1427836082
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/spec/rolify/coverage/.resultset.json.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RolifyCommunity/rolify/55261dcc26ae0bbca90a657e9449c65095924465/spec/rolify/coverage/.resultset.json.lock
--------------------------------------------------------------------------------
/spec/rolify/custom_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper"
2 | require "rolify/shared_examples/shared_examples_for_roles"
3 | require "rolify/shared_examples/shared_examples_for_dynamic"
4 | require "rolify/shared_examples/shared_examples_for_scopes"
5 | require "rolify/shared_examples/shared_examples_for_callbacks"
6 |
7 | describe "Using Rolify with custom User and Role class names" do
8 | def user_class
9 | Customer
10 | end
11 |
12 | def role_class
13 | Privilege
14 | end
15 |
16 | it_behaves_like Rolify::Role
17 | it_behaves_like "Role.scopes"
18 | it_behaves_like Rolify::Dynamic
19 | it_behaves_like "Rolify.callbacks"
20 | end
21 |
--------------------------------------------------------------------------------
/spec/rolify/matchers_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe 'have_role', focus: true do
4 | let(:object) { Object.new }
5 |
6 | it 'delegates to has_role?' do
7 | object.should_receive(:has_role?).with(:read, 'Resource') { true }
8 | object.should have_role(:read, 'Resource')
9 | end
10 |
11 | it 'reports a nice failure message for should' do
12 | object.should_receive(:has_role?) { false }
13 | expect{
14 | object.should have_role(:read, 'Resource')
15 | }.to raise_error('expected to have role :read "Resource"')
16 | end
17 |
18 | it 'reports a nice failure message for should_not' do
19 | object.should_receive(:has_role?) { true }
20 | expect{
21 | object.should_not have_role(:read, 'Resource')
22 | }.to raise_error('expected not to have role :read "Resource"')
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/spec/rolify/namespace_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper"
2 | require "rolify/shared_examples/shared_examples_for_roles"
3 | require "rolify/shared_examples/shared_examples_for_dynamic"
4 | require "rolify/shared_examples/shared_examples_for_scopes"
5 | require "rolify/shared_examples/shared_examples_for_callbacks"
6 |
7 | describe "Rolify.namespace" do
8 | def user_class
9 | Admin::Moderator
10 | end
11 |
12 | def role_class
13 | Admin::Right
14 | end
15 |
16 | def join_table
17 | "moderators_rights"
18 | end
19 |
20 | it_behaves_like Rolify::Role
21 | it_behaves_like "Role.scopes"
22 | it_behaves_like Rolify::Dynamic
23 | it_behaves_like "Rolify.callbacks"
24 | end
25 |
--------------------------------------------------------------------------------
/spec/rolify/resource_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper"
2 |
3 | describe Rolify::Resource do
4 | before(:all) do
5 | reset_defaults
6 | silence_warnings { User.rolify }
7 | Forum.resourcify
8 | Group.resourcify
9 | Team.resourcify
10 | Organization.resourcify
11 | Role.destroy_all
12 | end
13 |
14 | # Users
15 | let(:admin) { User.first }
16 | let(:tourist) { User.last }
17 | let(:captain) { User.where(:login => "god").first }
18 |
19 | # roles
20 | let!(:forum_role) { admin.add_role(:forum, Forum.first) }
21 | let!(:godfather_role) { admin.add_role(:godfather, Forum) }
22 | let!(:group_role) { admin.add_role(:group, Group.last) }
23 | let!(:grouper_role) { admin.add_role(:grouper, Group.first) }
24 | let!(:tourist_role) { tourist.add_role(:forum, Forum.last) }
25 | let!(:sneaky_role) { tourist.add_role(:group, Forum.first) }
26 | let!(:captain_role) { captain.add_role(:captain, Team.first) }
27 | let!(:player_role) { captain.add_role(:player, Team.last) }
28 | let!(:company_role) { admin.add_role(:owner, Company.first) }
29 |
30 | describe ".find_multiple_as" do
31 | subject { Group }
32 |
33 | it { should respond_to(:find_roles).with(1).arguments }
34 | it { should respond_to(:find_roles).with(2).arguments }
35 |
36 | context "with a role name as argument" do
37 | context "on the Forum class" do
38 | subject { Forum }
39 |
40 | it "should include Forum instances with forum role" do
41 | subject.find_as(:forum).should =~ [ Forum.first, Forum.last ]
42 | end
43 |
44 | it "should include Forum instances with godfather role" do
45 | subject.find_as(:godfather).should =~ Forum.all
46 | end
47 |
48 | it "should be able to modify the resource", :if => ENV['ADAPTER'] == 'active_record' do
49 | forum_resource = subject.find_as(:forum).first
50 | forum_resource.name = "modified name"
51 | expect { forum_resource.save }.not_to raise_error
52 | end
53 | end
54 |
55 | context "on the Group class" do
56 | subject { Group }
57 |
58 | it "should include Group instances with group role" do
59 | subject.find_as(:group).should =~ [ Group.last ]
60 | end
61 | end
62 |
63 | context "on a Group instance" do
64 | subject { Group.last }
65 |
66 | it "should ignore nil entries" do
67 | subject.subgroups.find_as(:group).should =~ [ ]
68 | end
69 | end
70 | end
71 |
72 | context "with an array of role names as argument" do
73 | context "on the Group class" do
74 | subject { Group }
75 |
76 | it "should include Group instances with both group and grouper roles" do
77 | subject.find_multiple_as([:group, :grouper]).should =~ [ Group.first, Group.last ]
78 | end
79 | end
80 | end
81 |
82 | context "with a role name and a user as arguments" do
83 | context "on the Forum class" do
84 | subject { Forum }
85 |
86 | it "should get all Forum instances binded to the forum role and the admin user" do
87 | subject.find_as(:forum, admin).should =~ [ Forum.first ]
88 | end
89 |
90 | it "should get all Forum instances binded to the forum role and the tourist user" do
91 | subject.find_as(:forum, tourist).should =~ [ Forum.last ]
92 | end
93 |
94 | it "should get all Forum instances binded to the godfather role and the admin user" do
95 | subject.find_as(:godfather, admin).should =~ Forum.all.to_a
96 | end
97 |
98 | it "should get all Forum instances binded to the godfather role and the tourist user" do
99 | subject.find_as(:godfather, tourist).should be_empty
100 | end
101 |
102 | it "should get Forum instances binded to the group role and the tourist user" do
103 | subject.find_as(:group, tourist).should =~ [ Forum.first ]
104 | end
105 |
106 | it "should not get Forum instances not binded to the group role and the tourist user" do
107 | subject.find_as(:group, tourist).should_not include(Forum.last)
108 | end
109 | end
110 |
111 | context "on the Group class" do
112 | subject { Group }
113 |
114 | it "should get all resources binded to the group role and the admin user" do
115 | subject.find_as(:group, admin).should =~ [ Group.last ]
116 | end
117 |
118 | it "should not get resources not binded to the group role and the admin user" do
119 | subject.find_as(:group, admin).should_not include(Group.first)
120 | end
121 | end
122 | end
123 |
124 | context "with an array of role names and a user as arguments" do
125 | context "on the Forum class" do
126 | subject { Forum }
127 |
128 | it "should get Forum instances binded to the forum and group roles and the tourist user" do
129 | subject.find_multiple_as([:forum, :group], tourist).should =~ [ Forum.first, Forum.last ]
130 | end
131 |
132 | end
133 |
134 | context "on the Group class" do
135 | subject { Group }
136 |
137 | it "should get Group instances binded to the group and grouper roles and the admin user" do
138 | subject.find_multiple_as([:group, :grouper], admin).should =~ [ Group.first, Group.last ]
139 | end
140 |
141 | end
142 | end
143 |
144 | context "with a model not having ID column" do
145 | subject { Team }
146 |
147 | it "should find Team instance using team_code column" do
148 | subject.find_multiple_as([:captain, :player], captain).should =~ [ Team.first, Team.last ]
149 | end
150 | end
151 |
152 | context "with a resource using STI" do
153 | subject { Organization }
154 | it "should find instances of children classes" do
155 | subject.find_multiple_as(:owner, admin).should =~ [ Company.first ]
156 | end
157 | end
158 | end
159 |
160 |
161 | describe ".except_multiple_as" do
162 | subject { Group }
163 |
164 | it { should respond_to(:find_roles).with(1).arguments }
165 | it { should respond_to(:find_roles).with(2).arguments }
166 |
167 | context "with a role name as argument" do
168 | context "on the Forum class" do
169 | subject { Forum }
170 |
171 | it "should not include Forum instances with forum role" do
172 | subject.except_as(:forum).should_not =~ [ Forum.first, Forum.last ]
173 | end
174 |
175 | it "should not include Forum instances with godfather role" do
176 | subject.except_as(:godfather).should be_empty
177 | end
178 |
179 | it "should be able to modify the resource", :if => ENV['ADAPTER'] == 'active_record' do
180 | forum_resource = subject.except_as(:forum).first
181 | forum_resource.name = "modified name"
182 | expect { forum_resource.save }.not_to raise_error
183 | end
184 | end
185 |
186 | context "on the Group class" do
187 | subject { Group }
188 |
189 | it "should not include Group instances with group role" do
190 | subject.except_as(:group).should_not =~ [ Group.last ]
191 | end
192 | end
193 |
194 | end
195 |
196 | context "with an array of role names as argument" do
197 | context "on the Group class" do
198 | subject { Group }
199 |
200 | it "should include Group instances without either the group and grouper roles" do
201 | subject.except_multiple_as([:group, :grouper]).should_not =~ [ Group.first, Group.last ]
202 | end
203 | end
204 | end
205 |
206 | context "with a role name and a user as arguments" do
207 | context "on the Forum class" do
208 | subject { Forum }
209 |
210 | it "should get all Forum instances the admin user does not have the forum role" do
211 | subject.except_as(:forum, admin).should_not =~ [ Forum.first ]
212 | end
213 |
214 | it "should get all Forum instances the tourist user does not have the forum role" do
215 | subject.except_as(:forum, tourist).should_not =~ [ Forum.last ]
216 | end
217 |
218 | it "should get all Forum instances the admin user does not have the godfather role" do
219 | subject.except_as(:godfather, admin).should_not =~ Forum.all
220 | end
221 |
222 | it "should get all Forum instances tourist user does not have the godfather role" do
223 | subject.except_as(:godfather, tourist).should =~ Forum.all
224 | end
225 |
226 | it "should get Forum instances the tourist user does not have the group role" do
227 | subject.except_as(:group, tourist).should_not =~ [ Forum.first ]
228 | end
229 |
230 | it "should get Forum instances the tourist user does not have the group role" do
231 | subject.except_as(:group, tourist).should_not =~ [ Forum.first ]
232 | end
233 | end
234 |
235 | context "on the Group class" do
236 | subject { Group }
237 |
238 | it "should get all resources not bounded to the group role and the admin user" do
239 | subject.except_as(:group, admin).should =~ [ Group.first ]
240 | end
241 |
242 | it "should not get resources bound to the group role and the admin user" do
243 | subject.except_as(:group, admin).should include(Group.first)
244 | end
245 | end
246 | end
247 |
248 | context "with an array of role names and a user as arguments" do
249 | context "on the Forum class" do
250 | subject { Forum }
251 |
252 | it "should get Forum instances not bound to the forum and group roles and the tourist user" do
253 | subject.except_multiple_as([:forum, :group], tourist).should_not =~ [ Forum.first, Forum.last ]
254 | end
255 |
256 | end
257 |
258 | context "on the Group class" do
259 | subject { Group }
260 |
261 | it "should get Group instances binded to the group and grouper roles and the admin user" do
262 | subject.except_multiple_as([:group, :grouper], admin).should =~ [ ]
263 | end
264 |
265 | end
266 | end
267 |
268 | context "with a model not having ID column" do
269 | subject { Team }
270 |
271 | it "should find Team instance not using team_code column" do
272 | subject.except_multiple_as(:captain, captain).should =~ [ Team.last ]
273 | end
274 | end
275 |
276 | context "with a resource using STI" do
277 | subject { Organization }
278 | it "should exclude instances of children classes with matching" do
279 | subject.except_as(:owner, admin).should_not =~ [ Company.first ]
280 | end
281 | end
282 | end
283 |
284 | describe ".find_role" do
285 |
286 | context "without using a role name parameter" do
287 |
288 | context "on the Forum class" do
289 | subject { Forum }
290 |
291 | it "should get all roles binded to a Forum class or instance" do
292 | subject.find_roles.to_a.should =~ [ forum_role, godfather_role, tourist_role, sneaky_role ]
293 | end
294 |
295 | it "should not get roles not binded to a Forum class or instance" do
296 | subject.find_roles.should_not include(group_role)
297 | end
298 |
299 | context "using :any parameter" do
300 | it "should get all roles binded to any Forum class or instance" do
301 | subject.find_roles(:any, :any).to_a.should =~ [ forum_role, godfather_role, tourist_role, sneaky_role ]
302 | end
303 |
304 | it "should not get roles not binded to a Forum class or instance" do
305 | subject.find_roles(:any, :any).should_not include(group_role)
306 | end
307 | end
308 | end
309 |
310 | context "on the Group class" do
311 | subject { Group }
312 |
313 | it "should get all roles binded to a Group class or instance" do
314 | subject.find_roles.to_a.should =~ [ group_role, grouper_role ]
315 | end
316 |
317 | it "should not get roles not binded to a Group class or instance" do
318 | subject.find_roles.should_not include(forum_role, godfather_role, tourist_role, sneaky_role)
319 | end
320 |
321 | context "using :any parameter" do
322 | it "should get all roles binded to Group class or instance" do
323 | subject.find_roles(:any, :any).to_a.should =~ [ group_role, grouper_role ]
324 | end
325 |
326 | it "should not get roles not binded to a Group class or instance" do
327 | subject.find_roles(:any, :any).should_not include(forum_role, godfather_role, tourist_role, sneaky_role)
328 | end
329 | end
330 | end
331 | end
332 |
333 | context "using a role name parameter" do
334 | context "on the Forum class" do
335 | subject { Forum }
336 |
337 | context "without using a user parameter" do
338 | it "should get all roles binded to a Forum class or instance and forum role name" do
339 | subject.find_roles(:forum).should include(forum_role, tourist_role)
340 | end
341 |
342 | it "should not get roles not binded to a Forum class or instance and forum role name" do
343 | subject.find_roles(:forum).should_not include(godfather_role, sneaky_role, group_role)
344 | end
345 | end
346 |
347 | context "using a user parameter" do
348 | it "should get all roles binded to any resource" do
349 | subject.find_roles(:forum, admin).to_a.should =~ [ forum_role ]
350 | end
351 |
352 | it "should not get roles not binded to the admin user and forum role name" do
353 | subject.find_roles(:forum, admin).should_not include(godfather_role, tourist_role, sneaky_role, group_role)
354 | end
355 | end
356 |
357 | context "using :any parameter" do
358 | it "should get all roles binded to any resource with forum role name" do
359 | subject.find_roles(:forum, :any).should include(forum_role, tourist_role)
360 | end
361 |
362 | it "should not get roles not binded to a resource with forum role name" do
363 | subject.find_roles(:forum, :any).should_not include(godfather_role, sneaky_role, group_role)
364 | end
365 | end
366 | end
367 |
368 | context "on the Group class" do
369 | subject { Group }
370 |
371 | context "without using a user parameter" do
372 | it "should get all roles binded to a Group class or instance and group role name" do
373 | subject.find_roles(:group).should include(group_role)
374 | end
375 |
376 | it "should not get roles not binded to a Forum class or instance and forum role name" do
377 | subject.find_roles(:group).should_not include(tourist_role, godfather_role, sneaky_role, forum_role)
378 | end
379 | end
380 |
381 | context "using a user parameter" do
382 | it "should get all roles binded to any resource" do
383 | subject.find_roles(:group, admin).should include(group_role)
384 | end
385 |
386 | it "should not get roles not binded to the admin user and forum role name" do
387 | subject.find_roles(:group, admin).should_not include(godfather_role, tourist_role, sneaky_role, forum_role)
388 | end
389 | end
390 |
391 | context "using :any parameter" do
392 | it "should get all roles binded to any resource with forum role name" do
393 | subject.find_roles(:group, :any).should include(group_role)
394 | end
395 |
396 | it "should not get roles not binded to a resource with forum role name" do
397 | subject.find_roles(:group, :any).should_not include(godfather_role, sneaky_role, forum_role, tourist_role)
398 | end
399 | end
400 | end
401 | end
402 |
403 | context "using :any as role name parameter" do
404 | context "on the Forum class" do
405 | subject { Forum }
406 |
407 | context "without using a user parameter" do
408 | it "should get all roles binded to a Forum class or instance" do
409 | subject.find_roles(:any).should include(forum_role, godfather_role, tourist_role, sneaky_role)
410 | end
411 |
412 | it "should not get roles not binded to a Forum class or instance" do
413 | subject.find_roles(:any).should_not include(group_role)
414 | end
415 | end
416 |
417 | context "using a user parameter" do
418 | it "should get all roles binded to a Forum class or instance and admin user" do
419 | subject.find_roles(:any, admin).should include(forum_role, godfather_role)
420 | end
421 |
422 | it "should not get roles not binded to the admin user and Forum class or instance" do
423 | subject.find_roles(:any, admin).should_not include(tourist_role, sneaky_role, group_role)
424 | end
425 | end
426 |
427 | context "using :any as user parameter" do
428 | it "should get all roles binded to a Forum class or instance" do
429 | subject.find_roles(:any, :any).should include(forum_role, godfather_role, tourist_role, sneaky_role)
430 | end
431 |
432 | it "should not get roles not binded to a Forum class or instance" do
433 | subject.find_roles(:any, :any).should_not include(group_role)
434 | end
435 | end
436 | end
437 |
438 | context "on the Group class" do
439 | subject { Group }
440 |
441 | context "without using a user parameter" do
442 | it "should get all roles binded to a Group class or instance" do
443 | subject.find_roles(:any).should include(group_role)
444 | end
445 |
446 | it "should not get roles not binded to a Group class or instance" do
447 | subject.find_roles(:any).should_not include(forum_role, godfather_role, tourist_role, sneaky_role)
448 | end
449 | end
450 |
451 | context "using a user parameter" do
452 | it "should get all roles binded to a Group class or instance and admin user" do
453 | subject.find_roles(:any, admin).should include(group_role)
454 | end
455 |
456 | it "should not get roles not binded to the admin user and Group class or instance" do
457 | subject.find_roles(:any, admin).should_not include(forum_role, godfather_role, tourist_role, sneaky_role)
458 | end
459 | end
460 |
461 | context "using :any as user parameter" do
462 | it "should get all roles binded to a Group class or instance" do
463 | subject.find_roles(:any, :any).should include(group_role)
464 | end
465 |
466 | it "should not get roles not binded to a Group class or instance" do
467 | subject.find_roles(:any, :any).should_not include(forum_role, godfather_role, tourist_role, sneaky_role)
468 | end
469 | end
470 | end
471 | end
472 |
473 | context "with a resource using STI" do
474 | subject{ Organization }
475 | it "should find instances of children classes" do
476 | subject.find_roles(:owner, admin).should =~ [company_role]
477 | end
478 | end
479 | end
480 |
481 | describe "#roles" do
482 | before(:all) { Role.destroy_all }
483 | subject { Forum.first }
484 |
485 | it { should respond_to :roles }
486 |
487 | context "on a Forum instance" do
488 | its(:roles) { should match_array( [ forum_role, sneaky_role ]) }
489 | its(:roles) { should_not include(group_role, godfather_role, tourist_role) }
490 | end
491 |
492 | context "on a Group instance" do
493 | subject { Group.last }
494 |
495 | its(:roles) { should eq([ group_role ]) }
496 | its(:roles) { should_not include(forum_role, godfather_role, sneaky_role, tourist_role) }
497 |
498 | context "when deleting a Group instance" do
499 | subject do
500 | Group.create(:name => "to delete")
501 | end
502 |
503 | before do
504 | subject.roles.create :name => "group_role1"
505 | subject.roles.create :name => "group_role2"
506 | end
507 |
508 | it "should remove the roles binded to this instance" do
509 | expect { subject.destroy }.to change { Role.count }.by(-2)
510 | end
511 | end
512 | end
513 | end
514 |
515 | describe "#applied_roles" do
516 | context "on a Forum instance" do
517 | subject { Forum.first }
518 |
519 | its(:applied_roles) { should =~ [ forum_role, godfather_role, sneaky_role ] }
520 | its(:applied_roles) { should_not include(group_role, tourist_role) }
521 | end
522 |
523 | context "on a Group instance" do
524 | subject { Group.last }
525 |
526 | its(:applied_roles) { should =~ [ group_role ] }
527 | its(:applied_roles) { should_not include(forum_role, godfather_role, sneaky_role, tourist_role) }
528 | end
529 | end
530 |
531 |
532 | describe '.resource_types' do
533 |
534 | it 'include all models that call resourcify' do
535 | Rolify.resource_types.should include("HumanResource", "Forum", "Group",
536 | "Team", "Organization")
537 | end
538 | end
539 |
540 |
541 | describe "#strict" do
542 | context "strict user" do
543 | before(:all) do
544 | @strict_user = StrictUser.first
545 | @strict_user.role_ids
546 | @strict_user.add_role(:forum, Forum.first)
547 | @strict_user.add_role(:forum, Forum)
548 | end
549 |
550 | it "should return only strict forum" do
551 | @strict_user.has_role?(:forum, Forum.first).should be true
552 | @strict_user.has_cached_role?(:forum, Forum.first).should be true
553 | end
554 |
555 | it "should return false on strict another forum" do
556 | @strict_user.has_role?(:forum, Forum.last).should be false
557 | @strict_user.has_cached_role?(:forum, Forum.last).should be false
558 | end
559 |
560 | it "should return true if user has role on Forum model" do
561 | @strict_user.has_role?(:forum, Forum).should be true
562 | @strict_user.has_cached_role?(:forum, Forum).should be true
563 | end
564 |
565 | it "should return true if user has role any forum name" do
566 | @strict_user.has_role?(:forum, :any).should be true
567 | @strict_user.has_cached_role?(:forum, :any).should be true
568 | end
569 |
570 | it "should return false when deleted role on Forum model" do
571 | @strict_user.remove_role(:forum, Forum)
572 | @strict_user.has_role?(:forum, Forum).should be false
573 | @strict_user.has_cached_role?(:forum, Forum).should be false
574 | end
575 | end
576 | end
577 | end
578 |
--------------------------------------------------------------------------------
/spec/rolify/resourcifed_and_rolifed_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper"
2 |
3 | describe "Resourcify and rolify on the same model" do
4 |
5 | before(:all) do
6 | reset_defaults
7 | Role.delete_all
8 | HumanResource.delete_all
9 | end
10 |
11 | let!(:user) do
12 | user = HumanResource.new login: 'Samer'
13 | user.save
14 | user
15 | end
16 |
17 | it "should add the role to the user" do
18 | expect { user.add_role :admin }.to change { user.roles.count }.by(1)
19 | end
20 |
21 | it "should create a role to the roles collection" do
22 | expect { user.add_role :moderator }.to change { Role.count }.by(1)
23 | end
24 | end
--------------------------------------------------------------------------------
/spec/rolify/role_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper"
2 |
3 | describe Rolify do
4 |
5 | context 'cache' do
6 | let(:user) { User.first }
7 | before { user.grant(:zombie) }
8 | specify do
9 | expect(user).to have_role(:zombie)
10 | user.remove_role(:zombie)
11 | expect(user).to_not have_role(:zombie)
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/rolify/shared_contexts.rb:
--------------------------------------------------------------------------------
1 | shared_context "global role", :scope => :global do
2 | subject { admin }
3 |
4 | def admin
5 | user_class.first
6 | end
7 |
8 | before(:all) do
9 | load_roles
10 | create_other_roles
11 | end
12 |
13 | def load_roles
14 | role_class.destroy_all
15 | admin.roles = []
16 | admin.add_role :admin
17 | admin.add_role :staff
18 | admin.add_role :manager, Group
19 | admin.add_role :player, Forum
20 | admin.add_role :moderator, Forum.last
21 | admin.add_role :moderator, Group.last
22 | admin.add_role :anonymous, Forum.first
23 | end
24 | end
25 |
26 | shared_context "class scoped role", :scope => :class do
27 | subject { manager }
28 |
29 | before(:all) do
30 | load_roles
31 | create_other_roles
32 | end
33 |
34 | def manager
35 | user_class.where(:login => "moderator").first
36 | end
37 |
38 | def load_roles
39 | role_class.destroy_all
40 | manager.roles = []
41 | manager.add_role :manager, Forum
42 | manager.add_role :player, Forum
43 | manager.add_role :warrior
44 | manager.add_role :moderator, Forum.last
45 | manager.add_role :moderator, Group.last
46 | manager.add_role :anonymous, Forum.first
47 | end
48 | end
49 |
50 | shared_context "instance scoped role", :scope => :instance do
51 | subject { moderator }
52 |
53 | before(:all) do
54 | load_roles
55 | create_other_roles
56 | end
57 |
58 | def moderator
59 | user_class.where(:login => "god").first
60 | end
61 |
62 | def load_roles
63 | role_class.destroy_all
64 | moderator.roles = []
65 | moderator.add_role :moderator, Forum.first
66 | moderator.add_role :anonymous, Forum.last
67 | moderator.add_role :visitor, Forum
68 | moderator.add_role :soldier
69 | end
70 | end
71 |
72 | shared_context "mixed scoped roles", :scope => :mixed do
73 | subject { user_class }
74 |
75 | before(:all) do
76 | role_class.destroy_all
77 | end
78 |
79 | let!(:root) { provision_user(user_class.first, [ :admin, :staff, [ :moderator, Group ], [ :visitor, Forum.last ] ]) }
80 | let!(:modo) { provision_user(user_class.where(:login => "moderator").first, [[ :moderator, Forum ], [ :manager, Group ], [ :visitor, Group.first ]])}
81 | let!(:visitor) { provision_user(user_class.last, [[ :visitor, Forum.last ]]) }
82 | let!(:owner) { provision_user(user_class.first, [[:owner, Company.first]]) }
83 | end
84 |
85 | def create_other_roles
86 | role_class.create :name => "superhero"
87 | role_class.create :name => "admin", :resource_type => "Group"
88 | role_class.create :name => "admin", :resource => Forum.first
89 | role_class.create :name => "VIP", :resource_type => "Forum"
90 | role_class.create :name => "manager", :resource => Forum.last
91 | role_class.create :name => "roomate", :resource => Forum.first
92 | role_class.create :name => "moderator", :resource => Group.first
93 | end
--------------------------------------------------------------------------------
/spec/rolify/shared_examples/shared_examples_for_add_role.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for "#add_role_examples" do |param_name, param_method|
2 | context "using #{param_name} as parameter" do
3 | context "with a global role", :scope => :global do
4 | it "should add the role to the user" do
5 | expect { subject.add_role "root".send(param_method) }.to change { subject.roles.count }.by(1)
6 | end
7 |
8 | it "should create a role to the roles table" do
9 | expect { subject.add_role "moderator".send(param_method) }.to change { role_class.count }.by(1)
10 | end
11 |
12 | context "considering a new global role" do
13 | it "creates a new class scoped role" do
14 | expect(subject.add_role "expert".send(param_method)).to be_the_same_role("expert")
15 | end
16 | end
17 |
18 | context "should not create another role" do
19 | it "if the role was already assigned to the user" do
20 | subject.add_role "manager".send(param_method)
21 | expect { subject.add_role "manager".send(param_method) }.not_to change { subject.roles.size }
22 | end
23 |
24 | it "if the role already exists in the db" do
25 | role_class.create :name => "god"
26 | expect { subject.add_role "god".send(param_method) }.not_to change { role_class.count }
27 | end
28 | end
29 | end
30 |
31 | context "with a class scoped role", :scope => :class do
32 | it "should add the role to the user" do
33 | expect { subject.add_role "supervisor".send(param_method), Forum }.to change { subject.roles.count }.by(1)
34 | end
35 |
36 | it "should create a role in the roles table" do
37 | expect { subject.add_role "moderator".send(param_method), Forum }.to change { role_class.count }.by(1)
38 | end
39 |
40 | context "considering a new class scoped role" do
41 | it "creates a new class scoped role" do
42 | expect(subject.add_role "boss".send(param_method), Forum).to be_the_same_role("boss", Forum)
43 | end
44 | end
45 |
46 | context "should not create another role" do
47 | it "if the role was already assigned to the user" do
48 | subject.add_role "warrior".send(param_method), Forum
49 | expect { subject.add_role "warrior".send(param_method), Forum }.not_to change { subject.roles.count }
50 | end
51 |
52 | it "if already existing in the database" do
53 | role_class.create :name => "hacker", :resource_type => "Forum"
54 | expect { subject.add_role "hacker".send(param_method), Forum }.not_to change { role_class.count }
55 | end
56 | end
57 | end
58 |
59 | context "with an instance scoped role", :scope => :instance do
60 | it "should add the role to the user" do
61 | expect { subject.add_role "visitor".send(param_method), Forum.last }.to change { subject.roles.count }.by(1)
62 | end
63 |
64 | it "should create a role in the roles table" do
65 | expect { subject.add_role "member".send(param_method), Forum.last }.to change { role_class.count }.by(1)
66 | end
67 |
68 | it "creates a new instance scoped role" do
69 | expect(subject.add_role "mate".send(param_method), Forum.last).to be_the_same_role("mate", Forum.last)
70 | end
71 |
72 | context "should not create another role" do
73 | it "if the role was already assigned to the user" do
74 | subject.add_role "anonymous".send(param_method), Forum.first
75 | expect { subject.add_role "anonymous".send(param_method), Forum.first }.not_to change { subject.roles.size }
76 | end
77 |
78 | it "if already existing in the database" do
79 | role_class.create :name => "ghost", :resource_type => "Forum", :resource_id => Forum.first.id
80 | expect { subject.add_role "ghost".send(param_method), Forum.first }.not_to change { role_class.count }
81 | end
82 | end
83 | end
84 | end
85 | end
--------------------------------------------------------------------------------
/spec/rolify/shared_examples/shared_examples_for_callbacks.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for "Rolify.callbacks" do
2 | before(:all) do
3 | reset_defaults
4 | Rolify.dynamic_shortcuts = false
5 | role_class.destroy_all
6 | end
7 |
8 | after :each do
9 | @user.roles.destroy_all
10 | end
11 |
12 | describe "rolify association callbacks", :if => (Rolify.orm == "active_record") do
13 | describe "before_add" do
14 | it "should receive callback" do
15 | rolify_options = { :role_cname => role_class.to_s, :before_add => :role_callback }
16 | rolify_options[:role_join_table_name] = join_table if defined? join_table
17 | silence_warnings { user_class.rolify rolify_options }
18 | @user = user_class.first
19 | @user.stub(:role_callback)
20 | @user.should_receive(:role_callback)
21 | @user.add_role :admin
22 | end
23 | end
24 |
25 | describe "after_add" do
26 | it "should receive callback" do
27 | rolify_options = { :role_cname => role_class.to_s, :after_add => :role_callback }
28 | rolify_options[:role_join_table_name] = join_table if defined? join_table
29 | silence_warnings { user_class.rolify rolify_options }
30 | @user = user_class.first
31 | @user.stub(:role_callback)
32 | @user.should_receive(:role_callback)
33 | @user.add_role :admin
34 | end
35 | end
36 |
37 | describe "before_remove" do
38 | it "should receive callback" do
39 | rolify_options = { :role_cname => role_class.to_s, :before_remove => :role_callback }
40 | rolify_options[:role_join_table_name] = join_table if defined? join_table
41 | silence_warnings { user_class.rolify rolify_options }
42 | @user = user_class.first
43 | @user.add_role :admin
44 | @user.stub(:role_callback)
45 |
46 | @user.should_receive(:role_callback)
47 | @user.remove_role :admin
48 | end
49 | end
50 |
51 | describe "after_remove" do
52 | it "should receive callback" do
53 | rolify_options = { :role_cname => role_class.to_s, :after_remove => :role_callback }
54 | rolify_options[:role_join_table_name] = join_table if defined? join_table
55 | silence_warnings { user_class.rolify rolify_options }
56 | @user = user_class.first
57 | @user.add_role :admin
58 | @user.stub(:role_callback)
59 |
60 | @user.should_receive(:role_callback)
61 | @user.remove_role :admin
62 | end
63 | end
64 | end
65 | end
66 |
--------------------------------------------------------------------------------
/spec/rolify/shared_examples/shared_examples_for_dynamic.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for Rolify::Dynamic do
2 | before(:all) do
3 | Rolify.dynamic_shortcuts = true
4 | role_class.destroy_all
5 | rolify_options = { :role_cname => role_class.to_s }
6 | rolify_options[:role_join_table_name] = join_table if defined? join_table
7 | silence_warnings { user_class.rolify rolify_options }
8 | Forum.resourcify :roles, :role_cname => role_class.to_s
9 | Group.resourcify :roles, :role_cname => role_class.to_s
10 | end
11 |
12 | context "using a global role" do
13 | subject do
14 | admin = user_class.first
15 | admin.add_role :admin
16 | admin.add_role :moderator, Forum.first
17 | admin.add_role :solo
18 | admin
19 | end
20 |
21 | it { should respond_to(:is_admin?).with(0).arguments }
22 | it { should respond_to(:is_moderator_of?).with(1).arguments }
23 | it { should_not respond_to(:is_god?) }
24 |
25 | it { subject.is_admin?.should be(true) }
26 | it { subject.is_admin?.should be(true) }
27 | it { subject.is_admin?.should be(true) }
28 |
29 | context "removing the role on the last user having it" do
30 | before do
31 | subject.remove_role :solo
32 | end
33 |
34 | it { should_not respond_to(:is_solo?) }
35 | it { subject.is_solo?.should be(false) }
36 | end
37 | end
38 |
39 | context "using a resource scoped role" do
40 | subject do
41 | moderator = user_class.where(:login => "moderator").first
42 | moderator.add_role :moderator, Forum.first
43 | moderator.add_role :sole_mio, Forum.last
44 | moderator
45 | end
46 |
47 | it { should respond_to(:is_moderator?).with(0).arguments }
48 | it { should respond_to(:is_moderator_of?).with(1).arguments }
49 | it { should_not respond_to(:is_god?) }
50 | it { should_not respond_to(:is_god_of?) }
51 |
52 | it { subject.is_moderator?.should be(false) }
53 | it { subject.is_moderator_of?(Forum).should be(false) }
54 | it { subject.is_moderator_of?(Forum.first).should be(true) }
55 | it { subject.is_moderator_of?(Forum.last).should be(false) }
56 | it { subject.is_moderator_of?(Group).should be(false) }
57 | it { subject.is_moderator_of?(Group.first).should be(false) }
58 | it { subject.is_moderator_of?(Group.last).should be(false) }
59 |
60 | context "removing the role on the last user having it" do
61 | before do
62 | subject.remove_role :sole_mio, Forum.last
63 | end
64 |
65 | it { should_not respond_to(:is_sole_mio?) }
66 | it { subject.is_sole_mio?.should be(false) }
67 | end
68 | end
69 |
70 | context "using a class scoped role" do
71 | subject do
72 | manager = user_class.where(:login => "god").first
73 | manager.add_role :manager, Forum
74 | manager.add_role :only_me, Forum
75 | manager
76 | end
77 |
78 | it { should respond_to(:is_manager?).with(0).arguments }
79 | it { should respond_to(:is_manager_of?).with(1).arguments }
80 | it { should_not respond_to(:is_god?) }
81 | it { should_not respond_to(:is_god_of?) }
82 |
83 | it { subject.is_manager?.should be(false) }
84 | it { subject.is_manager_of?(Forum).should be(true) }
85 | it { subject.is_manager_of?(Forum.first).should be(true) }
86 | it { subject.is_manager_of?(Forum.last).should be(true) }
87 | it { subject.is_manager_of?(Group).should be(false) }
88 | it { subject.is_manager_of?(Group.first).should be(false) }
89 | it { subject.is_manager_of?(Group.last).should be(false) }
90 |
91 | context "removing the role on the last user having it" do
92 | before do
93 | subject.remove_role :only_me, Forum
94 | end
95 |
96 | it { should_not respond_to(:is_only_me?) }
97 | it { subject.is_only_me?.should be(false) }
98 | end
99 | end
100 |
101 | context "if the role doesn't exist in the database" do
102 |
103 | subject { user_class.first }
104 |
105 | context "using a global role" do
106 | before(:all) do
107 | other_guy = user_class.last
108 | other_guy.add_role :superman
109 | end
110 |
111 | it { should respond_to(:is_superman?).with(0).arguments }
112 | it { should_not respond_to(:is_superman_of?) }
113 | it { should_not respond_to(:is_god?) }
114 |
115 | it { subject.is_superman?.should be(false) }
116 | it { subject.is_god?.should be(false) }
117 | end
118 |
119 | context "using a resource scope role" do
120 | before(:all) do
121 | other_guy = user_class.last
122 | other_guy.add_role :batman, Forum.first
123 | end
124 |
125 | it { should respond_to(:is_batman?).with(0).arguments }
126 | it { should respond_to(:is_batman_of?).with(1).arguments }
127 | it { should_not respond_to(:is_god?) }
128 | it { should_not respond_to(:is_god_of?) }
129 |
130 | it { subject.is_batman?.should be(false) }
131 | it { subject.is_batman_of?(Forum).should be(false) }
132 | it { subject.is_batman_of?(Forum.first).should be(false) }
133 | it { subject.is_batman_of?(Forum.last).should be(false) }
134 | it { subject.is_batman_of?(Group).should be(false) }
135 | it { subject.is_batman_of?(Group.first).should be(false) }
136 | it { subject.is_batman_of?(Group.last).should be(false) }
137 |
138 | it { subject.is_god?.should be(false) }
139 | it { subject.is_god_of?(Forum).should be(false) }
140 | it { subject.is_god_of?(Forum.first).should be(false) }
141 | it { subject.is_god_of?(Forum.last).should be(false) }
142 | it { subject.is_god_of?(Group).should be(false) }
143 | it { subject.is_god_of?(Group.first).should be(false) }
144 | it { subject.is_god_of?(Group.last).should be(false) }
145 | end
146 | end
147 | end
148 |
--------------------------------------------------------------------------------
/spec/rolify/shared_examples/shared_examples_for_finders.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for :finders do |param_name, param_method|
2 | context "using #{param_name} as parameter" do
3 | describe ".with_role" do
4 | it { should respond_to(:with_role).with(1).argument }
5 | it { should respond_to(:with_role).with(2).arguments }
6 |
7 | context "when resource setting: strict is set to false" do
8 | context "with a global role" do
9 | it { subject.with_role("admin".send(param_method)).should eq([ root ]) }
10 | it { subject.with_role("moderator".send(param_method)).should be_empty }
11 | it { subject.with_role("visitor".send(param_method)).should be_empty }
12 | end
13 |
14 | context "with a class scoped role" do
15 | context "on Forum class" do
16 | it { subject.with_role("admin".send(param_method), Forum).should eq([ root ]) }
17 | it { subject.with_role("moderator".send(param_method), Forum).should eq([ modo ]) }
18 | it { subject.with_role("visitor".send(param_method), Forum).should be_empty }
19 | end
20 |
21 | context "on Group class" do
22 | it { subject.with_role("admin".send(param_method), Group).should eq([ root ]) }
23 | it { subject.with_role("moderator".send(param_method), Group).should eq([ root ]) }
24 | it { subject.with_role("visitor".send(param_method), Group).should be_empty }
25 | end
26 | end
27 |
28 | context "with an instance scoped role" do
29 | context "on Forum.first instance" do
30 | it { subject.with_role("admin".send(param_method), Forum.first).should eq([ root ]) }
31 | it { subject.with_role("moderator".send(param_method), Forum.first).should eq([ modo ]) }
32 | it { subject.with_role("visitor".send(param_method), Forum.first).should be_empty }
33 | end
34 |
35 | context "on Forum.last instance" do
36 | it { subject.with_role("admin".send(param_method), Forum.last).should eq([ root ]) }
37 | it { subject.with_role("moderator".send(param_method), Forum.last).should eq([ modo ]) }
38 | it { subject.with_role("visitor".send(param_method), Forum.last).should include(root, visitor) } # =~ doesn't pass using mongoid, don't know why...
39 | end
40 |
41 | context "on Group.first instance" do
42 | it { subject.with_role("admin".send(param_method), Group.first).should eq([ root ]) }
43 | it { subject.with_role("moderator".send(param_method), Group.first).should eq([ root ]) }
44 | it { subject.with_role("visitor".send(param_method), Group.first).should eq([ modo ]) }
45 | end
46 |
47 | context "on Company.first_instance" do
48 | it { subject.with_role("owner".send(param_method), Company.first).should eq([ owner ]) }
49 | end
50 | end
51 | end
52 |
53 | context "when resource setting: strict is set to true" do
54 | before(:context) do
55 | user_class.strict_rolify = true
56 | end
57 | after(:context) do
58 | user_class.strict_rolify = false
59 | end
60 |
61 | context "with an instance scoped role" do
62 | context "on Forum.first instance" do
63 | it { subject.with_role("admin".send(param_method), Forum.first).should be_empty }
64 | it { subject.with_role("moderator".send(param_method), Forum.first).should be_empty }
65 | end
66 |
67 | context "on any resource" do
68 | it { subject.with_role("admin".send(param_method), :any).should_not be_empty }
69 | it { subject.with_role("moderator".send(param_method), :any).should_not be_empty }
70 | end
71 | end
72 | end
73 | end
74 |
75 | describe ".without_role" do
76 | it { should respond_to(:without_role).with(1).argument }
77 | it { should respond_to(:without_role).with(2).arguments }
78 |
79 | context "with a global role" do
80 | it { subject.without_role("admin".send(param_method)).should_not eq([ root ]) }
81 | it { subject.without_role("moderator".send(param_method)).should_not be_empty }
82 | it { subject.without_role("visitor".send(param_method)).should_not be_empty }
83 | end
84 |
85 | context "with a class scoped role" do
86 | context "on Forum class" do
87 | it { subject.without_role("admin".send(param_method), Forum).should_not eq([ root ]) }
88 | it { subject.without_role("moderator".send(param_method), Forum).should_not eq([ modo ]) }
89 | it { subject.without_role("visitor".send(param_method), Forum).should_not be_empty }
90 | end
91 |
92 | context "on Group class" do
93 | it { subject.without_role("admin".send(param_method), Group).should_not eq([ root ]) }
94 | it { subject.without_role("moderator".send(param_method), Group).should_not eq([ root ]) }
95 | it { subject.without_role("visitor".send(param_method), Group).should_not be_empty }
96 | end
97 | end
98 |
99 | context "with an instance scoped role" do
100 | context "on Forum.first instance" do
101 | it { subject.without_role("admin".send(param_method), Forum.first).should_not eq([ root ]) }
102 | it { subject.without_role("moderator".send(param_method), Forum.first).should_not eq([ modo ]) }
103 | it { subject.without_role("visitor".send(param_method), Forum.first).should_not be_empty }
104 | end
105 |
106 | context "on Forum.last instance" do
107 | it { subject.without_role("admin".send(param_method), Forum.last).should_not eq([ root ]) }
108 | it { subject.without_role("moderator".send(param_method), Forum.last).should_not eq([ modo ]) }
109 | it { subject.without_role("visitor".send(param_method), Forum.last).should_not include(root, visitor) } # =~ doesn't pass using mongoid, don't know why...
110 | end
111 |
112 | context "on Group.first instance" do
113 | it { subject.without_role("admin".send(param_method), Group.first).should_not eq([ root ]) }
114 | it { subject.without_role("moderator".send(param_method), Group.first).should_not eq([ root ]) }
115 | it { subject.without_role("visitor".send(param_method), Group.first).should_not eq([ modo ]) }
116 | end
117 |
118 | context "on Company.first_instance" do
119 | it { subject.without_role("owner".send(param_method), Company.first).should_not eq([ owner ]) }
120 | end
121 | end
122 | end
123 |
124 |
125 | describe ".with_all_roles" do
126 | it { should respond_to(:with_all_roles) }
127 |
128 | it { subject.with_all_roles("admin".send(param_method), :staff).should eq([ root ]) }
129 | it { subject.with_all_roles("admin".send(param_method), :staff, { :name => "moderator".send(param_method), :resource => Group }).should eq([ root ]) }
130 | it { subject.with_all_roles("admin".send(param_method), "moderator".send(param_method)).should be_empty }
131 | it { subject.with_all_roles("admin".send(param_method), :staff, { :name => "moderator".send(param_method), :resource => Forum }).should be_empty }
132 | it { subject.with_all_roles({ :name => "moderator".send(param_method), :resource => Forum }, { :name => :manager, :resource => Group }).should eq([ modo ]) }
133 | it { subject.with_all_roles("moderator".send(param_method), :manager).should be_empty }
134 | it { subject.with_all_roles({ :name => "visitor".send(param_method), :resource => Forum.last }, { :name => "moderator".send(param_method), :resource => Group }).should eq([ root ]) }
135 | it { subject.with_all_roles({ :name => "visitor".send(param_method), :resource => Group.first }, { :name => "moderator".send(param_method), :resource => Forum }).should eq([ modo ]) }
136 | it { subject.with_all_roles({ :name => "visitor".send(param_method), :resource => :any }, { :name => "moderator".send(param_method), :resource => :any }).should =~ [ root, modo ] }
137 | end
138 |
139 | describe ".with_any_role" do
140 | it { should respond_to(:with_any_role) }
141 |
142 | it { subject.with_any_role("admin".send(param_method), :staff).should eq([ root ]) }
143 | it { subject.with_any_role("admin".send(param_method), :staff, { :name => "moderator".send(param_method), :resource => Group }).should eq([ root ]) }
144 | it { subject.with_any_role("admin".send(param_method), "moderator".send(param_method)).should eq([ root ]) }
145 | it { subject.with_any_role("admin".send(param_method), :staff, { :name => "moderator".send(param_method), :resource => Forum }).should =~ [ root, modo ] }
146 | it { subject.with_any_role({ :name => "moderator".send(param_method), :resource => Forum }, { :name => :manager, :resource => Group }).should eq([ modo ]) }
147 | it { subject.with_any_role({ :name => "moderator".send(param_method), :resource => Group }, { :name => :manager, :resource => Group }).should =~ [ root, modo ] }
148 | it { subject.with_any_role("moderator".send(param_method), :manager).should be_empty }
149 | it { subject.with_any_role({ :name => "visitor".send(param_method), :resource => Forum.last }, { :name => "moderator".send(param_method), :resource => Group }).should =~ [ root, visitor ] }
150 | it { subject.with_any_role({ :name => "visitor".send(param_method), :resource => Group.first }, { :name => "moderator".send(param_method), :resource => Forum }).should eq([ modo ]) }
151 | it { subject.with_any_role({ :name => "visitor".send(param_method), :resource => :any }, { :name => "moderator".send(param_method), :resource => :any }).should =~ [ root, modo, visitor ] }
152 | end
153 | end
154 | end
155 |
--------------------------------------------------------------------------------
/spec/rolify/shared_examples/shared_examples_for_has_all_roles.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for "#has_all_roles?_examples" do |param_name, param_method|
2 | context "using #{param_name} as parameter" do
3 | context "with a global role", :scope => :global do
4 | context "on global roles only request" do
5 | it { subject.has_all_roles?("staff".send(param_method)).should be_truthy }
6 | it { subject.has_all_roles?("admin".send(param_method), "staff".send(param_method)).should be_truthy }
7 | it { subject.has_all_roles?("admin".send(param_method), "dummy".send(param_method)).should be_falsey }
8 | it { subject.has_all_roles?("dummy".send(param_method), "dumber".send(param_method)).should be_falsey }
9 | end
10 |
11 | context "on mixed scoped roles" do
12 | it { subject.has_all_roles?({ :name => "admin".send(param_method), :resource => Forum }, { :name => "admin".send(param_method), :resource => Group }).should be_truthy }
13 | it { subject.has_all_roles?({ :name => "admin".send(param_method), :resource => :any }, { :name => "admin".send(param_method), :resource => Group }).should be_truthy }
14 | it { subject.has_all_roles?({ :name => "admin".send(param_method), :resource => Forum }, { :name => "staff".send(param_method), :resource => Group.last }).should be_truthy }
15 | it { subject.has_all_roles?({ :name => "admin".send(param_method), :resource => Forum.first }, { :name => "admin".send(param_method), :resource => Forum.last }).should be_truthy }
16 | it { subject.has_all_roles?({ :name => "admin".send(param_method), :resource => Forum.first }, { :name => "dummy".send(param_method), :resource => Forum.last }).should be_falsey }
17 | it { subject.has_all_roles?({ :name => "admin".send(param_method), :resource => Forum.first }, { :name => "dummy".send(param_method), :resource => :any }).should be_falsey}
18 | end
19 | end
20 |
21 | context "with a class scoped role", :scope => :class do
22 | context "on class scoped roles only" do
23 | it { subject.has_all_roles?({ :name => "player".send(param_method), :resource => Forum }).should be_truthy }
24 | it { subject.has_all_roles?({ :name => "manager".send(param_method), :resource => Forum }, { :name => "player".send(param_method), :resource => Forum }).should be_truthy }
25 | it { subject.has_all_roles?({ :name => "manager".send(param_method), :resource => :any }, { :name => "player".send(param_method), :resource => Forum }).should be_truthy }
26 | it { subject.has_all_roles?({ :name => "manager".send(param_method), :resource => :any }, { :name => "player".send(param_method), :resource => :any }).should be_truthy }
27 | it { subject.has_all_roles?({ :name => "manager".send(param_method), :resource => Forum }, { :name => "dummy".send(param_method), :resource => Forum }).should be_falsey }
28 | it { subject.has_all_roles?({ :name => "manager".send(param_method), :resource => Forum }, { :name => "dummy".send(param_method), :resource => :any }).should be_falsey }
29 | it { subject.has_all_roles?({ :name => "dummy".send(param_method), :resource => Forum }, { :name => "dumber".send(param_method), :resource => Group }).should be_falsey }
30 | end
31 |
32 | context "on mixed scoped roles" do
33 | it { subject.has_all_roles?({ :name => "manager".send(param_method), :resource => Forum.first }, { :name => "manager".send(param_method), :resource => Forum.last }).should be_truthy }
34 | it { subject.has_all_roles?({ :name => "manager".send(param_method), :resource => Group }, { :name => "moderator".send(param_method), :resource => Forum.first }).should be_falsey }
35 | it { subject.has_all_roles?({ :name => "manager".send(param_method), :resource => Forum.first }, { :name => "moderator".send(param_method), :resource => Forum }).should be_falsey }
36 | it { subject.has_all_roles?({ :name => "manager".send(param_method), :resource => Forum.last }, { :name => "warrior".send(param_method), :resource => Forum.last }).should be_truthy }
37 | end
38 | end
39 |
40 | context "with a instance scoped role", :scope => :instance do
41 | context "on instance scoped roles only" do
42 | it { subject.has_all_roles?({ :name => "moderator".send(param_method), :resource => :any }, { :name => "anonymous".send(param_method), :resource => Forum.last }).should be_truthy }
43 | it { subject.has_all_roles?({ :name => "moderator".send(param_method), :resource => :any }, { :name => "anonymous".send(param_method), :resource => :any }).should be_truthy }
44 | it { subject.has_all_roles?({ :name => "moderator".send(param_method), :resource => :any }, { :name => "anonymous".send(param_method), :resource => Forum }).should be_falsey }
45 | it { subject.has_all_roles?({ :name => "moderator".send(param_method), :resource => Forum.first }, { :name => "anonymous".send(param_method), :resource => Forum.last }).should be_truthy }
46 | it { subject.has_all_roles?({ :name => "moderator".send(param_method), :resource => Forum.first }, { :name => "moderator".send(param_method), :resource => Forum.last }).should be_falsey }
47 | it { subject.has_all_roles?({ :name => "moderator".send(param_method), :resource => Forum.first }, { :name => "dummy".send(param_method), :resource => Forum.last }).should be_falsey }
48 | it { subject.has_all_roles?({ :name => "dummy".send(param_method), :resource => Forum.first }, { :name => "dumber".send(param_method), :resource => Forum.last }).should be_falsey }
49 | end
50 |
51 | context "on mixed scoped roles" do
52 | it { subject.has_all_roles?({ :name => "visitor".send(param_method), :resource => Forum.last }).should be_truthy }
53 | it { subject.has_all_roles?("soldier".send(param_method), { :name => "moderator".send(param_method), :resource => Forum.first }, { :name => "visitor".send(param_method), :resource => Forum }).should be(true) }
54 | it { subject.has_all_roles?("soldier".send(param_method), { :name => "moderator".send(param_method), :resource => Forum.last }, { :name => "visitor".send(param_method), :resource => Forum }).should be(false) }
55 | it { subject.has_all_roles?("soldier".send(param_method), { :name => "moderator".send(param_method), :resource => :any }, { :name => "visitor".send(param_method), :resource => Forum }).should be(true) }
56 | it { subject.has_all_roles?("soldier".send(param_method), { :name => "moderator".send(param_method), :resource => :any }, { :name => "visitor".send(param_method), :resource => :any }).should be(true) }
57 | it { subject.has_all_roles?("soldier".send(param_method), { :name => "moderator".send(param_method), :resource => Forum.first }, { :name => "visitor".send(param_method), :resource => Group }).should be(false) }
58 | it { subject.has_all_roles?("soldier".send(param_method), { :name => "moderator".send(param_method), :resource => Forum.first }, { :name => "visitor".send(param_method), :resource => Group.first }).should be(false) }
59 | it { subject.has_all_roles?({ :name => "soldier".send(param_method), :resource => Forum }, { :name => "moderator".send(param_method), :resource => Forum.first }, { :name => "visitor".send(param_method), :resource => Forum }).should be(true) }
60 | it { subject.has_all_roles?({ :name => "soldier".send(param_method), :resource => Forum.first }, { :name => "moderator".send(param_method), :resource => Forum.first }, { :name => "visitor".send(param_method), :resource => Forum }).should be(true) }
61 | it { subject.has_all_roles?("soldier".send(param_method), { :name => "moderator".send(param_method), :resource => Forum.first }, { :name => "visitor".send(param_method), :resource => Forum.first }).should be(true) }
62 | it { subject.has_all_roles?("dummy".send(param_method), { :name => "dumber".send(param_method), :resource => Forum.last }, { :name => "dumberer".send(param_method), :resource => Forum }).should be(false) }
63 | it { subject.has_all_roles?("soldier".send(param_method), "dummy".send(param_method), { :name => "dumber".send(param_method), :resource => Forum.last }, { :name => "dumberer".send(param_method), :resource => Forum }).should be(false) }
64 | it { subject.has_all_roles?({ :name => "manager".send(param_method), :resource => Forum.last }, "dummy".send(param_method), { :name => "dumber".send(param_method), :resource => Forum.last }, { :name => "dumberer".send(param_method), :resource => Forum }).should be(false) }
65 | it { subject.has_all_roles?("soldier".send(param_method), { :name => "dumber".send(param_method), :resource => Forum.last }, { :name => "manager".send(param_method), :resource => Forum.last }).should be(false) }
66 | it { subject.has_all_roles?({ :name => "soldier".send(param_method), :resource => Forum.first }, { :name => "moderator".send(param_method), :resource => Forum.first }, { :name => "visitor".send(param_method), :resource => Forum.last }).should be(true) }
67 | it { subject.has_all_roles?({ :name => "soldier".send(param_method), :resource => Forum.first }, { :name => "moderator".send(param_method), :resource => :any }, { :name => "visitor".send(param_method), :resource => Forum.last }).should be(true) }
68 | end
69 | end
70 | end
71 | end
--------------------------------------------------------------------------------
/spec/rolify/shared_examples/shared_examples_for_has_any_role.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for "#has_any_role?_examples" do |param_name, param_method|
2 | context "using #{param_name} as parameter" do
3 | context "with a global role", :scope => :global do
4 | before do
5 | subject.add_role "staff".send(param_method)
6 | end
7 |
8 | it { subject.has_any_role?("staff".send(param_method)).should be_truthy }
9 | it { subject.has_any_role?("admin".send(param_method), "staff".send(param_method)).should be_truthy }
10 | it { subject.has_any_role?("admin".send(param_method), "moderator".send(param_method)).should be_truthy }
11 | it { subject.has_any_role?("dummy".send(param_method), "dumber".send(param_method)).should be_falsey }
12 | it { subject.has_any_role?({ :name => "admin".send(param_method), :resource => Forum }, { :name => "admin".send(param_method), :resource => Group }).should be_truthy }
13 | it { subject.has_any_role?({ :name => "admin".send(param_method), :resource => :any }, { :name => "admin".send(param_method), :resource => Group }).should be_truthy }
14 | it { subject.has_any_role?({ :name => "admin".send(param_method), :resource => Forum }, { :name => "staff".send(param_method), :resource => Group.last }).should be_truthy }
15 | it { subject.has_any_role?({ :name => "admin".send(param_method), :resource => Forum.first }, { :name => "admin".send(param_method), :resource => Forum.last }).should be_truthy }
16 | it { subject.has_any_role?({ :name => "admin".send(param_method), :resource => Forum.first }, { :name => "dummy".send(param_method), :resource => Forum.last }).should be_truthy }
17 | it { subject.has_any_role?({ :name => "admin".send(param_method), :resource => Forum.first }, { :name => "dummy".send(param_method), :resource => :any }).should be_truthy }
18 | it { subject.has_any_role?({ :name => "dummy".send(param_method), :resource => Forum.first }, { :name => "dumber".send(param_method), :resource => :any }).should be_falsey }
19 | it { subject.has_any_role?({ :name => "dummy".send(param_method), :resource => :any }, { :name => "dumber".send(param_method), :resource => :any }).should be_falsey }
20 | end
21 |
22 | context "with a class scoped role", :scope => :class do
23 | before do
24 | subject.add_role "player".send(param_method), Forum
25 | subject.add_role "superhero".send(param_method)
26 | end
27 |
28 | it { subject.has_any_role?({ :name => "player".send(param_method), :resource => Forum }).should be_truthy }
29 | it { subject.has_any_role?({ :name => "manager".send(param_method), :resource => Forum }, { :name => "player".send(param_method), :resource => Forum }).should be_truthy }
30 | it { subject.has_any_role?({ :name => "manager".send(param_method), :resource => Forum }, { :name => "player".send(param_method), :resource => :any }).should be_truthy }
31 | it { subject.has_any_role?({ :name => "manager".send(param_method), :resource => Forum }, { :name => "player".send(param_method), :resource => :any }).should be_truthy }
32 | it { subject.has_any_role?({ :name => "manager".send(param_method), :resource => :any }, { :name => "player".send(param_method), :resource => :any }).should be_truthy }
33 | it { subject.has_any_role?({ :name => "manager".send(param_method), :resource => Forum }, { :name => "dummy".send(param_method), :resource => Forum }).should be_truthy }
34 | it { subject.has_any_role?({ :name => "manager".send(param_method), :resource => Forum }, { :name => "dummy".send(param_method), :resource => :any }).should be_truthy }
35 | it { subject.has_any_role?({ :name => "dummy".send(param_method), :resource => Forum }, { :name => "dumber".send(param_method), :resource => Group }).should be_falsey }
36 | it { subject.has_any_role?({ :name => "manager".send(param_method), :resource => Forum.first }, { :name => "manager".send(param_method), :resource => Forum.last }).should be_truthy }
37 | it { subject.has_any_role?({ :name => "manager".send(param_method), :resource => Group }, { :name => "moderator".send(param_method), :resource => Forum.first }).should be_falsey }
38 | it { subject.has_any_role?({ :name => "manager".send(param_method), :resource => Forum.first }, { :name => "moderator".send(param_method), :resource => Forum }).should be_truthy }
39 | it { subject.has_any_role?({ :name => "manager".send(param_method), :resource => Forum.last }, { :name => "warrior".send(param_method), :resource => Forum.last }).should be_truthy }
40 | end
41 |
42 | context "with a instance scoped role", :scope => :instance do
43 | before do
44 | subject.add_role "visitor".send(param_method), Forum.last
45 | subject.add_role "leader", Group
46 | subject.add_role "warrior"
47 | end
48 |
49 | it { subject.has_any_role?({ :name => "visitor", :resource => Forum.last }).should be_truthy }
50 | it { subject.has_any_role?({ :name => "moderator", :resource => Forum.first }, { :name => "visitor", :resource => Forum.last }).should be_truthy }
51 | it { subject.has_any_role?({ :name => "moderator", :resource => :any }, { :name => "visitor", :resource => Forum.last }).should be_truthy }
52 | it { subject.has_any_role?({ :name => "moderator", :resource => :any }, { :name => "visitor", :resource => :any}).should be_truthy }
53 | it { subject.has_any_role?({ :name => "moderator", :resource => Forum }, { :name => "visitor", :resource => :any }).should be_truthy }
54 | it { subject.has_any_role?({ :name => "moderator", :resource => Forum.first }, { :name => "moderator", :resource => Forum.last }).should be_truthy }
55 | it { subject.has_any_role?({ :name => "moderator", :resource => Forum.first }, { :name => "dummy", :resource => Forum.last }).should be_truthy }
56 | it { subject.has_any_role?({ :name => "dummy", :resource => Forum.first }, { :name => "dumber", :resource => Forum.last }).should be_falsey }
57 | it { subject.has_any_role?("warrior", { :name => "moderator", :resource => Forum.first }, { :name => "leader", :resource => Group }).should be(true) }
58 | it { subject.has_any_role?("warrior", { :name => "moderator", :resource => :any }, { :name => "leader", :resource => Forum }).should be(true) }
59 | it { subject.has_any_role?("warrior", { :name => "moderator", :resource => Forum.first }, { :name => "leader", :resource => :any }).should be(true) }
60 | it { subject.has_any_role?("warrior", { :name => "moderator", :resource => :any }, { :name => "leader", :resource => :any }).should be(true) }
61 | it { subject.has_any_role?("warrior", { :name => "moderator", :resource => Forum.last }, { :name => "leader", :resource => Forum }).should be(true) }
62 | it { subject.has_any_role?("warrior", { :name => "moderator", :resource => Forum.last }, { :name => "leader", :resource => Group }).should be(true) }
63 | it { subject.has_any_role?("warrior", { :name => "moderator", :resource => Forum.last }, { :name => "leader", :resource => Group.first }).should be(true) }
64 | it { subject.has_any_role?({ :name => "warrior", :resource => Forum }, { :name => "moderator", :resource => Forum.last }, { :name => "leader", :resource => Forum }).should be(true) }
65 | it { subject.has_any_role?({ :name => "warrior", :resource => Forum.first }, { :name => "moderator", :resource => Forum.last }, { :name => "leader", :resource => Forum }).should be(true) }
66 | it { subject.has_any_role?("warrior", { :name => "moderator", :resource => Forum.last }, { :name => "leader", :resource => Forum.first }).should be(true) }
67 | it { subject.has_any_role?("dummy", { :name => "dumber", :resource => Forum.last }, { :name => "dumberer", :resource => Forum }).should be(false) }
68 | it { subject.has_any_role?({ :name => "leader", :resource => Group.last }, "dummy", { :name => "dumber", :resource => Forum.last }, { :name => "dumberer", :resource => Forum }).should be(true) }
69 | end
70 | end
71 | end
--------------------------------------------------------------------------------
/spec/rolify/shared_examples/shared_examples_for_has_role.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for "#has_role?_examples" do |param_name, param_method|
2 | context "using #{param_name} as parameter" do
3 | context "with a global role", :scope => :global do
4 | it { subject.has_role?("admin".send(param_method)).should be_truthy }
5 |
6 | it { subject.has_cached_role?("admin".send(param_method)).should be_truthy }
7 |
8 | context "on resource request" do
9 | it { subject.has_role?("admin".send(param_method), Forum.first).should be_truthy }
10 | it { subject.has_role?("admin".send(param_method), Forum).should be_truthy }
11 | it { subject.has_role?("admin".send(param_method), :any).should be_truthy }
12 |
13 | it { subject.has_cached_role?("admin".send(param_method), Forum.first).should be_truthy }
14 | it { subject.has_cached_role?("admin".send(param_method), Forum).should be_truthy }
15 | it { subject.has_cached_role?("admin".send(param_method), :any).should be_truthy }
16 | end
17 |
18 | context "with another global role" do
19 | before(:all) { role_class.create(:name => "global") }
20 |
21 | it { subject.has_role?("global".send(param_method)).should be_falsey }
22 | it { subject.has_role?("global".send(param_method), :any).should be_falsey }
23 |
24 | it { subject.has_cached_role?("global".send(param_method)).should be_falsey }
25 | it { subject.has_cached_role?("global".send(param_method), :any).should be_falsey }
26 | end
27 |
28 | it "should not get an instance scoped role" do
29 | subject.has_role?("moderator".send(param_method), Group.first).should be_falsey
30 |
31 | subject.has_cached_role?("moderator".send(param_method), Group.first).should be_falsey
32 | end
33 |
34 | it "should not get a class scoped role" do
35 | subject.has_role?("manager".send(param_method), Forum).should be_falsey
36 |
37 | subject.has_cached_role?("manager".send(param_method), Forum).should be_falsey
38 | end
39 |
40 | context "using inexisting role" do
41 | it { subject.has_role?("dummy".send(param_method)).should be_falsey }
42 | it { subject.has_role?("dumber".send(param_method), Forum.first).should be_falsey }
43 |
44 | it { subject.has_cached_role?("dummy".send(param_method)).should be_falsey }
45 | it { subject.has_cached_role?("dumber".send(param_method), Forum.first).should be_falsey }
46 | end
47 | end
48 |
49 | context "with a class scoped role", :scope => :class do
50 | context "on class scoped role request" do
51 | it { subject.has_role?("manager".send(param_method), Forum).should be_truthy }
52 | it { subject.has_role?("manager".send(param_method), Forum.first).should be_truthy }
53 | it { subject.has_role?("manager".send(param_method), :any).should be_truthy }
54 |
55 | it { subject.has_cached_role?("manager".send(param_method), Forum).should be_truthy }
56 | it { subject.has_cached_role?("manager".send(param_method), Forum.first).should be_truthy }
57 | it { subject.has_cached_role?("manager".send(param_method), :any).should be_truthy }
58 | end
59 |
60 | it "should not get a scoped role when asking for a global" do
61 | subject.has_role?("manager".send(param_method)).should be_falsey
62 |
63 | subject.has_cached_role?("manager".send(param_method)).should be_falsey
64 | end
65 |
66 | it "should not get a global role" do
67 | role_class.create(:name => "admin")
68 | subject.has_role?("admin".send(param_method)).should be_falsey
69 |
70 | subject.has_cached_role?("admin".send(param_method)).should be_falsey
71 | end
72 |
73 | context "with another class scoped role" do
74 | context "on the same resource but with a different name" do
75 | before(:all) { role_class.create(:name => "member", :resource_type => "Forum") }
76 |
77 | it { subject.has_role?("member".send(param_method), Forum).should be_falsey }
78 | it { subject.has_role?("member".send(param_method), :any).should be_falsey }
79 |
80 | it { subject.has_cached_role?("member".send(param_method), Forum).should be_falsey }
81 | it { subject.has_cached_role?("member".send(param_method), :any).should be_falsey }
82 | end
83 |
84 | context "on another resource with the same name" do
85 | before(:all) { role_class.create(:name => "manager", :resource_type => "Group") }
86 |
87 | it { subject.has_role?("manager".send(param_method), Group).should be_falsey }
88 | it { subject.has_role?("manager".send(param_method), :any).should be_truthy }
89 |
90 | it { subject.has_cached_role?("manager".send(param_method), Group).should be_falsey }
91 | it { subject.has_cached_role?("manager".send(param_method), :any).should be_truthy }
92 | end
93 |
94 | context "on another resource with another name" do
95 | before(:all) { role_class.create(:name => "defenders", :resource_type => "Group") }
96 |
97 | it { subject.has_role?("defenders".send(param_method), Group).should be_falsey }
98 | it { subject.has_role?("defenders".send(param_method), :any).should be_falsey }
99 |
100 | it { subject.has_cached_role?("defenders".send(param_method), Group).should be_falsey }
101 | it { subject.has_cached_role?("defenders".send(param_method), :any).should be_falsey }
102 | end
103 | end
104 |
105 | context "using inexisting role" do
106 | it { subject.has_role?("dummy".send(param_method), Forum).should be_falsey }
107 | it { subject.has_role?("dumber".send(param_method)).should be_falsey }
108 |
109 | it { subject.has_cached_role?("dummy".send(param_method), Forum).should be_falsey }
110 | it { subject.has_cached_role?("dumber".send(param_method)).should be_falsey }
111 | end
112 | end
113 |
114 | context "with a instance scoped role", :scope => :instance do
115 | context "on instance scoped role request" do
116 | it { subject.has_role?("moderator".send(param_method), Forum.first).should be_truthy }
117 | it { subject.has_role?("moderator".send(param_method), :any).should be_truthy }
118 | it {
119 | m = subject.class.new
120 | m.add_role("moderator", Forum.first)
121 | m.has_role?("moderator".send(param_method), :any).should be_truthy
122 | }
123 |
124 | it { subject.has_cached_role?("moderator".send(param_method), Forum.first).should be_truthy }
125 | it { subject.has_cached_role?("moderator".send(param_method), :any).should be_truthy }
126 | it {
127 | m = subject.class.new
128 | m.add_role("moderator", Forum.first)
129 | m.has_cached_role?("moderator".send(param_method), :any).should be_truthy
130 | }
131 | end
132 |
133 | it "should not get an instance scoped role when asking for a global" do
134 | subject.has_role?("moderator".send(param_method)).should be_falsey
135 |
136 | subject.has_cached_role?("moderator".send(param_method)).should be_falsey
137 | end
138 |
139 | it "should not get an instance scoped role when asking for a class scoped" do
140 | subject.has_role?("moderator".send(param_method), Forum).should be_falsey
141 |
142 | subject.has_cached_role?("moderator".send(param_method), Forum).should be_falsey
143 | end
144 |
145 | it "should not get a global role" do
146 | role_class.create(:name => "admin")
147 | subject.has_role?("admin".send(param_method)).should be_falsey
148 |
149 | subject.has_cached_role?("admin".send(param_method)).should be_falsey
150 | end
151 |
152 | context "with another instance scoped role" do
153 | context "on the same resource but with a different role name" do
154 | before(:all) { role_class.create(:name => "member", :resource => Forum.first) }
155 |
156 | it { subject.has_role?("member".send(param_method), Forum.first).should be_falsey }
157 | it { subject.has_role?("member".send(param_method), :any).should be_falsey }
158 |
159 | it { subject.has_cached_role?("member".send(param_method), Forum.first).should be_falsey }
160 | it { subject.has_cached_role?("member".send(param_method), :any).should be_falsey }
161 | end
162 |
163 | context "on another resource of the same type but with the same role name" do
164 | before(:all) { role_class.create(:name => "moderator", :resource => Forum.last) }
165 |
166 | it { subject.has_role?("moderator".send(param_method), Forum.last).should be_falsey }
167 | it { subject.has_role?("moderator".send(param_method), :any).should be_truthy }
168 |
169 | it { subject.has_cached_role?("moderator".send(param_method), Forum.last).should be_falsey }
170 | it { subject.has_cached_role?("moderator".send(param_method), :any).should be_truthy }
171 | end
172 |
173 | context "on another resource of different type but with the same role name" do
174 | before(:all) { role_class.create(:name => "moderator", :resource => Group.last) }
175 |
176 | it { subject.has_role?("moderator".send(param_method), Group.last).should be_falsey }
177 | it { subject.has_role?("moderator".send(param_method), :any).should be_truthy }
178 |
179 | it { subject.has_cached_role?("moderator".send(param_method), Group.last).should be_falsey }
180 | it { subject.has_cached_role?("moderator".send(param_method), :any).should be_truthy }
181 | end
182 |
183 | context "on another resource of the same type and with another role name" do
184 | before(:all) { role_class.create(:name => "member", :resource => Forum.last) }
185 |
186 | it { subject.has_role?("member".send(param_method), Forum.last).should be_falsey }
187 | it { subject.has_role?("member".send(param_method), :any).should be_falsey }
188 |
189 | it { subject.has_cached_role?("member".send(param_method), Forum.last).should be_falsey }
190 | it { subject.has_cached_role?("member".send(param_method), :any).should be_falsey }
191 | end
192 |
193 | context "on another resource of different type and with another role name" do
194 | before(:all) { role_class.create(:name => "member", :resource => Group.first) }
195 |
196 | it { subject.has_role?("member".send(param_method), Group.first).should be_falsey }
197 | it { subject.has_role?("member".send(param_method), :any).should be_falsey }
198 |
199 | it { subject.has_cached_role?("member".send(param_method), Group.first).should be_falsey }
200 | it { subject.has_cached_role?("member".send(param_method), :any).should be_falsey }
201 | end
202 | end
203 | end
204 | end
205 | end
206 |
--------------------------------------------------------------------------------
/spec/rolify/shared_examples/shared_examples_for_only_has_role.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for "#only_has_role?_examples" do |param_name, param_method|
2 | context "using #{param_name} as parameter" do
3 | context "with a global role", :scope => :global do
4 | subject do
5 | user = User.create(:login => "global_user")
6 | user.add_role "global_role".send(param_method)
7 | user
8 | end
9 |
10 | it { subject.only_has_role?("global_role".send(param_method)).should be_truthy }
11 |
12 | context "on resource request" do
13 | it { subject.only_has_role?("global_role".send(param_method), Forum.first).should be_truthy }
14 | it { subject.only_has_role?("global_role".send(param_method), Forum).should be_truthy }
15 | it { subject.only_has_role?("global_role".send(param_method), :any).should be_truthy }
16 | end
17 |
18 | context "with another global role" do
19 | before(:all) { role_class.create(:name => "another_global_role") }
20 |
21 | it { subject.only_has_role?("another_global_role".send(param_method)).should be_falsey }
22 | it { subject.only_has_role?("another_global_role".send(param_method), :any).should be_falsey }
23 | end
24 |
25 | it "should not get an instance scoped role" do
26 | subject.only_has_role?("moderator".send(param_method), Group.first).should be_falsey
27 | end
28 |
29 | it "should not get a class scoped role" do
30 | subject.only_has_role?("manager".send(param_method), Forum).should be_falsey
31 | end
32 |
33 | context "using inexisting role" do
34 | it { subject.only_has_role?("dummy".send(param_method)).should be_falsey }
35 | it { subject.only_has_role?("dumber".send(param_method), Forum.first).should be_falsey }
36 | end
37 |
38 | context "with multiple roles" do
39 | before { subject.add_role "multiple_global_roles".send(param_method) }
40 |
41 | it { subject.only_has_role?("global_role".send(param_method)).should be_falsey }
42 | end
43 | end
44 |
45 | context "with a class scoped role", :scope => :class do
46 | subject do
47 | user = User.create(:login => "class_user")
48 | user.add_role "class_role".send(param_method), Forum
49 | user
50 | end
51 |
52 | context "on class scoped role request" do
53 | it { subject.only_has_role?("class_role".send(param_method), Forum).should be_truthy }
54 | it { subject.only_has_role?("class_role".send(param_method), Forum.first).should be_truthy }
55 | it { subject.only_has_role?("class_role".send(param_method), :any).should be_truthy }
56 | end
57 |
58 | it "should not get a scoped role when asking for a global" do
59 | subject.only_has_role?("class_role".send(param_method)).should be_falsey
60 | end
61 |
62 | it "should not get a global role" do
63 | role_class.create(:name => "global_role")
64 | subject.only_has_role?("global_role".send(param_method)).should be_falsey
65 | end
66 |
67 | context "with another class scoped role" do
68 | context "on the same resource but with a different name" do
69 | before(:all) { role_class.create(:name => "another_class_role", :resource_type => "Forum") }
70 |
71 | it { subject.only_has_role?("another_class_role".send(param_method), Forum).should be_falsey }
72 | it { subject.only_has_role?("another_class_role".send(param_method), :any).should be_falsey }
73 | end
74 |
75 | context "on another resource with the same name" do
76 | before(:all) { role_class.create(:name => "class_role", :resource_type => "Group") }
77 |
78 | it { subject.only_has_role?("class_role".send(param_method), Group).should be_falsey }
79 | it { subject.only_has_role?("class_role".send(param_method), :any).should be_truthy }
80 | end
81 |
82 | context "on another resource with another name" do
83 | before(:all) { role_class.create(:name => "another_class_role", :resource_type => "Group") }
84 |
85 | it { subject.only_has_role?("another_class_role".send(param_method), Group).should be_falsey }
86 | it { subject.only_has_role?("another_class_role".send(param_method), :any).should be_falsey }
87 | end
88 | end
89 |
90 | context "using inexisting role" do
91 | it { subject.only_has_role?("dummy".send(param_method), Forum).should be_falsey }
92 | it { subject.only_has_role?("dumber".send(param_method)).should be_falsey }
93 | end
94 |
95 | context "with multiple roles" do
96 | before { subject.add_role "multiple_class_roles".send(param_method) }
97 |
98 | it { subject.only_has_role?("class_role".send(param_method), Forum).should be_falsey }
99 | it { subject.only_has_role?("class_role".send(param_method), Forum.first).should be_falsey }
100 | it { subject.only_has_role?("class_role".send(param_method), :any).should be_falsey }
101 | end
102 | end
103 |
104 | context "with a instance scoped role", :scope => :instance do
105 | subject do
106 | user = User.create(:login => "instance_user")
107 | user.add_role "instance_role".send(param_method), Forum.first
108 | user
109 | end
110 |
111 | context "on instance scoped role request" do
112 | it { subject.only_has_role?("instance_role".send(param_method), Forum.first).should be_truthy }
113 | it { subject.only_has_role?("instance_role".send(param_method), :any).should be_truthy }
114 | end
115 |
116 | it "should not get an instance scoped role when asking for a global" do
117 | subject.only_has_role?("instance_role".send(param_method)).should be_falsey
118 | end
119 |
120 | it "should not get an instance scoped role when asking for a class scoped" do
121 | subject.only_has_role?("instance_role".send(param_method), Forum).should be_falsey
122 | end
123 |
124 | it "should not get a global role" do
125 | role_class.create(:name => "global_role")
126 | subject.only_has_role?("global_role".send(param_method)).should be_falsey
127 | end
128 |
129 | context "with another instance scoped role" do
130 | context "on the same resource but with a different role name" do
131 | before(:all) { role_class.create(:name => "another_instance_role", :resource => Forum.first) }
132 |
133 | it { subject.only_has_role?("another_instance_role".send(param_method), Forum.first).should be_falsey }
134 | it { subject.only_has_role?("another_instance_role".send(param_method), :any).should be_falsey }
135 | end
136 |
137 | context "on another resource of the same type but with the same role name" do
138 | before(:all) { role_class.create(:name => "moderator", :resource => Forum.last) }
139 |
140 | it { subject.only_has_role?("instance_role".send(param_method), Forum.last).should be_falsey }
141 | it { subject.only_has_role?("instance_role".send(param_method), :any).should be_truthy }
142 | end
143 |
144 | context "on another resource of different type but with the same role name" do
145 | before(:all) { role_class.create(:name => "moderator", :resource => Group.last) }
146 |
147 | it { subject.only_has_role?("instance_role".send(param_method), Group.last).should be_falsey }
148 | it { subject.only_has_role?("instance_role".send(param_method), :any).should be_truthy }
149 | end
150 |
151 | context "on another resource of the same type and with another role name" do
152 | before(:all) { role_class.create(:name => "another_instance_role", :resource => Forum.last) }
153 |
154 | it { subject.only_has_role?("another_instance_role".send(param_method), Forum.last).should be_falsey }
155 | it { subject.only_has_role?("another_instance_role".send(param_method), :any).should be_falsey }
156 | end
157 |
158 | context "on another resource of different type and with another role name" do
159 | before(:all) { role_class.create(:name => "another_instance_role", :resource => Group.first) }
160 |
161 | it { subject.only_has_role?("another_instance_role".send(param_method), Group.first).should be_falsey }
162 | it { subject.only_has_role?("another_instance_role".send(param_method), :any).should be_falsey }
163 | end
164 | end
165 |
166 | context "with multiple roles" do
167 | before { subject.add_role "multiple_instance_roles".send(param_method), Forum.first }
168 |
169 | it { subject.only_has_role?("instance_role".send(param_method), Forum.first).should be_falsey }
170 | it { subject.only_has_role?("instance_role".send(param_method), :any).should be_falsey }
171 | end
172 | end
173 | end
174 | end
--------------------------------------------------------------------------------
/spec/rolify/shared_examples/shared_examples_for_remove_role.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for "#remove_role_examples" do |param_name, param_method|
2 | context "using #{param_name} as parameter" do
3 | context "removing a global role", :scope => :global do
4 | context "being a global role of the user" do
5 | it { expect { subject.remove_role("admin".send(param_method)) }.to change { subject.roles.size }.by(-1) }
6 |
7 | it { should_not have_role("admin".send(param_method)) }
8 | end
9 |
10 | context "being a class scoped role to the user" do
11 | it { expect { subject.remove_role("manager".send(param_method)) }.to change { subject.roles.size }.by(-1) }
12 |
13 | it { should_not have_role("manager".send(param_method), Group) }
14 | end
15 |
16 | context "being instance scoped roles to the user" do
17 | it { expect { subject.remove_role("moderator".send(param_method)) }.to change { subject.roles.size }.by(-2) }
18 |
19 | it { should_not have_role("moderator".send(param_method), Forum.last) }
20 | it { should_not have_role("moderator".send(param_method), Group.last) }
21 | end
22 |
23 | context "not being a role of the user" do
24 | it { expect { subject.remove_role("superhero".send(param_method)) }.not_to change { subject.roles.size } }
25 | end
26 |
27 | context "used by another user" do
28 | before do
29 | user = user_class.last
30 | user.add_role "staff".send(param_method)
31 | end
32 |
33 | it { expect { subject.remove_role("staff".send(param_method)) }.not_to change { role_class.count } }
34 |
35 | it { should_not have_role("staff".send(param_method)) }
36 | end
37 |
38 | context "not used by anyone else" do
39 | before do
40 | subject.add_role "nobody".send(param_method)
41 | end
42 |
43 | it { expect { subject.remove_role("nobody".send(param_method)) }.to change { role_class.count }.by(-1) }
44 | end
45 | end
46 |
47 | context "removing a class scoped role", :scope => :class do
48 | context "being a global role of the user" do
49 | it { expect { subject.remove_role("warrior".send(param_method), Forum) }.not_to change{ subject.roles.size } }
50 | end
51 |
52 | context "being a class scoped role to the user" do
53 | it { expect { subject.remove_role("manager".send(param_method), Forum) }.to change{ subject.roles.size }.by(-1) }
54 |
55 | it { should_not have_role("manager", Forum) }
56 | end
57 |
58 | context "being instance scoped role to the user" do
59 | it { expect { subject.remove_role("moderator".send(param_method), Forum) }.to change { subject.roles.size }.by(-1) }
60 |
61 | it { should_not have_role("moderator".send(param_method), Forum.last) }
62 | it { should have_role("moderator".send(param_method), Group.last) }
63 | end
64 |
65 | context "not being a role of the user" do
66 | it { expect { subject.remove_role("manager".send(param_method), Group) }.not_to change { subject.roles.size } }
67 | end
68 | end
69 |
70 | context "removing a instance scoped role", :scope => :instance do
71 | context "being a global role of the user" do
72 | it { expect { subject.remove_role("soldier".send(param_method), Group.first) }.not_to change { subject.roles.size } }
73 | end
74 |
75 | context "being a class scoped role to the user" do
76 | it { expect { subject.remove_role("visitor".send(param_method), Forum.first) }.not_to change { subject.roles.size } }
77 | end
78 |
79 | context "being instance scoped role to the user" do
80 | it { expect { subject.remove_role("moderator".send(param_method), Forum.first) }.to change { subject.roles.size }.by(-1) }
81 |
82 | it { should_not have_role("moderator", Forum.first) }
83 | end
84 |
85 | context "not being a role of the user" do
86 | it { expect { subject.remove_role("anonymous".send(param_method), Forum.first) }.not_to change { subject.roles.size } }
87 | end
88 | end
89 | end
90 | end
91 |
--------------------------------------------------------------------------------
/spec/rolify/shared_examples/shared_examples_for_roles.rb:
--------------------------------------------------------------------------------
1 | require "rolify/shared_contexts"
2 | require "rolify/shared_examples/shared_examples_for_add_role"
3 | require "rolify/shared_examples/shared_examples_for_has_role"
4 | require "rolify/shared_examples/shared_examples_for_only_has_role"
5 | require "rolify/shared_examples/shared_examples_for_has_all_roles"
6 | require "rolify/shared_examples/shared_examples_for_has_any_role"
7 | require "rolify/shared_examples/shared_examples_for_remove_role"
8 | require "rolify/shared_examples/shared_examples_for_finders"
9 |
10 |
11 | shared_examples_for Rolify::Role do
12 | before(:all) do
13 | reset_defaults
14 | Rolify.dynamic_shortcuts = false
15 | rolify_options = { :role_cname => role_class.to_s }
16 | rolify_options[:role_join_table_name] = join_table if defined? join_table
17 | silence_warnings { user_class.rolify rolify_options }
18 | role_class.destroy_all
19 | Forum.resourcify :roles, :role_cname => role_class.to_s
20 | Group.resourcify :roles, :role_cname => role_class.to_s
21 | Organization.resourcify :roles, :role_cname => role_class.to_s
22 | end
23 |
24 | context "in the Instance level" do
25 | before(:all) do
26 | admin = user_class.first
27 | admin.add_role :admin
28 | admin.add_role :moderator, Forum.first
29 | end
30 |
31 | subject { user_class.first }
32 |
33 | [ :grant, :add_role ].each do |method_alias|
34 | it { should respond_to(method_alias.to_sym).with(1).arguments }
35 | it { should respond_to(method_alias.to_sym).with(2).arguments }
36 | end
37 |
38 | it { should respond_to(:has_role?).with(1).arguments }
39 | it { should respond_to(:has_role?).with(2).arguments }
40 |
41 | it { should respond_to(:has_all_roles?) }
42 | it { should respond_to(:has_all_roles?) }
43 |
44 | it { should respond_to(:has_any_role?) }
45 | it { should respond_to(:has_any_role?) }
46 |
47 | [ :has_no_role, :revoke, :remove_role ].each do |method_alias|
48 | it { should respond_to(method_alias.to_sym).with(1).arguments }
49 | it { should respond_to(method_alias.to_sym).with(2).arguments }
50 | end
51 |
52 | it { should_not respond_to(:is_admin?) }
53 | it { should_not respond_to(:is_moderator_of?) }
54 |
55 | describe "#has_role?" do
56 | it_should_behave_like "#has_role?_examples", "String", :to_s
57 | it_should_behave_like "#has_role?_examples", "Symbol", :to_sym
58 | end
59 |
60 | describe "#only_has_role?" do
61 | it_should_behave_like "#only_has_role?_examples", "String", :to_s
62 | it_should_behave_like "#only_has_role?_examples", "Symbol", :to_sym
63 | end
64 |
65 | describe "#has_all_roles?" do
66 | it_should_behave_like "#has_all_roles?_examples", "String", :to_s
67 | it_should_behave_like "#has_all_roles?_examples", "Symbol", :to_sym
68 | end
69 |
70 | describe "#has_any_role?" do
71 | it_should_behave_like "#has_any_role?_examples", "String", :to_s
72 | it_should_behave_like "#has_any_role?_examples", "Symbol", :to_sym
73 | end
74 |
75 | describe "#has_no_role" do
76 | it_should_behave_like "#remove_role_examples", "String", :to_s
77 | it_should_behave_like "#remove_role_examples", "Symbol", :to_sym
78 | end
79 | end
80 |
81 | context "with a new instance" do
82 | let(:user) { user_class.new }
83 |
84 | before do
85 | user.add_role :admin
86 | user.add_role :moderator, Forum.first
87 | end
88 |
89 | subject { user }
90 |
91 | it { should have_role :admin }
92 | # it { should have_role :admin, Forum }
93 | # it { should have_role :admin, :any }
94 | # it { should have_role :moderator, Forum.first }
95 | # it { should have_role :moderator, :any }
96 | # it { should_not have_role :moderator }
97 | # it { should_not have_role :moderator, Forum }
98 | it { subject.has_any_role?(:admin).should be_truthy }
99 | end
100 |
101 | context "on the Class level ", :scope => :mixed do
102 | it_should_behave_like :finders, "String", :to_s
103 | it_should_behave_like :finders, "Symbol", :to_sym
104 | end
105 | end
106 |
--------------------------------------------------------------------------------
/spec/rolify/shared_examples/shared_examples_for_scopes.rb:
--------------------------------------------------------------------------------
1 | require "rolify/shared_contexts"
2 |
3 | shared_examples_for "Role.scopes" do
4 | before do
5 | role_class.destroy_all
6 | end
7 |
8 | subject { user_class.first }
9 |
10 | describe ".global" do
11 | let!(:admin_role) { subject.add_role :admin }
12 | let!(:staff_role) { subject.add_role :staff }
13 |
14 | it { subject.roles.global.should == [ admin_role, staff_role ] }
15 | end
16 |
17 | describe ".class_scoped" do
18 | let!(:manager_role) { subject.add_role :manager, Group }
19 | let!(:moderator_role) { subject.add_role :moderator, Forum }
20 |
21 | it { subject.roles.class_scoped.should =~ [ manager_role, moderator_role ] }
22 | it { subject.roles.class_scoped(Group).should =~ [ manager_role ] }
23 | it { subject.roles.class_scoped(Forum).should =~ [ moderator_role ] }
24 | end
25 |
26 | describe ".instance_scoped" do
27 | let!(:visitor_role) { subject.add_role :visitor, Forum.first }
28 | let!(:zombie_role) { subject.add_role :visitor, Forum.last }
29 | let!(:anonymous_role) { subject.add_role :anonymous, Group.last }
30 |
31 | it { subject.roles.instance_scoped.to_a.entries.should =~ [ visitor_role, zombie_role, anonymous_role ] }
32 | it { subject.roles.instance_scoped(Forum).should =~ [ visitor_role, zombie_role ] }
33 | it { subject.roles.instance_scoped(Forum.first).should =~ [ visitor_role ] }
34 | it { subject.roles.instance_scoped(Forum.last).should =~ [ zombie_role ] }
35 | it { subject.roles.instance_scoped(Group.last).should =~ [ anonymous_role ] }
36 | it { subject.roles.instance_scoped(Group.first).should be_empty }
37 | end
38 | end
--------------------------------------------------------------------------------
/spec/rolify/utils_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper"
2 |
3 | describe Rolify::Utils do
4 | class Harness
5 | extend Rolify::Utils
6 | define_method(:new_method) { |*_args| true }
7 | deprecate :old_method, :new_method
8 | end
9 |
10 | let(:harness) { Harness.new }
11 |
12 | context '#deprecate' do
13 | it 'calls new method with same arguments' do
14 | expect(harness).to receive(:warn).once
15 | expect(harness).to receive(:new_method).once.with(1, 2, 3)
16 | harness.old_method(1, 2, 3)
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | require 'coveralls'
2 | Coveralls.wear_merged!
3 |
4 | require 'rubygems'
5 | require "bundler/setup"
6 |
7 | require 'rolify'
8 | require 'rolify/matchers'
9 | require 'rails'
10 | begin
11 | require 'its'
12 | rescue LoadError
13 | end
14 | require 'database_cleaner'
15 |
16 | ENV['ADAPTER'] ||= 'active_record'
17 |
18 | load File.dirname(__FILE__) + "/support/adapters/#{ENV['ADAPTER']}.rb"
19 | load File.dirname(__FILE__) + '/support/data.rb'
20 |
21 |
22 |
23 | def reset_defaults
24 | Rolify.use_defaults
25 | Rolify.use_mongoid if ENV['ADAPTER'] == 'mongoid'
26 | end
27 |
28 | def provision_user(user, roles)
29 | roles.each do |role|
30 | if role.is_a? Array
31 | user.add_role *role
32 | else
33 | user.add_role role
34 | end
35 | end
36 | user
37 | end
38 |
39 | def silence_warnings(&block)
40 | warn_level = $VERBOSE
41 | $VERBOSE = nil
42 | result = block.call
43 | $VERBOSE = warn_level
44 | result
45 | end
46 |
47 | RSpec.configure do |config|
48 | config.expect_with(:rspec) { |c| c.syntax = [:should, :expect] }
49 |
50 | config.before(:suite) do
51 | DatabaseCleaner.strategy = :truncation
52 | DatabaseCleaner.start
53 | end
54 |
55 | config.after(:suite) do |example|
56 | DatabaseCleaner.clean
57 | end
58 |
59 | end
60 |
--------------------------------------------------------------------------------
/spec/support/adapters/active_record.rb:
--------------------------------------------------------------------------------
1 | load File.dirname(__FILE__) + '/utils/active_record.rb'
2 |
3 | extend_rspec_with_activerecord_specific_matchers
4 | establish_connection
5 |
6 | ActiveRecord::Base.extend Rolify
7 |
8 | load File.dirname(__FILE__) + '/../schema.rb'
9 |
10 | # Standard user and role classes
11 | class User < ActiveRecord::Base
12 | rolify
13 | end
14 |
15 | class Role < ActiveRecord::Base
16 | has_and_belongs_to_many :users, :join_table => :users_roles
17 | has_and_belongs_to_many :strict_users, :join_table => :strict_users_roles
18 |
19 | belongs_to :resource, :polymorphic => true
20 |
21 | extend Rolify::Adapter::Scopes
22 | end
23 |
24 | # Strict user and role classes
25 | class StrictUser < ActiveRecord::Base
26 | rolify strict: true
27 | end
28 |
29 | # Resourcifed and rolifed at the same time
30 | class HumanResource < ActiveRecord::Base
31 | resourcify :resources
32 | rolify
33 | end
34 |
35 | # Custom role and class names
36 | class Customer < ActiveRecord::Base
37 | rolify :role_cname => "Privilege"
38 | end
39 |
40 | class Privilege < ActiveRecord::Base
41 | has_and_belongs_to_many :customers, :join_table => :customers_privileges
42 | belongs_to :resource, :polymorphic => true
43 |
44 | extend Rolify::Adapter::Scopes
45 | end
46 |
47 | # Namespaced models
48 | module Admin
49 | def self.table_name_prefix
50 | 'admin_'
51 | end
52 |
53 | class Moderator < ActiveRecord::Base
54 | rolify :role_cname => "Admin::Right", :role_join_table_name => "moderators_rights"
55 | end
56 |
57 | class Right < ActiveRecord::Base
58 | has_and_belongs_to_many :moderators, :class_name => "Admin::Moderator", :join_table => "moderators_rights"
59 | belongs_to :resource, :polymorphic => true
60 |
61 | extend Rolify::Adapter::Scopes
62 | end
63 | end
64 |
65 |
66 | # Resources classes
67 | class Forum < ActiveRecord::Base
68 | #resourcify done during specs setup to be able to use custom user classes
69 | end
70 |
71 | class Group < ActiveRecord::Base
72 | #resourcify done during specs setup to be able to use custom user classes
73 |
74 | def subgroups
75 | Group.where(:parent_id => id)
76 | end
77 | end
78 |
79 | class Team < ActiveRecord::Base
80 | #resourcify done during specs setup to be able to use custom user classes
81 | self.primary_key = "team_code"
82 |
83 | default_scope { order(:team_code) }
84 | end
85 |
86 | class Organization < ActiveRecord::Base
87 |
88 | end
89 |
90 | class Company < Organization
91 |
92 | end
93 |
--------------------------------------------------------------------------------
/spec/support/adapters/mongoid.rb:
--------------------------------------------------------------------------------
1 | load File.dirname(__FILE__) + '/utils/mongoid.rb'
2 |
3 | load_mongoid_config
4 |
5 | begin
6 | Mongo::Logger.logger.level = ::Logger::FATAL
7 | rescue NameError
8 | end
9 |
10 | ::Mongoid::Document.module_eval do
11 | def self.included(base)
12 | base.extend Rolify
13 | end
14 | end
15 |
16 | Rolify.use_mongoid
17 |
18 | # Standard user and role classes
19 | class User
20 | include Mongoid::Document
21 | default_scope -> { order_by id: 'asc' }
22 |
23 | rolify
24 |
25 | field :login, :type => String
26 | end
27 |
28 | # Standard user and role classes
29 | class StrictUser
30 | include Mongoid::Document
31 | default_scope -> { order_by id: 'asc' }
32 | rolify strict: true
33 |
34 | field :login, :type => String
35 | end
36 |
37 | class Role
38 | include Mongoid::Document
39 | has_and_belongs_to_many :users
40 | has_and_belongs_to_many :strict_users
41 | belongs_to :resource, :polymorphic => true
42 |
43 | field :name, :type => String
44 | index(
45 | {
46 | :name => 1,
47 | :resource_type => 1,
48 | :resource_id => 1
49 | },
50 | { :unique => true }
51 | )
52 |
53 | scopify
54 | end
55 |
56 | # Resourcifed and rolifed at the same time
57 | class HumanResource
58 | include Mongoid::Document
59 | default_scope -> { order_by id: 'asc' }
60 | resourcify :resources
61 | rolify
62 |
63 | field :login, :type => String
64 | end
65 |
66 | #class Power
67 | # include Mongoid::Document
68 | # has_and_belongs_to_many :human_resources
69 | # belongs_to :resource, :polymorphic => true
70 | # scopify
71 | #
72 | # field :name, :type => String
73 | # index(
74 | # {
75 | # :name => 1,
76 | # :resource_type => 1,
77 | # :resource_id => 1
78 | # },
79 | # { :unique => true }
80 | # )
81 | #end
82 |
83 | # Custom role and class names
84 | class Customer
85 | include Mongoid::Document
86 | default_scope -> { order_by id: 'asc' }
87 | rolify :role_cname => "Privilege"
88 |
89 | field :login, :type => String
90 | end
91 |
92 | class Privilege
93 | include Mongoid::Document
94 | default_scope -> { order_by id: 'asc' }
95 | has_and_belongs_to_many :customers
96 | belongs_to :resource, :polymorphic => true
97 | scopify
98 |
99 | field :name, :type => String
100 | index(
101 | {
102 | :name => 1,
103 | :resource_type => 1,
104 | :resource_id => 1
105 | },
106 | { :unique => true }
107 | )
108 | end
109 |
110 | # Namespaced models
111 | module Admin
112 | class Moderator
113 | include Mongoid::Document
114 | default_scope -> { order_by id: 'asc' }
115 | rolify :role_cname => "Admin::Right"
116 |
117 | field :login, :type => String
118 | end
119 |
120 | class Right
121 | include Mongoid::Document
122 | default_scope -> { order_by id: 'asc' }
123 | has_and_belongs_to_many :moderators, :class_name => 'Admin::Moderator'
124 | belongs_to :resource, :polymorphic => true
125 | scopify
126 |
127 | field :name, :type => String
128 | index(
129 | {
130 | :name => 1,
131 | :resource_type => 1,
132 | :resource_id => 1
133 | },
134 | { :unique => true }
135 | )
136 | end
137 | end
138 |
139 | # Resources classes
140 | class Forum
141 | include Mongoid::Document
142 | default_scope -> { order_by id: 'asc' }
143 | #resourcify done during specs setup to be able to use custom user classes
144 |
145 | field :name, :type => String
146 | end
147 |
148 | class Group
149 | include Mongoid::Document
150 | default_scope -> { order_by id: 'asc' }
151 | #resourcify done during specs setup to be able to use custom user classes
152 |
153 | field :name, :type => String
154 | field :parent_id, :type => Integer
155 |
156 | def subgroups
157 | Group.in(:parent_id => _id)
158 | end
159 | end
160 |
161 | class Team
162 | include Mongoid::Document
163 | default_scope -> { order_by id: 'asc' }
164 | #resourcify done during specs setup to be able to use custom user classes
165 |
166 | field :team_code, :type => Integer
167 | field :name, :type => String
168 | end
169 |
170 | class Organization
171 | include Mongoid::Document
172 | default_scope -> { order_by id: 'asc' }
173 | end
174 |
175 | class Company < Organization
176 |
177 | end
178 |
--------------------------------------------------------------------------------
/spec/support/adapters/mongoid_5.yml:
--------------------------------------------------------------------------------
1 | test:
2 | clients:
3 | default:
4 | database: godfather
5 | hosts:
6 | - localhost:27017
7 |
--------------------------------------------------------------------------------
/spec/support/adapters/mongoid_6.yml:
--------------------------------------------------------------------------------
1 | test:
2 | clients:
3 | default:
4 | database: godfather
5 | hosts:
6 | - localhost:27017
7 |
--------------------------------------------------------------------------------
/spec/support/adapters/mongoid_7.yml:
--------------------------------------------------------------------------------
1 | test:
2 | clients:
3 | default:
4 | database: godfather
5 | hosts:
6 | - localhost:27017
7 |
--------------------------------------------------------------------------------
/spec/support/adapters/utils/active_record.rb:
--------------------------------------------------------------------------------
1 | require 'active_record'
2 |
3 | def establish_connection
4 | ActiveRecord::Base.establish_connection(
5 | :adapter => "sqlite3",
6 | :database => ":memory:"
7 | )
8 | end
9 |
10 | def extend_rspec_with_activerecord_specific_matchers
11 | RSpec::Matchers::BuiltIn::OperatorMatcher.register(ActiveRecord::Relation, '=~', RSpec::Matchers::BuiltIn::ContainExactly)
12 | end
13 |
--------------------------------------------------------------------------------
/spec/support/adapters/utils/mongoid.rb:
--------------------------------------------------------------------------------
1 | require 'mongoid'
2 |
3 | def mongoid_major_version
4 | Mongoid::VERSION.split('.').first.to_i
5 | end
6 |
7 | def mongoid_config
8 | "spec/support/adapters/mongoid_#{mongoid_major_version}.yml"
9 | end
10 |
11 | def load_mongoid_config
12 | Mongoid.load!(mongoid_config, :test)
13 | end
14 |
--------------------------------------------------------------------------------
/spec/support/data.rb:
--------------------------------------------------------------------------------
1 | # Users
2 | [ User, Customer, Admin::Moderator, StrictUser ].each do |user|
3 | user.destroy_all
4 |
5 | user.create(:login => "admin")
6 | user.create(:login => "moderator")
7 | user.create(:login => "god")
8 | user.create(:login => "zombie")
9 | end
10 |
11 | # Roles
12 | [ Role, Privilege, Admin::Right ].each do |role|
13 | role.destroy_all
14 | end
15 |
16 | # Resources
17 | Forum.create(:name => "forum 1")
18 | Forum.create(:name => "forum 2")
19 | Forum.create(:name => "forum 3")
20 |
21 | Group.create(:name => "group 1")
22 | Group.create(:name => "group 2")
23 |
24 | Team.create(:team_code => "1", :name => "PSG")
25 | Team.create(:team_code => "2", :name => "MU")
26 |
27 | Organization.create
28 | Company.create
29 |
--------------------------------------------------------------------------------
/spec/support/schema.rb:
--------------------------------------------------------------------------------
1 | ActiveRecord::Schema.define do
2 | self.verbose = false
3 |
4 | [ :roles, :privileges, :admin_rights ].each do |table|
5 | create_table(table) do |t|
6 | t.string :name
7 | t.references :resource, :polymorphic => true
8 |
9 | t.timestamps null: false
10 | end
11 | end
12 |
13 | [ :users, :human_resources, :customers, :admin_moderators, :strict_users ].each do |table|
14 | create_table(table) do |t|
15 | t.string :login
16 | end
17 | end
18 |
19 | create_table(:users_roles, :id => false) do |t|
20 | t.references :user
21 | t.references :role
22 | end
23 |
24 | create_table(:strict_users_roles, :id => false) do |t|
25 | t.references :strict_user
26 | t.references :role
27 | end
28 |
29 | create_table(:human_resources_roles, :id => false) do |t|
30 | t.references :human_resource
31 | t.references :role
32 | end
33 |
34 | create_table(:customers_privileges, :id => false) do |t|
35 | t.references :customer
36 | t.references :privilege
37 | end
38 |
39 | create_table(:moderators_rights, :id => false) do |t|
40 | t.references :moderator
41 | t.references :right
42 | end
43 |
44 | create_table(:forums) do |t|
45 | t.string :name
46 | end
47 |
48 | create_table(:groups) do |t|
49 | t.integer :parent_id
50 | t.string :name
51 | end
52 |
53 | create_table(:teams, :id => false) do |t|
54 | t.primary_key :team_code
55 | t.string :name
56 | end
57 |
58 | create_table(:organizations) do |t|
59 | t.string :type
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/spec/support/stream_helpers.rb:
--------------------------------------------------------------------------------
1 | module StreamHelpers
2 | def capture(stream)
3 | stream = stream.to_s
4 | captured_stream = Tempfile.new(stream)
5 | stream_io = eval("$#{stream}")
6 | origin_stream = stream_io.dup
7 | stream_io.reopen(captured_stream)
8 |
9 | yield
10 |
11 | stream_io.rewind
12 | return captured_stream.read
13 | ensure
14 | captured_stream.close
15 | captured_stream.unlink
16 | stream_io.reopen(origin_stream)
17 | end
18 | end
19 |
--------------------------------------------------------------------------------