guise 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -1,13 +1,33 @@
1
+ sudo: false
2
+ cache: bundler
1
3
  rvm:
2
- - 1.9.3
3
4
  - 2.0.0
4
- - 2.1.0
5
- - jruby-19mode
5
+ - 2.1.8
6
+ - 2.2.4
7
+ - 2.3.0
6
8
  gemfile:
7
9
  - gemfiles/3.1.gemfile
8
10
  - gemfiles/3.2.gemfile
9
11
  - gemfiles/4.0.gemfile
10
- install: 'travis_retry bundle install -j 4'
12
+ - gemfiles/4.1.gemfile
13
+ - gemfiles/4.2.gemfile
14
+ - gemfiles/5.0.gemfile
11
15
  script: 'bundle exec rake'
12
16
  env:
13
- secure: "I0cDQLpPt8NlOswL5Vomim4gb+NHvLW+0mPf2iimP1gTE5C+3PnoomCRx//0CyI/NSMhjrHg8DbrkvtBCfAYinrgzCi3cUkofi0zn5T6GaGUfYQz4Bmh7fmvppRVpVDCSXMOzOSYYEXBnie5b865BYTDrt1U3aM8qvq7pd/XOXg="
17
+ global:
18
+ # Code Climate coverage reporting
19
+ - secure: "I0cDQLpPt8NlOswL5Vomim4gb+NHvLW+0mPf2iimP1gTE5C+3PnoomCRx//0CyI/NSMhjrHg8DbrkvtBCfAYinrgzCi3cUkofi0zn5T6GaGUfYQz4Bmh7fmvppRVpVDCSXMOzOSYYEXBnie5b865BYTDrt1U3aM8qvq7pd/XOXg="
20
+ matrix:
21
+ exclude:
22
+ - rvm: 2.2.4
23
+ gemfile: gemfiles/3.1.gemfile
24
+ - rvm: 2.3.0
25
+ gemfile: gemfiles/3.1.gemfile
26
+ - rvm: 2.2.4
27
+ gemfile: gemfiles/3.2.gemfile
28
+ - rvm: 2.0.0
29
+ gemfile: gemfiles/5.0.gemfile
30
+ - rvm: 2.1.8
31
+ gemfile: gemfiles/5.0.gemfile
32
+ allow_failures:
33
+ - gemfile: gemfiles/5.0.gemfile
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --title "paraphrase Documentation" --protected -M github-markup -M redcarpet
data/Appraisals CHANGED
@@ -22,3 +22,8 @@ appraise '4.2' do
22
22
  gem 'activerecord', '~> 4.2.0'
23
23
  gem 'activesupport', '~> 4.2.0'
24
24
  end
