enumerations 2.2.3 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6bff6ddbd1cfb803b3463c11796daf3c81f1c741
4
- data.tar.gz: 20a258a2ed4129ed92b044f2933fb366d45aba6e
2
+ SHA256:
3
+ metadata.gz: 662c2ae6e522b2f97a03e6dc0c848b8d6d45d77000f36ca5f08a3b6dc4ce6433
4
+ data.tar.gz: 8d5a3f9e31fe5f1bf514e0b7deb2c6269a6acce629f14d18078110165994cda2
5
5
  SHA512:
6
- metadata.gz: 584c186148b1038d4aadbdd1ee4cb230ee32b40332aca1888933a2ac2813ad61dd356eb548701ab52a10a9e426122ba70e6022cc6254001431b3fd2e51c3d198
7
- data.tar.gz: 7048a1acf02560a3311d3956d09ce76d25651a631bf7b4a169d7513d28f4f656142ec93a0f44fff6667022d8651f07cdc81104b2eab969c5dabb0468c65bc72e
6
+ metadata.gz: d9b80ce8946b5614c07d15e7625f366186bfdbb463b807faa4b18458af32ea69c623214ac87b83f165d683e49047d1fdada5222ac299b8d2bb53d3c3ca8d2e3d
7
+ data.tar.gz: b05ffbd75a2fd6744c71b211aa966c72e74cba905a73cd4efdbb1dde43a3809314d0da4be8626609b9b761fa85f2b96872d8eb01826b6c27a4ce78226999f0cb
data/.rubocop.yml ADDED
@@ -0,0 +1,8 @@
1
+ LineLength:
2
+ Max: 100
3
+
4
+ Documentation:
5
+ Enabled: False
6
+
7
+ Style/SymbolArray:
8
+ Enabled: False
data/CHANGELOG.md ADDED
@@ -0,0 +1,126 @@
1
+ # Change Log
2
+
3
+ ## [v2.4.0](https://github.com/infinum/enumerations/tree/v2.4.0) (2019-02-07)
4
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v2.3.3...v2.4.0)
5
+
6
+ **Implemented enhancements:**
7
+
8
+ - Add `translate_attributes` configuration option to disable translation of attributes
9
+
10
+ ## [v2.3.3](https://github.com/infinum/enumerations/tree/v2.3.1) (2019-19-09)
11
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v2.3.2...v2.3.3)
12
+
13
+ ## [v2.3.2](https://github.com/infinum/enumerations/tree/v2.3.1) (2019-03-27)
14
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v2.3.1...v2.3.2)
15
+
16
+ ## [v2.3.1](https://github.com/infinum/enumerations/tree/v2.3.1) (2017-09-08)
17
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v2.3.0...v2.3.1)
18
+
19
+ ## [v2.3.0](https://github.com/infinum/enumerations/tree/v2.3.0) (2017-09-08)
20
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v2.2.3...v2.3.0)
21
+
22
+ **Implemented enhancements:**
23
+
24
+ - Setting attribute to nil if enumeration value is unknown - surprising? [\#35](https://github.com/infinum/enumerations/issues/35)
25
+ - Add `without` methods [\#31](https://github.com/infinum/enumerations/issues/31)
26
+ - Add methods with '?' [\#19](https://github.com/infinum/enumerations/issues/19)
27
+ - Add with\_enumeration\(enumeration\) scope [\#18](https://github.com/infinum/enumerations/issues/18)
28
+
29
+ **Closed issues:**
30
+
31
+ - Not assigning the enumeration when tweaking the primary and foreign key [\#32](https://github.com/infinum/enumerations/issues/32)
32
+ - Undocumented feature - can't set attribute if it's not in the enumeration [\#30](https://github.com/infinum/enumerations/issues/30)
33
+
34
+ **Merged pull requests:**
35
+
36
+ - Feature/raising error on invalid enumeration value [\#38](https://github.com/infinum/enumerations/pull/38) ([PetarCurkovic](https://github.com/PetarCurkovic))
37
+ - Bugfix/config options [\#37](https://github.com/infinum/enumerations/pull/37) ([PetarCurkovic](https://github.com/PetarCurkovic))
38
+ - Feature/predicate methods for attributes [\#36](https://github.com/infinum/enumerations/pull/36) ([PetarCurkovic](https://github.com/PetarCurkovic))
39
+ - Feature/without scopes [\#34](https://github.com/infinum/enumerations/pull/34) ([PetarCurkovic](https://github.com/PetarCurkovic))
40
+ - Feature/with enumeration scope [\#33](https://github.com/infinum/enumerations/pull/33) ([PetarCurkovic](https://github.com/PetarCurkovic))
41
+
42
+ ## [v2.2.3](https://github.com/infinum/enumerations/tree/v2.2.3) (2017-03-17)
43
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v2.2.2...v2.2.3)
44
+
45
+ ## [v2.2.2](https://github.com/infinum/enumerations/tree/v2.2.2) (2017-03-01)
46
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v2.2.1...v2.2.2)
47
+
48
+ **Implemented enhancements:**
49
+
50
+ - Add id and quoted\_id methods [\#20](https://github.com/infinum/enumerations/issues/20)
51
+
52
+ **Fixed bugs:**
53
+
54
+ - Error when assiging nil [\#21](https://github.com/infinum/enumerations/issues/21)
55
+
56
+ **Closed issues:**
57
+
58
+ - upgrade to new codeclimate reporter [\#25](https://github.com/infinum/enumerations/issues/25)
59
+ - Giving a invalid enum name raises an error [\#23](https://github.com/infinum/enumerations/issues/23)
60
+ - Make second argument to Enumerations.value optional [\#22](https://github.com/infinum/enumerations/issues/22)
61
+
62
+ **Merged pull requests:**
63
+
64
+ - Make second argument to Enumerations.value optional [\#28](https://github.com/infinum/enumerations/pull/28) ([domagojnakic](https://github.com/domagojnakic))
65
+ - Fix giving invalid enum name raises error [\#27](https://github.com/infinum/enumerations/pull/27) ([domagojnakic](https://github.com/domagojnakic))
66
+ - Replaced CodeClimate::TestReporter with SimpleCov [\#26](https://github.com/infinum/enumerations/pull/26) ([PetarCurkovic](https://github.com/PetarCurkovic))
67
+ - Add migration readme [\#24](https://github.com/infinum/enumerations/pull/24) ([Narayanan170](https://github.com/Narayanan170))
68
+
69
+ ## [v2.2.1](https://github.com/infinum/enumerations/tree/v2.2.1) (2016-09-20)
70
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v2.2.0...v2.2.1)
71
+
72
+ **Closed issues:**
73
+
74
+ - Add option to store foreign\_key as string [\#14](https://github.com/infinum/enumerations/issues/14)
75
+
76
+ **Merged pull requests:**
77
+
78
+ - Bugfix/empty initializer [\#17](https://github.com/infinum/enumerations/pull/17) ([PetarCurkovic](https://github.com/PetarCurkovic))
79
+
80
+ ## [v2.2.0](https://github.com/infinum/enumerations/tree/v2.2.0) (2016-09-19)
81
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v2.1.0...v2.2.0)
82
+
83
+ **Merged pull requests:**
84
+
85
+ - Feature/remove [\#16](https://github.com/infinum/enumerations/pull/16) ([PetarCurkovic](https://github.com/PetarCurkovic))
86
+
87
+ ## [v2.1.0](https://github.com/infinum/enumerations/tree/v2.1.0) (2016-08-19)
88
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v2.0.0...v2.1.0)
89
+
90
+ **Closed issues:**
91
+
92
+ - Moved all back to Base [\#9](https://github.com/infinum/enumerations/issues/9)
93
+ - I18n.locale [\#6](https://github.com/infinum/enumerations/issues/6)
94
+ - Case statement [\#3](https://github.com/infinum/enumerations/issues/3)
95
+
96
+ **Merged pull requests:**
97
+
98
+ - Feature/where filtering [\#13](https://github.com/infinum/enumerations/pull/13) ([PetarCurkovic](https://github.com/PetarCurkovic))
99
+ - Feature/localized attributes [\#12](https://github.com/infinum/enumerations/pull/12) ([PetarCurkovic](https://github.com/PetarCurkovic))
100
+
101
+ ## [v2.0.0](https://github.com/infinum/enumerations/tree/v2.0.0) (2016-08-17)
102
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v1.3.0...v2.0.0)
103
+
104
+ **Merged pull requests:**
105
+
106
+ - Update version to 2.0.0 [\#11](https://github.com/infinum/enumerations/pull/11) ([PetarCurkovic](https://github.com/PetarCurkovic))
107
+ - Refactor [\#10](https://github.com/infinum/enumerations/pull/10) ([PetarCurkovic](https://github.com/PetarCurkovic))
108
+
109
+ ## [v1.3.0](https://github.com/infinum/enumerations/tree/v1.3.0) (2016-08-11)
110
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v1.1.1...v1.3.0)
111
+
112
+ ## [v1.1.1](https://github.com/infinum/enumerations/tree/v1.1.1) (2016-06-07)
113
+ [Full Changelog](https://github.com/infinum/enumerations/compare/v1.1.0...v1.1.1)
114
+
115
+ **Merged pull requests:**
116
+
117
+ - Bugfix/value-id [\#8](https://github.com/infinum/enumerations/pull/8) ([nikajukic](https://github.com/nikajukic))
118
+ - Document configuration options [\#7](https://github.com/infinum/enumerations/pull/7) ([stankec](https://github.com/stankec))
119
+ - Refactoring all around [\#5](https://github.com/infinum/enumerations/pull/5) ([janvarljen](https://github.com/janvarljen))
120
+ - Added value method and support for custom attributes [\#4](https://github.com/infinum/enumerations/pull/4) ([PetarCurkovic](https://github.com/PetarCurkovic))
121
+ - Some refactoring and updated README [\#2](https://github.com/infinum/enumerations/pull/2) ([PetarCurkovic](https://github.com/PetarCurkovic))
122
+
123
+ ## [v1.1.0](https://github.com/infinum/enumerations/tree/v1.1.0) (2012-08-19)
124
+ **Merged pull requests:**
125
+
126
+ - Gemspec. [\#1](https://github.com/infinum/enumerations/pull/1) ([neektza](https://github.com/neektza))
File without changes
@@ -2,11 +2,11 @@ Enumerations
2
2
  ============
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/enumerations.svg)](https://badge.fury.io/rb/enumerations)
5
- [![Code Climate](https://codeclimate.com/github/infinum/enumerations/badges/gpa.svg)](https://codeclimate.com/github/infinum/enumerations)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/c3b96c5afceaa9be2173/maintainability)](https://codeclimate.com/github/infinum/enumerations/maintainability)
6
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/c3b96c5afceaa9be2173/test_coverage)](https://codeclimate.com/github/infinum/enumerations/test_coverage)
6
7
  [![Build Status](https://semaphoreci.com/api/v1/infinum/enumerations/branches/master/shields_badge.svg)](https://semaphoreci.com/infinum/enumerations)
7
- [![Test Coverage](https://codeclimate.com/github/infinum/enumerations/badges/coverage.svg)](https://codeclimate.com/github/infinum/enumerations/coverage)
8
8
 
9
- Rails plugin for enumerations in ActiveRecord models.
9
+ Rails plugin for Enumerations in ActiveRecord models.
10
10
 
11
11
  Installation
12
12
  ============
@@ -83,6 +83,8 @@ Or you can set enumerations by `symbol`:
83
83
  @post.status = Status.find(:draft)
84
84
  ```
85
85
 
86
+ > If you try to set value that is not an Enumeration value (except `nil`), you will get an `Enumerations::InvalidValueError` exception. You can turn this exception off in configuration.
87
+
86
88
  Also, you can set enumeration value like this:
87
89
 
88
90
  ```ruby
@@ -175,6 +177,14 @@ following format:
175
177
 
176
178
  ```ruby
177
179
  with_#{enumeration_name}_#{enumeration_value_name}
180
+ without_#{enumeration_name}_#{enumeration_value_name}
181
+ ```
182
+
183
+ or you can use the following scope and pass an array of enumerations:
184
+
185
+ ```ruby
186
+ with_#{enumeration_name}(enumeration, ...)
187
+ without_#{enumeration_name}(enumeration, ...)
178
188
  ```
179
189
 
180
190
  Examples:
@@ -185,7 +195,13 @@ class Post < ActiveRecord::Base
185
195
  end
186
196
 
187
197
  Post.with_status_draft # => <#ActiveRecord::Relation []>
188
- Post.with_status_review_pending # => <#ActiveRecord::Relation []>
198
+ Post.without_status_review_pending # => <#ActiveRecord::Relation []>
199
+ Post.with_status(:draft) # => <#ActiveRecord::Relation []>
200
+ Post.without_status(:draft) # => <#ActiveRecord::Relation []>
201
+ Post.with_status(Status.draft) # => <#ActiveRecord::Relation []>
202
+ Post.with_status(:draft, :review_pending) # => <#ActiveRecord::Relation []>
203
+ Post.with_status(Status.draft, 'published') # => <#ActiveRecord::Relation []>
204
+ Post.with_status([:draft, :review_pending]) # => <#ActiveRecord::Relation []>
189
205
  ```
190
206
 
191
207
  ```ruby
@@ -195,6 +211,8 @@ end
195
211
 
196
212
  Post.with_my_status_draft # => <#ActiveRecord::Relation []>
197
213
  Post.with_my_status_review_pending # => <#ActiveRecord::Relation []>
214
+ Post.with_my_status(:draft) # => <#ActiveRecord::Relation []>
215
+ Post.without_my_status(:draft) # => <#ActiveRecord::Relation []>
198
216
  ```
199
217
 
200
218
  Each scope returns all records with specified enumeration value.
@@ -212,6 +230,32 @@ Use in forms:
212
230
  = f.collection_select :status, Status.all, :symbol, :name
213
231
  ```
214
232
 
233
+
234
+
235
+ ## Validating input
236
+
237
+ Enumerations will by default raise an exception if you try to set an invalid value. This prevents usage of validations, which you might want to add if you're developing an API and have to return meaningful errors to API clients.
238
+
239
+ You can enable validations by first disabling error raising on invalid input (see [configuration](#configuration)). Then, you should add an inclusion validation to enumerated attributes:
240
+ ```ruby
241
+ class Post < ActiveRecord::Base
242
+ enumeration :status
243
+
244
+ validates :status, inclusion: { in: Status.all }
245
+ end
246
+ ```
247
+
248
+ You'll now get an appropriate error message when you insert an invalid value:
249
+ ```ruby
250
+ > post = Post.new(status: 'invalid')
251
+ > post.valid?
252
+ => false
253
+ > post.errors.full_messages.to_sentence
254
+ => "Status is not included in the list"
255
+ > post.status
256
+ => "invalid"
257
+ ```
258
+
215
259
  Advanced Usage
216
260
  =====
217
261
 
@@ -219,7 +263,7 @@ Except `name` you can specify any other attributes to your enumerations:
219
263
 
220
264
  ```ruby
221
265
  class Status < Enumerations::Base
222
- value :draft, id: 1, name: 'Draft'
266
+ value :draft, id: 1, name: 'Draft', published: false
223
267
  value :review_pending, id: 2, name: 'Review pending', description: 'Some description...'
224
268
  value :published, id: 3, name: 'Published', published: true
225
269
  value :other # passing no attributes is also allowed
@@ -234,10 +278,20 @@ Status.review_pending.description # => 'Some description...'
234
278
  Status.draft.description # => nil
235
279
  ```
236
280
 
281
+ For each attribute, you have predicate method. Predicate methods are actually calling `present?`
282
+ method on attribute value:
283
+
284
+ ```ruby
285
+ Status.draft.name? # => true
286
+ Status.draft.published? # => false
287
+ Status.published.published? # => true
288
+ Status.other.name? # => false
289
+ ```
290
+
237
291
  Translations
238
292
  =====
239
293
 
240
- **Enumerations** uses power of I18n API to enable you to create a locale file
294
+ **Enumerations** uses power of I18n API (if translate_attributes configuration is set to true) to enable you to create a locale file
241
295
  for enumerations like this:
242
296
 
243
297
  ```yaml
@@ -269,8 +323,8 @@ Configuration
269
323
 
270
324
  Basically no configuration is needed.
271
325
 
272
- **Enumerations** has two configuration options.
273
- You can customize primary key and foreign key suffix.
326
+ **Enumerations** has four configuration options.
327
+ You can customize primary key, foreign key suffix, whether to translate attributes and whether to raise `Enumerations::InvalidValueError` exception when setting invalid values.
274
328
  Just add initializer file to `config/initializers/enumerations.rb`.
275
329
 
276
330
  Example of configuration:
@@ -279,8 +333,10 @@ Example of configuration:
279
333
  # config/initializers/enumerations.rb
280
334
 
281
335
  Enumerations.configure do |config|
282
- config.primary_key = :id
283
- config.foreign_key_suffix = :id
336
+ config.primary_key = :id
337
+ config.foreign_key_suffix = :id
338
+ config.translate_attributes = true
339
+ config.raise_invalid_value_error = true
284
340
  end
285
341
  ```
286
342
 
@@ -291,7 +347,7 @@ If you set enumeration as:
291
347
  ```ruby
292
348
  enumeration :status
293
349
  ```
294
- then model should have `status`column (as `String` type).
350
+ then model should have `status` column (as `String` type).
295
351
  If you want save an `ID` to this column, you can set `foreign_key_suffix` to `id`.
296
352
  Then model should have `status_id` column.
297
353
 
@@ -323,6 +379,17 @@ post = Post.new
323
379
  post.status = Status.draft # => post.status_id = 1
324
380
  ```
325
381
 
382
+ If you want to configure primary key per enumeration class, you can use `primary_key=` class method:
383
+
384
+ ```ruby
385
+ class Status < Enumerations::Base
386
+ self.primary_key = :id
387
+
388
+ value :draft, id: 1, name: 'Draft'
389
+ value :review_pending, id: 2, name: 'Review pending'
390
+ end
391
+ ```
392
+
326
393
  Database Enumerations
327
394
  =====================
328
395
 
@@ -360,7 +427,7 @@ Credits
360
427
  =======
361
428
  **Enumerations** is maintained and sponsored by [Infinum](https://infinum.co)
362
429
 
363
- Copyright © 2016 Infinum Ltd.
430
+ Copyright © 2010 - 2018 Infinum Ltd.
364
431
 
365
432
  License
366
433
  =======
data/enumerations.gemspec CHANGED
@@ -3,7 +3,7 @@ require File.expand_path('../lib/enumerations/version', __FILE__)
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'enumerations'
5
5
  s.version = Enumerations::VERSION
6
- s.date = '2016-09-20'
6
+ s.date = '2017-09-08'
7
7
  s.summary = 'Enumerations for ActiveRecord!'
8
8
  s.description = 'Extends ActiveRecord with enumeration capabilites.'
9
9
  s.homepage = 'https://github.com/infinum/enumerations'
@@ -22,8 +22,8 @@ Gem::Specification.new do |s|
22
22
  s.add_dependency 'i18n'
23
23
  s.add_development_dependency 'pry-byebug'
24
24
  s.add_development_dependency 'rake'
25
- s.add_development_dependency 'codeclimate-test-reporter', '~> 1.0'
26
- s.add_development_dependency 'sqlite3'
25
+ s.add_development_dependency 'simplecov'
26
+ s.add_development_dependency 'sqlite3', '~> 1.4.0'
27
27
 
28
28
  s.files = `git ls-files`.split("\n")
29
29
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
data/lib/enumerations.rb CHANGED
@@ -7,7 +7,7 @@ require 'enumerations/configuration'
7
7
  require 'enumerations/version'
8
8
  require 'enumerations/base'
9
9
  require 'enumerations/reflection'
10
- require 'enumerations/enumerations_error'
10
+ require 'enumerations/errors'
11
11
 
12
12
  module Enumerations
13
13
  extend ActiveSupport::Concern
@@ -52,13 +52,23 @@ module Enumerations
52
52
  _enumerations
53
53
  end
54
54
 
55
+ def fetch_foreign_key_values(reflection, *symbols)
56
+ symbols.flatten.map do |symbol|
57
+ enumeration_value = reflection.enumerator_class.find(symbol)
58
+
59
+ enumeration_value &&
60
+ enumeration_value.send(reflection.enumerator_class.primary_key || :symbol)
61
+ end
62
+ end
63
+
55
64
  private
56
65
 
57
66
  def add_enumeration(reflection)
58
67
  define_getter_method(reflection)
59
68
  define_setter_method(reflection)
60
69
  define_bang_methods(reflection)
61
- define_scopes(reflection)
70
+ define_scopes_for_each_enumeration_value(reflection)
71
+ define_enumeration_scope(reflection)
62
72
 
63
73
  self._enumerations += [reflection]
64
74
  end
@@ -72,7 +82,7 @@ module Enumerations
72
82
  #
73
83
  def define_getter_method(reflection)
74
84
  define_method(reflection.name) do
75
- reflection.enumerator_class.find(self[reflection.foreign_key])
85
+ reflection.enumerator_class.find(self[reflection.foreign_key]) || self[reflection.foreign_key]
76
86
  end
77
87
  end
78
88
 
@@ -86,9 +96,15 @@ module Enumerations
86
96
  define_method("#{reflection.name}=") do |other|
87
97
  enumeration_value = reflection.enumerator_class.find(other)
88
98
 
89
- self[reflection.foreign_key] =
90
- enumeration_value &&
91
- enumeration_value.send(Enumerations.configuration.primary_key || :symbol)
99
+ if other.present? && enumeration_value.nil?
100
+ raise Enumerations::InvalidValueError if Enumerations.configuration.raise_invalid_value_error
101
+
102
+ self[reflection.foreign_key] = other
103
+ else
104
+ self[reflection.foreign_key] =
105
+ enumeration_value &&
106
+ enumeration_value.send(reflection.enumerator_class.primary_key || :symbol)
107
+ end
92
108
  end
93
109
  end
94
110
 
@@ -116,14 +132,37 @@ module Enumerations
116
132
  # User.with_role_admin => <#ActiveRecord::Relation []>
117
133
  # User.with_role_editor => <#ActiveRecord::Relation []>
118
134
  #
119
- def define_scopes(reflection)
135
+ def define_scopes_for_each_enumeration_value(reflection)
120
136
  reflection.enumerator_class.all.each do |enumeration|
121
- foreign_key = enumeration.send(Enumerations.configuration.primary_key || :symbol)
137
+ foreign_key = enumeration.send(reflection.enumerator_class.primary_key || :symbol)
138
+
139
+ scope("with_#{reflection.name}_#{enumeration.symbol}",
140
+ -> { where(reflection.foreign_key => foreign_key) })
122
141
 
123
- scope "with_#{reflection.name}_#{enumeration.symbol}",
124
- -> { where(reflection.foreign_key => foreign_key) }
142
+ scope("without_#{reflection.name}_#{enumeration.symbol}",
143
+ -> { where.not(reflection.foreign_key => foreign_key) })
125
144
  end
126
145
  end
146
+
147
+ # Scope for enumerated ActiveRecord model.
148
+ # Format of scope name is with_#{enumeration_name}(*enumerations).
149
+ #
150
+ # Example:
151
+ #
152
+ # User.with_role(:admin) => <#ActiveRecord::Relation []>
153
+ # User.with_role(:admin, Role.editor) => <#ActiveRecord::Relation []>
154
+ #
155
+ def define_enumeration_scope(reflection)
156
+ scope("with_#{reflection.name}",
157
+ lambda do |*symbols|
158
+ where(reflection.foreign_key => fetch_foreign_key_values(reflection, symbols))
159
+ end)
160
+
161
+ scope("without_#{reflection.name}",
162
+ lambda do |*symbols|
163
+ where.not(reflection.foreign_key => fetch_foreign_key_values(reflection, symbols))
164
+ end)
165
+ end
127
166
  end
128
167
  end
129
168
 
@@ -4,14 +4,15 @@ require 'enumerations/value'
4
4
  require 'enumerations/finder_methods'
5
5
 
6
6
  module Enumerations
7
- class Base
7
+ class Base < ActiveSupport::Multibyte::Chars
8
8
  extend Enumerations::FinderMethods
9
9
  include Enumerations::Value
10
10
 
11
- class_attribute :_values, :_symbol_index
11
+ class_attribute :_values, :_symbol_index, :_primary_key
12
12
 
13
13
  self._values = {}
14
14
  self._symbol_index = {}
15
+ self._primary_key = nil
15
16
 
16
17
  # Adding new value to enumeration
17
18
  #
@@ -79,16 +80,45 @@ module Enumerations
79
80
  _values.values
80
81
  end
81
82
 
83
+ # Sets primary key for enumeration class.
84
+ #
85
+ # Example:
86
+ #
87
+ # class Status < Enumeration::Base
88
+ # primary_key = :id
89
+ # end
90
+ #
91
+ def self.primary_key=(key)
92
+ self._primary_key = key && key.to_sym
93
+ end
94
+
95
+ # Gets primary key for enumeration class.
96
+ #
97
+ # Example:
98
+ #
99
+ # Status.primary_key => # nil
100
+ #
101
+ # class Status < Enumeration::Base
102
+ # primary_key = :id
103
+ # end
104
+ #
105
+ # Status.primary_key => # :id
106
+ #
107
+ def self.primary_key
108
+ _primary_key || Enumerations.configuration.primary_key
109
+ end
110
+
82
111
  def self.validate_symbol_and_primary_key(symbol, attributes)
83
- raise EnumerationsError, "Duplicate symbol #{symbol}" if find(symbol)
112
+ raise Enumerations::DuplicatedSymbolError if find(symbol)
84
113
 
85
- primary_key = Enumerations.configuration.primary_key
86
114
  return if primary_key.nil?
87
115
 
88
- raise EnumerationsError, 'Enumeration primary key is required' if attributes[primary_key].nil?
89
- raise EnumerationsError, "Duplicate primary key #{attributes[primary_key]}" if find(attributes[primary_key])
116
+ primary_key_value = attributes[primary_key]
90
117
 
91
- self._symbol_index = _symbol_index.merge(symbol => attributes[primary_key])
118
+ raise Enumerations::MissingPrimaryKeyError if primary_key_value.nil?
119
+ raise Enumerations::DuplicatedPrimaryKeyError if find(primary_key_value)
120
+
121
+ self._symbol_index = _symbol_index.merge(symbol => primary_key_value)
92
122
  end
93
123
 
94
124
  private_class_method :validate_symbol_and_primary_key
@@ -96,6 +126,8 @@ module Enumerations
96
126
  attr_reader :symbol, :attributes
97
127
 
98
128
  def initialize(symbol, attributes)
129
+ super(symbol)
130
+
99
131
  @symbol = symbol
100
132
  @attributes = attributes
101
133
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerations
2
4
  def self.configuration
3
5
  @configuration ||= Configuration.new
@@ -14,10 +16,14 @@ module Enumerations
14
16
  class Configuration
15
17
  attr_accessor :primary_key
16
18
  attr_accessor :foreign_key_suffix
19
+ attr_accessor :translate_attributes
20
+ attr_accessor :raise_invalid_value_error
17
21
 
18
22
  def initialize
19
- @primary_key = nil
20
- @foreign_key_suffix = nil
23
+ @primary_key = nil
24
+ @foreign_key_suffix = nil
25
+ @translate_attributes = true
26
+ @raise_invalid_value_error = true
21
27
  end
22
28
  end
23
29
  end
@@ -0,0 +1,7 @@
1
+ module Enumerations
2
+ class Error < StandardError; end
3
+ class DuplicatedSymbolError < Error; end
4
+ class MissingPrimaryKeyError < Error; end
5
+ class DuplicatedPrimaryKeyError < Error; end
6
+ class InvalidValueError < Error; end
7
+ end
@@ -39,7 +39,9 @@ module Enumerations
39
39
  end
40
40
 
41
41
  def find_by_primary_key(primary_key)
42
- value_from_symbol_index(primary_key) || value_from_symbol_index(primary_key.to_s.to_i)
42
+ return value_from_symbol_index(primary_key.to_i) if primary_key.is_a?(String)
43
+
44
+ value_from_symbol_index(primary_key)
43
45
  end
44
46
 
45
47
  private
@@ -1,6 +1,6 @@
1
1
  module Enumerations
2
2
  class Reflection
3
- attr_reader :name
3
+ attr_reader :name, :options
4
4
 
5
5
  def initialize(name, options = {})
6
6
  @name = name
@@ -8,11 +8,11 @@ module Enumerations
8
8
  end
9
9
 
10
10
  def class_name
11
- @class_name ||= (@options[:class_name] || name).to_s.camelize
11
+ @class_name ||= (options[:class_name] || name).to_s.camelize
12
12
  end
13
13
 
14
14
  def foreign_key
15
- @foreign_key ||= (@options[:foreign_key] || default_foreign_key_name).to_sym
15
+ @foreign_key ||= (options[:foreign_key] || default_foreign_key_name).to_sym
16
16
  end
17
17
 
18
18
  def enumerator_class
@@ -39,6 +39,7 @@ module Enumerations
39
39
  def create_instance_methods
40
40
  define_attributes_getters
41
41
  define_value_checking_method
42
+ define_predicate_methods_for_attributes
42
43
  end
43
44
 
44
45
  # Getters for all attributes
@@ -65,6 +66,8 @@ module Enumerations
65
66
  end
66
67
 
67
68
  def translate_attribute(key, locale)
69
+ return @attributes[key].to_s unless Enumerations.configuration.translate_attributes
70
+
68
71
  I18n.t(key, scope: [:enumerations, self.class.name.demodulize.underscore, symbol],
69
72
  default: @attributes[key].to_s,
70
73
  locale: locale)
@@ -83,5 +86,28 @@ module Enumerations
83
86
  __callee__[0..-2].to_sym == symbol
84
87
  end
85
88
  end
89
+
90
+ # Predicate methods for all attributes
91
+ #
92
+ # Example:
93
+ #
94
+ # class Role < Enumerations::Base
95
+ # value :admin, name: 'Administrator', active: false
96
+ # end
97
+ #
98
+ # user.role.name? => # true
99
+ # user.role.admin? => # false
100
+ #
101
+ def define_predicate_methods_for_attributes
102
+ @attributes.each do |key, _|
103
+ method_name = "#{key}?"
104
+
105
+ next if respond_to?(method_name.to_sym)
106
+
107
+ self.class.send :define_method, method_name do
108
+ @attributes[key].present?
109
+ end
110
+ end
111
+ end
86
112
  end
87
113
  end
@@ -1,3 +1,3 @@
1
1
  module Enumerations
2
- VERSION = '2.2.3'.freeze
2
+ VERSION = '2.5.0'.freeze
3
3
  end
data/test/base_test.rb CHANGED
@@ -16,7 +16,7 @@ class BaseTest < Minitest::Test
16
16
  end
17
17
 
18
18
  def test_duplicated_symbol
19
- assert_raises EnumerationsError, 'Duplicate symbol draft' do
19
+ assert_raises Enumerations::DuplicatedSymbolError do
20
20
  obj = Class.new(Enumerations::Base)
21
21
 
22
22
  obj.value :draft, id: 1, name: 'Draft'
@@ -0,0 +1,27 @@
1
+ module Configuration
2
+ ::CustomConfigurationEnum = Class.new(Enumerations::Base)
3
+
4
+ CustomConfigurationEnum.primary_key = :id
5
+ CustomConfigurationEnum.value :draft, id: 1
6
+
7
+ ::CustomConfigurationModel = Class.new(ActiveRecord::Base)
8
+ CustomConfigurationModel.table_name = :custom_models
9
+ CustomConfigurationModel.enumeration :custom_configuration_enum, foreign_key: :custom_enum_id
10
+
11
+ class CustomConfigurationTest < Minitest::Test
12
+ def test_primary_key_value
13
+ assert_equal :id, CustomConfigurationEnum.primary_key
14
+ end
15
+
16
+ def test_primary_key_value_is_not_set_in_configuration
17
+ assert_nil Enumerations.configuration.primary_key
18
+ end
19
+
20
+ def test_value_set_for_custom_foreign_key_config
21
+ model = CustomConfigurationModel.new
22
+ model.custom_configuration_enum = :draft
23
+
24
+ assert_equal :draft, model.custom_configuration_enum.symbol
25
+ end
26
+ end
27
+ end
@@ -37,7 +37,7 @@ class ConfigurationTest < Minitest::Test
37
37
  def test_required_primary_key_when_primary_key_configured
38
38
  Enumerations.configure { |config| config.primary_key = :id }
39
39
 
40
- assert_raises EnumerationsError, 'Enumeration primary key is required' do
40
+ assert_raises Enumerations::MissingPrimaryKeyError, 'Enumeration primary key is required' do
41
41
  Class.new(Enumerations::Base).value :draft, name: 'Draft'
42
42
  end
43
43
  end
@@ -45,7 +45,7 @@ class ConfigurationTest < Minitest::Test
45
45
  def test_duplicated_primary_key_when_primary_key_configured
46
46
  Enumerations.configure { |config| config.primary_key = :id }
47
47
 
48
- assert_raises EnumerationsError, 'Duplicate primary key 1' do
48
+ assert_raises Enumerations::DuplicatedPrimaryKeyError, 'Duplicate primary key 1' do
49
49
  Class.new(Enumerations::Base).values draft: { id: 1, name: 'Draft' },
50
50
  test: { id: 1, name: 'Draft' }
51
51
  end
@@ -1,5 +1,5 @@
1
1
  require_relative 'helpers/test_helper'
2
- require 'enumerations/enumerations_error'
2
+ require 'enumerations/errors'
3
3
 
4
4
  class EnumerationsTest < Minitest::Test
5
5
  def test_reflect_on_all_enumerations
@@ -75,21 +75,76 @@ class EnumerationsTest < Minitest::Test
75
75
  assert_equal 'published', u.status.to_s
76
76
  end
77
77
 
78
+ def test_enumerated_class_has_enumeration_scope
79
+ assert_respond_to User, :with_role
80
+ end
81
+
78
82
  def test_enumerated_class_has_scopes
79
83
  Role.all.each do |role|
80
84
  assert_respond_to User, ['with_role', role.to_s].join('_').to_sym
81
85
  end
82
86
  end
83
87
 
84
- def test_enumerated_class_scope_hash_value
88
+ def test_enumerated_class_enumeration_scope_hash_value
89
+ query_hash = User.with_role(:admin).where_values_hash.symbolize_keys
90
+
91
+ assert_equal query_hash, role: :admin
92
+ end
93
+
94
+ def test_enumerated_class_enumeration_without_scope_results
95
+ User.create(role: :admin)
96
+ User.create(role: :editor)
97
+
98
+ results = User.without_role(:admin)
99
+
100
+ assert_equal results, User.where.not(role: :admin)
101
+ end
102
+
103
+ def test_enumerated_class_enumeration_scope_hash_value_for_multiple_enums
104
+ query_hash = User.with_role(:admin, Role.author, 'editor').where_values_hash.symbolize_keys
105
+
106
+ assert_equal query_hash, role: [:admin, :author, :editor]
107
+ end
108
+
109
+ def test_enumerated_class_enumeration_scope_hash_value_for_multiple_enums_as_array
110
+ query_hash = User.with_role([:admin, Role.author, 'editor']).where_values_hash.symbolize_keys
111
+
112
+ assert_equal query_hash, role: [:admin, :author, :editor]
113
+ end
114
+
115
+ def test_enumerated_class_without_scope_hash_value
85
116
  query_hash = User.with_role_admin.where_values_hash.symbolize_keys
86
117
 
87
118
  assert_equal query_hash, role: :admin
88
119
  end
89
120
 
121
+ def test_enumerated_class_without_scope_results
122
+ User.create(role: :admin)
123
+ User.create(role: :editor)
124
+
125
+ results = User.without_role_admin
126
+
127
+ assert_equal results, User.where.not(role: :admin)
128
+ end
129
+
90
130
  def test_nonexistent_value_assignment
131
+ assert_raises Enumerations::InvalidValueError do
132
+ User.new(role: :nonexistent_value)
133
+ end
134
+ end
135
+
136
+ def test_nonexistent_value_assignment_with_error_raising_turned_off
137
+ Enumerations.configuration.raise_invalid_value_error = false
138
+
91
139
  user = User.new(role: :nonexistent_value)
92
- assert_nil user.role
140
+
141
+ assert_equal user.role, 'nonexistent_value'
142
+
143
+ user.role = :other_nonexistent_value
144
+
145
+ assert_equal user.role, 'other_nonexistent_value'
146
+
147
+ Enumerations.configuration.raise_invalid_value_error = true
93
148
  end
94
149
 
95
150
  def test_on_nil_value_assignment
@@ -91,4 +91,13 @@ class TranslationTest < Minitest::Test
91
91
 
92
92
  assert_nil status
93
93
  end
94
+
95
+ def test_turn_of_translate
96
+ status = Status.find(:draft)
97
+ Enumerations.configuration.translate_attributes = false
98
+ name = status.name
99
+ Enumerations.configuration.translate_attributes = true
100
+
101
+ assert_equal name, 'Draft'
102
+ end
94
103
  end
data/test/value_test.rb CHANGED
@@ -68,4 +68,18 @@ class ValueTest < Minitest::Test
68
68
 
69
69
  assert_equal role.type, 'croatist'
70
70
  end
71
+
72
+ def test_enumeration_attribute_predicate_methods
73
+ status = Status.none
74
+
75
+ assert_equal status.name?, true
76
+ assert_equal status.visible?, true
77
+ assert_equal status.deleted?, false
78
+ end
79
+
80
+ def test_enumeration_attribute_predicate_method_on_undefined_attribute
81
+ status = Status.deleted
82
+
83
+ assert_equal status.name?, false
84
+ end
71
85
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enumerations
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.3
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomislav Car
@@ -9,10 +9,10 @@ authors:
9
9
  - Nikola Santić
10
10
  - Stjepan Hadjić
11
11
  - Petar Ćurković
12
- autorequire:
12
+ autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2016-09-20 00:00:00.000000000 Z
15
+ date: 2017-09-08 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: activerecord
@@ -85,33 +85,33 @@ dependencies:
85
85
  - !ruby/object:Gem::Version
86
86
  version: '0'
87
87
  - !ruby/object:Gem::Dependency
88
- name: codeclimate-test-reporter
88
+ name: simplecov
89
89
  requirement: !ruby/object:Gem::Requirement
90
90
  requirements:
91
- - - "~>"
91
+ - - ">="
92
92
  - !ruby/object:Gem::Version
93
- version: '1.0'
93
+ version: '0'
94
94
  type: :development
95
95
  prerelease: false
96
96
  version_requirements: !ruby/object:Gem::Requirement
97
97
  requirements:
98
- - - "~>"
98
+ - - ">="
99
99
  - !ruby/object:Gem::Version
100
- version: '1.0'
100
+ version: '0'
101
101
  - !ruby/object:Gem::Dependency
102
102
  name: sqlite3
103
103
  requirement: !ruby/object:Gem::Requirement
104
104
  requirements:
105
- - - ">="
105
+ - - "~>"
106
106
  - !ruby/object:Gem::Version
107
- version: '0'
107
+ version: 1.4.0
108
108
  type: :development
109
109
  prerelease: false
110
110
  version_requirements: !ruby/object:Gem::Requirement
111
111
  requirements:
112
- - - ">="
112
+ - - "~>"
113
113
  - !ruby/object:Gem::Version
114
- version: '0'
114
+ version: 1.4.0
115
115
  description: Extends ActiveRecord with enumeration capabilites.
116
116
  email:
117
117
  - tomislav@infinum.hr
@@ -124,21 +124,24 @@ extensions: []
124
124
  extra_rdoc_files: []
125
125
  files:
126
126
  - ".gitignore"
127
+ - ".rubocop.yml"
128
+ - CHANGELOG.md
127
129
  - Gemfile
128
- - Migrate.md
130
+ - MIGRATE.md
131
+ - README.md
129
132
  - Rakefile
130
- - Readme.md
131
133
  - enumerations.gemspec
132
134
  - lib/enumerations.rb
133
135
  - lib/enumerations/base.rb
134
136
  - lib/enumerations/configuration.rb
135
- - lib/enumerations/enumerations_error.rb
137
+ - lib/enumerations/errors.rb
136
138
  - lib/enumerations/finder_methods.rb
137
139
  - lib/enumerations/reflection.rb
138
140
  - lib/enumerations/value.rb
139
141
  - lib/enumerations/version.rb
140
142
  - test/base_test.rb
141
143
  - test/configuration/configuration.rb
144
+ - test/configuration/custom_configuration_test.rb
142
145
  - test/configuration/enumerations_test.rb
143
146
  - test/configuration/finder_test.rb
144
147
  - test/configuration_test.rb
@@ -154,7 +157,7 @@ files:
154
157
  homepage: https://github.com/infinum/enumerations
155
158
  licenses: []
156
159
  metadata: {}
157
- post_install_message:
160
+ post_install_message:
158
161
  rdoc_options: []
159
162
  require_paths:
160
163
  - lib
@@ -169,14 +172,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
172
  - !ruby/object:Gem::Version
170
173
  version: '0'
171
174
  requirements: []
172
- rubyforge_project:
173
- rubygems_version: 2.6.8
174
- signing_key:
175
+ rubygems_version: 3.1.2
176
+ signing_key:
175
177
  specification_version: 4
176
178
  summary: Enumerations for ActiveRecord!
177
179
  test_files:
178
180
  - test/base_test.rb
179
181
  - test/configuration/configuration.rb
182
+ - test/configuration/custom_configuration_test.rb
180
183
  - test/configuration/enumerations_test.rb
181
184
  - test/configuration/finder_test.rb
182
185
  - test/configuration_test.rb
@@ -1,2 +0,0 @@
1
- class EnumerationsError < RuntimeError
2
- end