enumerations 2.2.3 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6bff6ddbd1cfb803b3463c11796daf3c81f1c741
4
- data.tar.gz: 20a258a2ed4129ed92b044f2933fb366d45aba6e
3
+ metadata.gz: ce06adb418c77b2cfe89af486bff75362b4183bc
4
+ data.tar.gz: e65afcbf46c76d46625443de26b52445a7a12a29
5
5
  SHA512:
6
- metadata.gz: 584c186148b1038d4aadbdd1ee4cb230ee32b40332aca1888933a2ac2813ad61dd356eb548701ab52a10a9e426122ba70e6022cc6254001431b3fd2e51c3d198
7
- data.tar.gz: 7048a1acf02560a3311d3956d09ce76d25651a631bf7b4a169d7513d28f4f656142ec93a0f44fff6667022d8651f07cdc81104b2eab969c5dabb0468c65bc72e
6
+ metadata.gz: 168a363ddbbcf47dbe58f2024d455c6b5aae795360b92ad947d77f396ca25a4714067e4affb7e283d72ba80539d42f573d83cec68e68d2ba3d8334721f1e346e
7
+ data.tar.gz: d09864e055364e4415870471d0ed16f2f00a7a2afbda0604f4d8dd37c65d165054de7524a5ac62f5173d71bd4c8eca4a626d6993ff06d4d6fa15d7ee1cab125f
@@ -0,0 +1,8 @@
1
+ LineLength:
2
+ Max: 100
3
+
4
+ Documentation:
5
+ Enabled: False
6
+
7
+ Style/SymbolArray:
8
+ Enabled: False
data/Readme.md CHANGED
@@ -6,7 +6,7 @@ Enumerations
6
6
  [![Build Status](https://semaphoreci.com/api/v1/infinum/enumerations/branches/master/shields_badge.svg)](https://semaphoreci.com/infinum/enumerations)
7
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.
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.
@@ -219,7 +237,7 @@ Except `name` you can specify any other attributes to your enumerations:
219
237
 
220
238
  ```ruby
221
239
  class Status < Enumerations::Base
222
- value :draft, id: 1, name: 'Draft'
240
+ value :draft, id: 1, name: 'Draft', published: false
223
241
  value :review_pending, id: 2, name: 'Review pending', description: 'Some description...'
224
242
  value :published, id: 3, name: 'Published', published: true
225
243
  value :other # passing no attributes is also allowed
@@ -234,6 +252,16 @@ Status.review_pending.description # => 'Some description...'
234
252
  Status.draft.description # => nil
235
253
  ```
236
254
 
255
+ For each attribute, you have predicate method. Predicate methods are actually calling `present?`
256
+ method on attribute value:
257
+
258
+ ```ruby
259
+ Status.draft.name? # => true
260
+ Status.draft.published? # => false
261
+ Status.published.published? # => true
262
+ Status.other.name? # => false
263
+ ```
264
+
237
265
  Translations
238
266
  =====
239
267
 
@@ -291,7 +319,7 @@ If you set enumeration as:
291
319
  ```ruby
292
320
  enumeration :status
293
321
  ```
294
- then model should have `status`column (as `String` type).
322
+ then model should have `status` column (as `String` type).
295
323
  If you want save an `ID` to this column, you can set `foreign_key_suffix` to `id`.
296
324
  Then model should have `status_id` column.
297
325
 
@@ -323,6 +351,17 @@ post = Post.new
323
351
  post.status = Status.draft # => post.status_id = 1
324
352
  ```
325
353
 
354
+ If you want to configure primary key per enumeration class, you can use `primary_key=` class method:
355
+
356
+ ```ruby
357
+ class Status < Enumerations::Base
358
+ self.primary_key = :id
359
+
360
+ value :draft, id: 1, name: 'Draft'
361
+ value :review_pending, id: 2, name: 'Review pending'
362
+ end
363
+ ```
364
+
326
365
  Database Enumerations
327
366
  =====================
328
367
 
@@ -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'
@@ -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
@@ -58,7 +58,8 @@ module Enumerations
58
58
  define_getter_method(reflection)
59
59
  define_setter_method(reflection)
60
60
  define_bang_methods(reflection)
61
- define_scopes(reflection)
61
+ define_scopes_for_each_enumeration_value(reflection)
62
+ define_enumeration_scope(reflection)
62
63
 
63
64
  self._enumerations += [reflection]
64
65
  end
@@ -86,9 +87,11 @@ module Enumerations
86
87
  define_method("#{reflection.name}=") do |other|
87
88
  enumeration_value = reflection.enumerator_class.find(other)
88
89
 
90
+ raise Enumerations::InvalidValueError if other.present? && enumeration_value.nil?
91
+
89
92
  self[reflection.foreign_key] =
90
93
  enumeration_value &&
91
- enumeration_value.send(Enumerations.configuration.primary_key || :symbol)
94
+ enumeration_value.send(reflection.enumerator_class.primary_key || :symbol)
92
95
  end
93
96
  end
94
97
 
@@ -116,12 +119,44 @@ module Enumerations
116
119
  # User.with_role_admin => <#ActiveRecord::Relation []>
117
120
  # User.with_role_editor => <#ActiveRecord::Relation []>
118
121
  #
119
- def define_scopes(reflection)
122
+ def define_scopes_for_each_enumeration_value(reflection)
120
123
  reflection.enumerator_class.all.each do |enumeration|
121
- foreign_key = enumeration.send(Enumerations.configuration.primary_key || :symbol)
124
+ foreign_key = enumeration.send(reflection.enumerator_class.primary_key || :symbol)
125
+
126
+ scope("with_#{reflection.name}_#{enumeration.symbol}",
127
+ -> { where(reflection.foreign_key => foreign_key) })
128
+
129
+ scope("without_#{reflection.name}_#{enumeration.symbol}",
130
+ -> { where.not(reflection.foreign_key => foreign_key) })
131
+ end
132
+ end
133
+
134
+ # Scope for enumerated ActiveRecord model.
135
+ # Format of scope name is with_#{enumeration_name}(*enumerations).
136
+ #
137
+ # Example:
138
+ #
139
+ # User.with_role(:admin) => <#ActiveRecord::Relation []>
140
+ # User.with_role(:admin, Role.editor) => <#ActiveRecord::Relation []>
141
+ #
142
+ def define_enumeration_scope(reflection)
143
+ scope("with_#{reflection.name}",
144
+ lambda do |*symbols|
145
+ where(reflection.foreign_key => fetch_foreign_key_values(reflection, symbols))
146
+ end)
147
+
148
+ scope("without_#{reflection.name}",
149
+ lambda do |*symbols|
150
+ where.not(reflection.foreign_key => fetch_foreign_key_values(reflection, symbols))
151
+ end)
152
+ end
153
+
154
+ def fetch_foreign_key_values(reflection, *symbols)
155
+ symbols.flatten.map do |symbol|
156
+ enumeration_value = reflection.enumerator_class.find(symbol)
122
157
 
123
- scope "with_#{reflection.name}_#{enumeration.symbol}",
124
- -> { where(reflection.foreign_key => foreign_key) }
158
+ enumeration_value &&
159
+ enumeration_value.send(reflection.enumerator_class.primary_key || :symbol)
125
160
  end
126
161
  end
127
162
  end
@@ -8,10 +8,11 @@ module Enumerations
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]
117
+
118
+ raise Enumerations::MissingPrimaryKeyError if primary_key_value.nil?
119
+ raise Enumerations::DuplicatedPrimaryKeyError if find(primary_key_value)
90
120
 
91
- self._symbol_index = _symbol_index.merge(symbol => attributes[primary_key])
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
@@ -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
@@ -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
@@ -83,5 +84,28 @@ module Enumerations
83
84
  __callee__[0..-2].to_sym == symbol
84
85
  end
85
86
  end
87
+
88
+ # Predicate methods for all attributes
89
+ #
90
+ # Example:
91
+ #
92
+ # class Role < Enumerations::Base
93
+ # value :admin, name: 'Administrator', active: false
94
+ # end
95
+ #
96
+ # user.role.name? => # true
97
+ # user.role.admin? => # false
98
+ #
99
+ def define_predicate_methods_for_attributes
100
+ @attributes.each do |key, _|
101
+ method_name = "#{key}?"
102
+
103
+ next if respond_to?(method_name.to_sym)
104
+
105
+ self.class.send :define_method, method_name do
106
+ @attributes[key].present?
107
+ end
108
+ end
109
+ end
86
110
  end
87
111
  end
@@ -1,3 +1,3 @@
1
1
  module Enumerations
2
- VERSION = '2.2.3'.freeze
2
+ VERSION = '2.3.1'.freeze
3
3
  end
@@ -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,62 @@ 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
91
- user = User.new(role: :nonexistent_value)
92
- assert_nil user.role
131
+ assert_raises Enumerations::InvalidValueError do
132
+ User.new(role: :nonexistent_value)
133
+ end
93
134
  end
94
135
 
95
136
  def test_on_nil_value_assignment
@@ -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.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomislav Car
@@ -12,7 +12,7 @@ authors:
12
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
@@ -124,6 +124,7 @@ extensions: []
124
124
  extra_rdoc_files: []
125
125
  files:
126
126
  - ".gitignore"
127
+ - ".rubocop.yml"
127
128
  - Gemfile
128
129
  - Migrate.md
129
130
  - Rakefile
@@ -132,13 +133,14 @@ files:
132
133
  - lib/enumerations.rb
133
134
  - lib/enumerations/base.rb
134
135
  - lib/enumerations/configuration.rb
135
- - lib/enumerations/enumerations_error.rb
136
+ - lib/enumerations/errors.rb
136
137
  - lib/enumerations/finder_methods.rb
137
138
  - lib/enumerations/reflection.rb
138
139
  - lib/enumerations/value.rb
139
140
  - lib/enumerations/version.rb
140
141
  - test/base_test.rb
141
142
  - test/configuration/configuration.rb
143
+ - test/configuration/custom_configuration_test.rb
142
144
  - test/configuration/enumerations_test.rb
143
145
  - test/configuration/finder_test.rb
144
146
  - test/configuration_test.rb
@@ -170,13 +172,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
172
  version: '0'
171
173
  requirements: []
172
174
  rubyforge_project:
173
- rubygems_version: 2.6.8
175
+ rubygems_version: 2.6.11
174
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