25
+
26
+ appraise '5.0' do
27
+ gem 'activerecord', '~> 5.0.0.beta'
28
+ gem 'activesupport', '~> 5.0.0.beta'
29
+ end
data/README.md CHANGED
@@ -3,14 +3,106 @@
3
3
  [![Build Status](https://travis-ci.org/ecbypi/guise.png?branch=master)](https://travis-ci.org/ecbypi/guise)
4
4
  [![Code Climate](https://codeclimate.com/github/ecbypi/guise.png)](https://codeclimate.com/github/ecbypi/guise)
5
5
 
6
+ A typical, quick-and-easy role management system involves `users` and `roles`
7
+ tables with a join table between them to determine membership to a role:
6
8
 
7
- An alternative to storing role resources in the database.
9
+ ```ruby
10
+ class User < ActiveRecord::Base
11
+ has_many :user_roles
12
+ has_many :roles, through: :user_roles
13
+ end
14
+
15
+ class UserRole < ActiveRecord::Bae
16
+ belongs_to :user
17
+ belongs_to :role
18
+ end
19
+
20
+ class Role < ActiveRecord::Base
21
+ has_many :user_roles
22
+ has_many :users, through: :user_roles
23
+ end
24
+ ```
25
+
26
+ A problem with this is that in simple setups, application behavior tends to be
27
+ hard-coded to rely on the existence of a database record representing the role
28
+ object in the `roles` table.
29
+
30
+ `guise` de-normalizes the above setup by storing the name of the role as a
31
+ column in what would be the join table between `users` and `roles`. The allowed
32
+ values are limited to the values defined in a declaration on the model that is
33
+ meant to have different roles.
34
+
35
+ Given `User` and `Role` models where the `Role` model has a `value` column.
36
+
37
+ ```ruby
38
+ class User < ActiveRecord::Base
39
+ end
40
+
41
+ class Role < ActiveRecord::Base
42
+ end
43
+ ```
44
+
45
+ By adding the following method call to `has_guises` to `User` and `guise_for` to
46
+ `Role`:
47
+
48
+ ```ruby
49
+ class User < ActiveRecord::Base
50
+ has_guises :DeskWorker, :MailForwarder, association: :roles, attribute: :value
51
+ end
52
+
53
+ class Role < ActiveRecord::Base
54
+ guise_for :User
55
+ end
56
+ ```
8
57
 
9
- `guise` uses a `has_many` association to store type information instead of
10
- using `has_many :through` or `has_and_belongs_to_many.` The `has_many` association
11
- stores the role or type information as a string representing the class name.
58
+ The equivalent associations, model scopes and validations are configured:
12
59
 
13
- If effect, `guise` enables 'multi-table-inheritance'.
60
+ ```ruby
61
+ class User < ActiveRecord::Base
62
+ has_many :roles
63
+
64
+ scope :desk_workers, -> { joins(:roles).where(roles: { value: "DeskWorker" }) }
65
+ scope :mail_forwarders, -> { joins(:roles).where(roles: { value: "MailForwarder" }) }
66
+
67
+ def has_role?(value)
68
+ roles.detect { |role| role.value == value }
69
+ end
70
+
71
+ def has_roles?(*values)
72
+ values.all? { |value| has_role?(value)
73
+ end
74
+
75
+ def has_any_roles?(*values)
76
+ values.any? { |value| has_role?(value)
77
+ end
78
+
79
+ def desk_worker?
80
+ has_role?("DeskWorker")
81
+ end
82
+
83
+ def mail_forwarder?
84
+ has_role?("MailForwarder")
85
+ end
86
+ end
87
+
88
+ class Role < ActiveRecord::Base
89
+ belongs_to :user
90
+
91
+ scope :desk_workers, -> { where(value: "DeskWorker") }
92
+ scope :mail_forwarders, -> { where(value: "MailForwarder") }
93
+
94
+ validates(
95
+ :value,
96
+ presence: true,
97
+ uniqueness: { scope: :user_id },
98
+ inclusion: { in: %w( DeskWorker MailForwarder ) }
99
+ )
100
+ end
101
+ ```
102
+
103
+ This allows filtering users by role / type and assigning records a role without
104
+ requiring an existing record in the database. The predicate methods can be used
105
+ for permissions / authorization.
14
106
 
15
107
  ## Installation
16
108
 
@@ -20,7 +112,7 @@ Add this line to your application's Gemfile:
20
112
  gem 'guise'
21
113
  ```
22
114
 
23
- And then execute:
115
+ Then execute:
24
116
 
25
117
  ```
26
118
  $ bundle
@@ -32,23 +124,25 @@ Or install it yourself as:
32
124
  $ gem install guise
33
125
  ```
34
126
 
35
-
36
127
  ## Usage
37
128
 
38
129
  Create a table to store your type information:
39
130
 
40
131
  ```
41
- rails generate model user_role user:references title:string:uniq
132
+ rails generate model role user:references value:string:uniq
42
133
  rake db:migrate
43
134
  ```
44
135
 
136
+ It is recommended to add an index on the foreign key and guise attribute. In
137
+ this case the columns are `user_id` and `value`.
138
+
45
139
  Then add `has_guises` to your model. This will setup the `has_many` association
46
140
  for you. It requires the name of the association and name of the column that
47
- the sublcass name will be stored in.
141
+ the subclass name will be stored in.
48
142
 
49
143
  ```ruby
50
144
  class User < ActiveRecord::Base
51
- has_guises :DeskWorker, :MailForwarder, association: :user_roles, attribute: :title
145
+ has_guises :DeskWorker, :MailForwarder, association: :roles, attribute: :value
52
146
  end
53
147
  ```
54
148
 
@@ -72,7 +166,11 @@ This method does the following:
72
166
  * Validates the column storing the name of the guise in the list supplied is
73
167
  unique to the resource it belongs to and is one of the provided names.
74
168
 
75
- To add a class for each guise, call `:guise_of` in a subclass:
169
+ ### Role Subclasses
170
+
171
+ If using `User.<guise_scope>` is too tedious, it is possible to setup
172
+ subclasses to represent each value referenced in `has_guises` using the
173
+ `guise_of` method:
76
174
 
77
175
  ```ruby
78
176
  class DeskWorker < User
@@ -80,25 +178,21 @@ class DeskWorker < User
80
178
  end
81
179
  ```
82
180
 
83
- This adds the following to the `DeskWorker` class:
181
+ This is equivalent to the following:
84
182
 
85
183
  ```ruby
86
184
  class DeskWorker < User
87
- default_scope -> { joins(:user_roles).where(user_roles: { title: 'DeskWorker'}) }
185
+ default_scope -> { joins(:roles).where(roles: { value: 'DeskWorker'}) }
88
186
 
89
187
  after_initialize do
90
- self.guises.build(title: 'DeskWorker')
91
- end
92
-
93
- after_create do
94
- self.guises.create(title: 'DeskWorker')
188
+ self.guises.build(value: 'DeskWorker')
95
189
  end
96
190
  end
97
191
  ```
98
192
 
99
193
  To scope the association class to a guise, use `scoped_guise_for`. The name of
100
- the class must be the guise it represents combined with the name of the parent
101
- class.
194
+ the class must be `<guise_value><association_class_name>` (i.e. the guise it
195
+ represents combined with the name of the parent class.
102
196
 
103
197
  ```ruby
104
198
  class DeskWorkerUserRole < UserRole
@@ -110,23 +204,20 @@ This sets up the class as follows:
110
204
 
111
205
  ```ruby
112
206
  class DeskWorkerUserRole < UserRole
113
- default_scope -> { where(title: 'DeskWorker') }
207
+ default_scope -> { where(value: "DeskWorker") }
114
208
 
115
209
  after_initialize do
116
- self.title = 'DeskWorker'
117
- end
118
-
119
- before_create do
120
- self.title = 'DeskWorker'
210
+ self.value = "DeskWorker"
121
211
  end
122
212
  end
123
213
  ```
124
214
 
125
215
  ### Customization
126
216
 
127
- If the association doesn't standard association assumptions, you can pass in
128
- the options for `has_many` into `has_guises`. The same applies to `guise_for`
129
- with the addition that you can specify not to validate attributes.
217
+ If the association doesn't standard association assumptions made by
218
+ `activerecord`, you can pass in the options for `has_many` into `has_guises`.
219
+ The same applies to `guise_for` with the addition that you can specify not to
220
+ validate attributes.
130
221
 
131
222
  ```ruby
132
223
  class Person < ActiveRecord::Base
data/gemfiles/3.1.gemfile CHANGED
@@ -5,4 +5,4 @@ source "https://rubygems.org"
5
5
  gem "activerecord", "~> 3.1.0"
6
6
  gem "activesupport", "~> 3.1.0"
7
7
 
8
- gemspec :path=>"../"
8
+ gemspec :path => "../"
@@ -19,48 +19,53 @@ GEM
19
19
  tzinfo (~> 0.3.29)
20
20
  activesupport (3.1.12)
21
21
  multi_json (~> 1.0)
22
- appraisal (0.5.2)
22
+ appraisal (2.1.0)
23
23
  bundler
24
24
  rake
25
+ thor (>= 0.14.0)
25
26
  arel (2.2.3)
26
27
  builder (3.0.4)
27
- codeclimate-test-reporter (0.4.0)
28
+ byebug (5.0.0)
29
+ columnize (= 0.9.0)
30
+ codeclimate-test-reporter (0.4.8)
28
31
  simplecov (>= 0.7.1, < 1.0.0)
29
32
  coderay (1.1.0)
33
+ columnize (0.9.0)
30
34
  diff-lcs (1.2.5)
31
35
  docile (1.1.5)
32
- factory_girl (4.4.0)
33
- activesupport (>= 3.0.0)
34
- i18n (0.6.11)
36
+ i18n (0.7.0)
37
+ json (1.8.3)
35
38
  method_source (0.8.2)
36
- multi_json (1.10.1)
37
- pry (0.10.1)
39
+ multi_json (1.11.2)
40
+ pry (0.10.3)
38
41
  coderay (~> 1.1.0)
39
42
  method_source (~> 0.8.1)
40
43
  slop (~> 3.4)
41
- rake (10.3.2)
42
- rspec (3.0.0)
43
- rspec-core (~> 3.0.0)
44
- rspec-expectations (~> 3.0.0)
45
- rspec-mocks (~> 3.0.0)
46
- rspec-core (3.0.4)
47
- rspec-support (~> 3.0.0)
48
- rspec-expectations (3.0.4)
44
+ rake (10.4.2)
45
+ redcarpet (3.3.3)
46
+ rspec (3.4.0)
47
+ rspec-core (~> 3.4.0)
48
+ rspec-expectations (~> 3.4.0)
49
+ rspec-mocks (~> 3.4.0)
50
+ rspec-core (3.4.0)
51
+ rspec-support (~> 3.4.0)
52
+ rspec-expectations (3.4.0)
49
53
  diff-lcs (>= 1.2.0, < 2.0)
50
- rspec-support (~> 3.0.0)
51
- rspec-mocks (3.0.4)
52
- rspec-support (~> 3.0.0)
53
- rspec-support (3.0.4)
54
- shoulda-matchers (2.6.2)
55
- activesupport (>= 3.0.0)
56
- simplecov (0.9.0)
54
+ rspec-support (~> 3.4.0)
55
+ rspec-mocks (3.4.0)
56
+ diff-lcs (>= 1.2.0, < 2.0)
57
+ rspec-support (~> 3.4.0)
58
+ rspec-support (3.4.0)
59
+ simplecov (0.10.0)
57
60
  docile (~> 1.1.0)
58
- multi_json
59
- simplecov-html (~> 0.8.0)
60
- simplecov-html (0.8.0)
61
+ json (~> 1.8)
62
+ simplecov-html (~> 0.10.0)
63
+ simplecov-html (0.10.0)
61
64
  slop (3.6.0)
62
- sqlite3 (1.3.9)
63
- tzinfo (0.3.41)
65
+ sqlite3 (1.3.11)
66
+ thor (0.19.1)
67
+ tzinfo (0.3.45)
68
+ yard (0.8.7.6)
64
69
 
65
70
  PLATFORMS
66
71
  ruby
@@ -68,12 +73,16 @@ PLATFORMS
68
73
  DEPENDENCIES
69
74
  activerecord (~> 3.1.0)
70
75
  activesupport (~> 3.1.0)
71
- appraisal (~> 0.5)
76
+ appraisal (>= 1.0)
77
+ byebug (~> 5.0)
72
78
  codeclimate-test-reporter (~> 0.3)
73
- factory_girl (~> 4.4)
74
79
  guise!
75
80
  pry (~> 0.9)
76
81
  rake (~> 10.1)
82
+ redcarpet (~> 3.2)
77
83
  rspec (~> 3.0)
78
- shoulda-matchers (~> 2.5)
79
84
  sqlite3 (~> 1.3)
85
+ yard (~> 0.8)
86
+
87
+ BUNDLED WITH
88
+ 1.10.6
data/gemfiles/3.2.gemfile CHANGED
@@ -5,4 +5,4 @@ source "https://rubygems.org"
5
5
  gem "activerecord", "~> 3.2.0"
6
6
  gem "activesupport", "~> 3.2.0"
7
7
 
8
- gemspec :path=>"../"
8
+ gemspec :path => "../"
@@ -8,59 +8,64 @@ PATH
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activemodel (3.2.13)
12
- activesupport (= 3.2.13)
11
+ activemodel (3.2.22)
12
+ activesupport (= 3.2.22)
13
13
  builder (~> 3.0.0)
14
- activerecord (3.2.13)
15
- activemodel (= 3.2.13)
16
- activesupport (= 3.2.13)
14
+ activerecord (3.2.22)
15
+ activemodel (= 3.2.22)
16
+ activesupport (= 3.2.22)
17
17
  arel (~> 3.0.2)
18
18
  tzinfo (~> 0.3.29)
19
- activesupport (3.2.13)
20
- i18n (= 0.6.1)
19
+ activesupport (3.2.22)
20
+ i18n (~> 0.6, >= 0.6.4)
21
21
  multi_json (~> 1.0)
22
- appraisal (0.5.2)
22
+ appraisal (2.1.0)
23
23
  bundler
24
24
  rake
25
- arel (3.0.2)
25
+ thor (>= 0.14.0)
26
+ arel (3.0.3)
26
27
  builder (3.0.4)
27
- codeclimate-test-reporter (0.4.0)
28
+ byebug (5.0.0)
29
+ columnize (= 0.9.0)
30
+ codeclimate-test-reporter (0.4.8)
28
31
  simplecov (>= 0.7.1, < 1.0.0)
29
32
  coderay (1.1.0)
33
+ columnize (0.9.0)
30
34
  diff-lcs (1.2.5)
31
35
  docile (1.1.5)
32
- factory_girl (4.4.0)
33
- activesupport (>= 3.0.0)
34
- i18n (0.6.1)
36
+ i18n (0.7.0)
37
+ json (1.8.3)
35
38
  method_source (0.8.2)
36
- multi_json (1.10.1)
37
- pry (0.10.1)
39
+ multi_json (1.11.2)
40
+ pry (0.10.3)
38
41
  coderay (~> 1.1.0)
39
42
  method_source (~> 0.8.1)
40
43
  slop (~> 3.4)
41
- rake (10.3.2)
42
- rspec (3.0.0)
43
- rspec-core (~> 3.0.0)
44
- rspec-expectations (~> 3.0.0)
45
- rspec-mocks (~> 3.0.0)
46
- rspec-core (3.0.4)
47
- rspec-support (~> 3.0.0)
48
- rspec-expectations (3.0.4)
44
+ rake (10.4.2)
45
+ redcarpet (3.3.3)
46
+ rspec (3.4.0)
47
+ rspec-core (~> 3.4.0)
48
+ rspec-expectations (~> 3.4.0)
49
+ rspec-mocks (~> 3.4.0)
50
+ rspec-core (3.4.0)
51
+ rspec-support (~> 3.4.0)
52
+ rspec-expectations (3.4.0)
49
53
  diff-lcs (>= 1.2.0, < 2.0)
50
- rspec-support (~> 3.0.0)
51
- rspec-mocks (3.0.4)
52
- rspec-support (~> 3.0.0)
53
- rspec-support (3.0.4)
54
- shoulda-matchers (2.6.2)
55
- activesupport (>= 3.0.0)
56
- simplecov (0.9.0)
54
+ rspec-support (~> 3.4.0)
55
+ rspec-mocks (3.4.0)
56
+ diff-lcs (>= 1.2.0, < 2.0)
57
+ rspec-support (~> 3.4.0)
58
+ rspec-support (3.4.0)
59
+ simplecov (0.10.0)
57
60
  docile (~> 1.1.0)
58
- multi_json
59
- simplecov-html (~> 0.8.0)
60
- simplecov-html (0.8.0)
61
+ json (~> 1.8)
62
+ simplecov-html (~> 0.10.0)
63
+ simplecov-html (0.10.0)
61
64
  slop (3.6.0)
62
- sqlite3 (1.3.9)
63
- tzinfo (0.3.41)
65
+ sqlite3 (1.3.11)
66
+ thor (0.19.1)
67
+ tzinfo (0.3.45)
68
+ yard (0.8.7.6)
64
69
 
65
70
  PLATFORMS
66
71
  ruby
@@ -68,12 +73,16 @@ PLATFORMS
68
73
  DEPENDENCIES
69
74
  activerecord (~> 3.2.0)
70
75
  activesupport (~> 3.2.0)
71
- appraisal (~> 0.5)
76
+ appraisal (>= 1.0)
77
+ byebug (~> 5.0)
72
78
  codeclimate-test-reporter (~> 0.3)
73
- factory_girl (~> 4.4)
74
79
  guise!
75
80
  pry (~> 0.9)
76
81
  rake (~> 10.1)
82
+ redcarpet (~> 3.2)
77
83
  rspec (~> 3.0)
78
- shoulda-matchers (~> 2.5)
79
84
  sqlite3 (~> 1.3)
85
+ yard (~> 0.8)
86
+
87
+ BUNDLED WITH
88
+ 1.10.6