enumerize 2.2.2 → 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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +10 -3
  3. data/CHANGELOG.md +12 -0
  4. data/Gemfile.global +1 -1
  5. data/README.md +30 -0
  6. data/Rakefile +2 -0
  7. data/lib/enumerize.rb +3 -0
  8. data/lib/enumerize/activemodel.rb +2 -0
  9. data/lib/enumerize/activerecord.rb +24 -0
  10. data/lib/enumerize/attribute.rb +17 -9
  11. data/lib/enumerize/attribute_map.rb +2 -0
  12. data/lib/enumerize/base.rb +6 -6
  13. data/lib/enumerize/hooks/formtastic.rb +2 -0
  14. data/lib/enumerize/hooks/sequel_dataset.rb +2 -0
  15. data/lib/enumerize/hooks/simple_form.rb +2 -0
  16. data/lib/enumerize/hooks/uniqueness.rb +2 -0
  17. data/lib/enumerize/integrations/rails_admin.rb +2 -0
  18. data/lib/enumerize/integrations/rspec.rb +2 -0
  19. data/lib/enumerize/integrations/rspec/matcher.rb +2 -0
  20. data/lib/enumerize/module.rb +2 -0
  21. data/lib/enumerize/module_attributes.rb +2 -0
  22. data/lib/enumerize/mongoid.rb +16 -0
  23. data/lib/enumerize/predicatable.rb +2 -0
  24. data/lib/enumerize/predicates.rb +2 -0
  25. data/lib/enumerize/scope/activerecord.rb +12 -0
  26. data/lib/enumerize/scope/mongoid.rb +11 -0
  27. data/lib/enumerize/scope/sequel.rb +12 -0
  28. data/lib/enumerize/sequel.rb +9 -4
  29. data/lib/enumerize/set.rb +2 -0
  30. data/lib/enumerize/utils.rb +12 -0
  31. data/lib/enumerize/value.rb +9 -15
  32. data/lib/enumerize/version.rb +1 -1
  33. data/lib/sequel/plugins/enumerize.rb +2 -0
  34. data/spec/enumerize/integrations/rspec/matcher_spec.rb +2 -0
  35. data/spec/spec_helper.rb +2 -0
  36. data/test/activemodel_test.rb +2 -0
  37. data/test/activerecord_test.rb +90 -4
  38. data/test/attribute_map_test.rb +2 -0
  39. data/test/attribute_test.rb +7 -0
  40. data/test/base_test.rb +3 -1
  41. data/test/formtastic_test.rb +2 -0
  42. data/test/module_attributes_test.rb +2 -0
  43. data/test/mongo_mapper_test.rb +11 -1
  44. data/test/mongoid_test.rb +30 -4
  45. data/test/multiple_test.rb +2 -0
  46. data/test/predicates_test.rb +2 -0
  47. data/test/rails_admin_test.rb +2 -0
  48. data/test/sequel_test.rb +51 -1
  49. data/test/set_test.rb +2 -0
  50. data/test/simple_form_test.rb +2 -0
  51. data/test/support/mock_controller.rb +2 -0
  52. data/test/support/shared_enums.rb +43 -0
  53. data/test/support/view_test_helper.rb +2 -0
  54. data/test/test_helper.rb +2 -0
  55. data/test/value_test.rb +5 -4
  56. metadata +6 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '09a21a038b965b870133316f6ff3343c673999dc49fc619045695e2b56acd5be'
4
- data.tar.gz: 031bb09cc643bff2ab3fbc1b9d3786ece309d684841a6199d11082aa14169c56
3
+ metadata.gz: 9f6c56fc7c04faa02a4b4e4c137d3e3b743426d040e3f58bb79377d2c896d98f
4
+ data.tar.gz: 1e1842411f2b914b6142d071e84c435f17dfdac0f87a61eb9bf0a45a469a7780
5
5
  SHA512:
6
- metadata.gz: 53ebadba90aaf20fd45007f386d2de7a702b3ee1973992675136a41be99fe92889e1c852c409fa0ae8eea1d948b5cfec08163a1b3b0f13fb58de7984992e9a01
7
- data.tar.gz: f8f90dd597f8ae953f8c162682ee96e24e49b0b4685b21d9003991c9779fb9abe9764b7cf4d5f6afeafce2a0a2f5ed073b3a00251210268cab76db6a45ba9b65
6
+ metadata.gz: b3c9a1fd651070c324e04f26dcf0539ed6d1a8666878106875b78acc00d6219c5525349e0f3557aa43eb6625986322063117f06f8162922b9ae1b91544593d10
7
+ data.tar.gz: 4f070511d3e8d06e13eef610b73b4e40b5db8bd73c7282aec5cf1203de78b09e323248ce9627b82a8c8ab0a8688a4e0e05ac6d4bf1659c3e5ff69cb86c435745
@@ -10,10 +10,17 @@ gemfile:
10
10
  - Gemfile.rails52
11
11
  - Gemfile.mongo_mapper
12
12
  rvm:
13
- - 2.2.7
14
- - 2.3.3
15
- - 2.4.1
13
+ - 2.2.9
14
+ - 2.3.6
15
+ - 2.4.3
16
+ - 2.5.0
16
17
  - jruby-9.1.14.0
18
+ before_install:
19
+ # Rubygems > 3.0.0 no longer supported rubies < 2.3
20
+ - gem install "rubygems-update:<3.0.0" --no-document && update_rubygems
21
+ # Bundler 2.0 is not supported by Rails < 5
22
+ - gem list -i bundler -v '>= 2.0.0' && rvm @global do gem uninstall bundler -x || true
23
+ - gem install bundler -v '< 2'
17
24
  env:
18
25
  global:
19
26
  - DB_USER=postgres
@@ -4,6 +4,18 @@
4
4
 
5
5
  ### bug fix
6
6
 
7
+ ## 2.3.1 (May 2, 2019)
8
+
9
+ ### enhancements
10
+
11
+ * Add ability to skip validations by passing `:skip_validations` option. (by [@chumakoff](https://github.com/chumakoff))
12
+ * Add option `scope: shallow` to extend scopes based on enumerized attribute values (by [@moofkit](https://github.com/moofkit/))
13
+
14
+ ### bug fix
15
+
16
+ * Fix issue with ActiveRecord and Mongoid `reload` method when enumberized attributes weren't synced from DB. (by [@nashby](https://github.com/nashby) and [@FunkyloverOne](https://github.com/FunkyloverOne))
17
+ * Fix issue with ActiveRecord `reload` method not working for ActiveRecord::Store attributes due to `1b776c`. (by [@rickcsong](https://github.com/rickcsong))
18
+
7
19
  ## 2.2.2 (March 6, 2018)
8
20
 
9
21
  ### bug fix
@@ -5,7 +5,7 @@ gemspec
5
5
  gem 'rake'
6
6
  gem 'rspec', :require => false
7
7
 
8
- gem 'sqlite3', :platform => [:ruby, :mswin, :mingw]
8
+ gem 'sqlite3', '~> 1.3.6', :platform => [:ruby, :mswin, :mingw]
9
9
  gem 'pg', '~> 0.21.0', :platform => [:ruby, :mswin, :mingw]
10
10
  gem 'sequel'
11
11
 
data/README.md CHANGED
@@ -58,6 +58,18 @@ class User < ActiveRecord::Base
58
58
  end
59
59
  ```
60
60
 
61
+ :warning: By default, `enumerize` adds `inclusion` validation to the model. You can skip validations by passing `skip_validations` option. :warning:
62
+
63
+ ```ruby
64
+ class User < ActiveRecord::Base
65
+ extend Enumerize
66
+
67
+ enumerize :sex, in: [:male, :female], skip_validations: lambda { |user| user.new_record? }
68
+
69
+ enumerize :role, in: [:user, :admin], skip_validations: true
70
+ end
71
+ ```
72
+
61
73
  Mongoid:
62
74
 
63
75
  ```ruby
@@ -256,6 +268,24 @@ User.having_status(:blocked).with_sex(:male, :female)
256
268
  # SELECT "users".* FROM "users" WHERE "users"."status" IN (2) AND "users"."sex" IN ('male', 'female')
257
269
  ```
258
270
 
271
+ Shallow scopes:
272
+
273
+ Adds named scopes to the class directly
274
+
275
+ ```ruby
276
+ class User < ActiveRecord::Base
277
+ extend Enumerize
278
+ enumerize :sex, :in => [:male, :female], scope: :shallow
279
+ enumerize :status, :in => { active: 1, blocked: 2 }, scope: :shallow
280
+ end
281
+
282
+ User.male
283
+ # SELECT "users".* FROM "users" WHERE "users"."sex" = 'male'
284
+
285
+ User.active
286
+ # SELECT "users".* FROM "users" WHERE "users"."status" = 1
287
+ ```
288
+
259
289
  :warning: It is not possible to define a scope when using the `:multiple` option. :warning:
260
290
 
261
291
  Array-like attributes with plain ruby objects:
data/Rakefile CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rake
2
+ # frozen_string_literal: true
3
+
2
4
  require "bundler/gem_tasks"
3
5
 
4
6
  require 'rake/testtask'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
  require 'enumerize/version'
3
5
 
@@ -10,6 +12,7 @@ module Enumerize
10
12
  autoload :Module, 'enumerize/module'
11
13
  autoload :Predicates, 'enumerize/predicates'
12
14
  autoload :Predicatable, 'enumerize/predicatable'
15
+ autoload :Utils, 'enumerize/utils'
13
16
  autoload :ModuleAttributes, 'enumerize/module_attributes'
14
17
 
15
18
  autoload :ActiveModelAttributesSupport, 'enumerize/activemodel'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module ActiveModelAttributesSupport
3
5
  def enumerize(name, options={})
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module ActiveRecordSupport
3
5
  def enumerize(name, options={})
@@ -50,6 +52,28 @@ module Enumerize
50
52
 
51
53
  became
52
54
  end
55
+
56
+ def reload(options = nil)
57
+ reloaded = super
58
+
59
+ reloaded.class.enumerized_attributes.each do |attr|
60
+ begin
61
+ # Checks first if the enumerized attribute is in ActiveRecord::Store
62
+ store_attr, _ = reloaded.class.stored_attributes.detect do |store_attr, keys|
63
+ keys.include?(attr.name)
64
+ end
65
+
66
+ if store_attr.present?
67
+ reloaded.send("#{attr.name}=", reloaded.send(store_attr).with_indifferent_access[attr.name])
68
+ else
69
+ reloaded.send("#{attr.name}=", reloaded[attr.name])
70
+ end
71
+ rescue ActiveModel::MissingAttributeError
72
+ end
73
+ end
74
+
75
+ reloaded
76
+ end
53
77
  end
54
78
 
55
79
  module RelationMethods
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  class Attribute
3
- attr_reader :klass, :name, :values, :default_value, :i18n_scope
5
+ attr_reader :klass, :name, :values, :default_value, :i18n_scope, :skip_validations_value
4
6
 
5
7
  def initialize(klass, name, options={})
6
8
  raise ArgumentError, ':in option is required' unless options[:in]
@@ -11,21 +13,23 @@ module Enumerize
11
13
  @klass = klass
12
14
  @name = name.to_sym
13
15
 
14
- value_class = options.fetch(:value_class, Value)
15
- @values = Array(options[:in]).map { |v| value_class.new(self, *v) }
16
-
17
- @value_hash = Hash[@values.map { |v| [v.value.to_s, v] }]
18
- @value_hash.merge! Hash[@values.map { |v| [v.to_s, v] }]
19
-
20
16
  if options[:i18n_scope]
21
17
  raise ArgumentError, ':i18n_scope option accepts only String or Array of strings' unless Array(options[:i18n_scope]).all? { |s| s.is_a?(String) }
22
18
  @i18n_scope = options[:i18n_scope]
23
19
  end
24
20
 
21
+ value_class = options.fetch(:value_class, Value)
22
+ @values = Array(options[:in]).map { |v| value_class.new(self, *v).freeze }
23
+
24
+ @value_hash = Hash[@values.map { |v| [v.value.to_s, v] }]
25
+ @value_hash.merge! Hash[@values.map { |v| [v.to_s, v] }]
26
+
25
27
  if options[:default]
26
28
  @default_value = find_default_value(options[:default])
27
29
  raise ArgumentError, 'invalid default value' unless @default_value
28
30
  end
31
+
32
+ @skip_validations_value = options.fetch(:skip_validations, false)
29
33
  end
30
34
 
31
35
  def find_default_value(value)
@@ -44,11 +48,15 @@ module Enumerize
44
48
  values.map { |value| find_value(value) }.compact
45
49
  end
46
50
 
51
+ def each_value
52
+ values.each { |value| yield value }
53
+ end
54
+
47
55
  def i18n_scopes
48
56
  @i18n_scopes ||= if i18n_scope
49
- scopes = Array(i18n_scope)
57
+ Array(i18n_scope)
50
58
  elsif @klass.respond_to?(:model_name)
51
- scopes = ["enumerize.#{@klass.model_name.i18n_key}.#{name}"]
59
+ ["enumerize.#{@klass.model_name.i18n_key}.#{name}"]
52
60
  else
53
61
  []
54
62
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  class AttributeMap
3
5
  attr_reader :attributes
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module Base
3
5
  def self.included(base)
@@ -72,6 +74,9 @@ module Enumerize
72
74
 
73
75
  def _validate_enumerized_attributes
74
76
  self.class.enumerized_attributes.each do |attr|
77
+ skip_validations = Utils.call_if_callable(attr.skip_validations_value, self)
78
+ next if skip_validations
79
+
75
80
  value = read_attribute_for_validation(attr.name)
76
81
  next if value.blank?
77
82
 
@@ -96,12 +101,7 @@ module Enumerize
96
101
  value_for_validation = _enumerized_values_for_validation[attr.name.to_s]
97
102
 
98
103
  if (!attr_value || attr_value.empty?) && (!value_for_validation || value_for_validation.empty?)
99
- value = attr.default_value
100
-
101
- if value.respond_to?(:call)
102
- value = value.arity == 0 ? value.call : value.call(self)
103
- end
104
-
104
+ value = Utils.call_if_callable(attr.default_value, self)
105
105
  public_send("#{attr.name}=", value)
106
106
  end
107
107
  rescue ActiveModel::MissingAttributeError
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
 
3
5
  module Enumerize
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module Hooks
3
5
  module SequelDataset
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
 
3
5
  module Enumerize
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
 
3
5
  module Enumerize
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module Integrations
3
5
  module RailsAdmin
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'enumerize/integrations/rspec/matcher'
2
4
 
3
5
  module Enumerize
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module Integrations
3
5
  module RSpec
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  class Module < ::Module
3
5
  attr_reader :_class_methods
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module ModuleAttributes
3
5
  def included(base)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module MongoidSupport
3
5
  def enumerize(name, options={})
@@ -5,9 +7,23 @@ module Enumerize
5
7
 
6
8
  _enumerize_module.dependent_eval do
7
9
  if self < ::Mongoid::Document
10
+ include InstanceMethods
11
+
8
12
  after_initialize :_set_default_value_for_enumerized_attributes
9
13
  end
10
14
  end
11
15
  end
16
+
17
+ module InstanceMethods
18
+ def reload
19
+ reloaded = super
20
+
21
+ reloaded.class.enumerized_attributes.each do |attr|
22
+ reloaded.send("#{attr.name}=", reloaded[attr.name])
23
+ end
24
+
25
+ reloaded
26
+ end
27
+ end
12
28
  end
13
29
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module Predicatable
3
5
  def respond_to_missing?(method, include_private=false)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/core_ext/module/delegation'
2
4
 
3
5
  module Enumerize
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module Scope
3
5
  module ActiveRecord
@@ -16,6 +18,8 @@ module Enumerize
16
18
  private
17
19
 
18
20
  def _define_activerecord_scope_methods!(name, options)
21
+ return _define_activerecord_shallow_scopes!(name) if options[:scope] == :shallow
22
+
19
23
  scope_name = options[:scope] == true ? "with_#{name}" : options[:scope]
20
24
 
21
25
  define_singleton_method scope_name do |*values|
@@ -32,6 +36,14 @@ module Enumerize
32
36
  end
33
37
  end
34
38
  end
39
+
40
+ def _define_activerecord_shallow_scopes!(attribute_name)
41
+ enumerized_attributes[attribute_name].each_value do |value_obj|
42
+ define_singleton_method(value_obj) do
43
+ where(attribute_name => value_obj.value)
44
+ end
45
+ end
46
+ end
35
47
  end
36
48
  end
37
49
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module Scope
3
5
  module Mongoid
@@ -16,6 +18,7 @@ module Enumerize
16
18
  private
17
19
 
18
20
  def _define_mongoid_scope_methods!(name, options)
21
+ return _define_mongoid_shallow_scopes!(name) if options[:scope] == :shallow
19
22
  scope_name = options[:scope] == true ? "with_#{name}" : options[:scope]
20
23
 
21
24
  define_singleton_method scope_name do |*values|
@@ -30,6 +33,14 @@ module Enumerize
30
33
  end
31
34
  end
32
35
  end
36
+
37
+ def _define_mongoid_shallow_scopes!(attribute_name)
38
+ enumerized_attributes[attribute_name].each_value do |value_obj|
39
+ define_singleton_method(value_obj) do
40
+ self.in(attribute_name => value_obj.value)
41
+ end
42
+ end
43
+ end
33
44
  end
34
45
  end
35
46
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module Scope
3
5
  module Sequel
@@ -18,6 +20,8 @@ module Enumerize
18
20
  private
19
21
 
20
22
  def _define_sequel_scope_methods!(name, options)
23
+ return _define_sequel_shallow_scopes!(name) if options[:scope] == :shallow
24
+
21
25
  klass = self
22
26
  scope_name = options[:scope] == true ? "with_#{name}" : options[:scope]
23
27
 
@@ -35,6 +39,14 @@ module Enumerize
35
39
  end
36
40
  end
37
41
  end
42
+
43
+ def _define_sequel_shallow_scopes!(attribute_name)
44
+ enumerized_attributes[attribute_name].each_value do |value_obj|
45
+ def_dataset_method(value_obj) do
46
+ where(attribute_name => value_obj.value.to_s)
47
+ end
48
+ end
49
+ end
38
50
  end
39
51
  end
40
52
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module SequelSupport
3
5
  def enumerize(name, options={})
@@ -17,8 +19,11 @@ module Enumerize
17
19
  module InstanceMethods
18
20
  def validate
19
21
  super
20
-
22
+
21
23
  self.class.enumerized_attributes.each do |attr|
24
+ skip_validations = Utils.call_if_callable(attr.skip_validations_value, self)
25
+ next if skip_validations
26
+
22
27
  value = read_attribute_for_validation(attr.name)
23
28
  next if value.blank?
24
29
 
@@ -38,13 +43,13 @@ module Enumerize
38
43
  if defined?(Sequel::Plugins::Serialization::InstanceMethods)
39
44
  modules = self.class.ancestors
40
45
  plugin_idx = modules.index(Sequel::Plugins::Serialization::InstanceMethods)
41
-
46
+
42
47
  if plugin_idx && plugin_idx < modules.index(Enumerize::SequelSupport::InstanceMethods)
43
48
  abort "ERROR: You need to enable the Sequel serialization plugin before calling any enumerize methods on a model."
44
49
  end
45
-
50
+
46
51
  plugin_idx = modules.index(Sequel::Plugins::ValidationHelpers::InstanceMethods)
47
-
52
+
48
53
  if plugin_idx && plugin_idx < modules.index(Enumerize::SequelSupport::InstanceMethods)
49
54
  abort "ERROR: You need to enable the Sequel validation_helpers plugin before calling any enumerize methods on a model."
50
55
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/core_ext/module/delegation'
2
4
 
3
5
  module Enumerize
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enumerize
4
+ module Utils
5
+ class << self
6
+ def call_if_callable(value, param = nil)
7
+ return value unless value.respond_to?(:call)
8
+ value.arity == 0 ? value.call : value.call(param)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'i18n'
2
4
 
3
5
  module Enumerize
@@ -11,10 +13,16 @@ module Enumerize
11
13
  @value = value.nil? ? name.to_s : value
12
14
 
13
15
  super(name.to_s)
16
+
17
+ @i18n_keys = @attr.i18n_scopes.map { |s| :"#{s}.#{self}" }
18
+ @i18n_keys << :"enumerize.defaults.#{@attr.name}.#{self}"
19
+ @i18n_keys << :"enumerize.#{@attr.name}.#{self}"
20
+ @i18n_keys << self.underscore.humanize # humanize value if there are no translations
21
+ @i18n_keys
14
22
  end
15
23
 
16
24
  def text
17
- I18n.t(i18n_keys[0], :default => i18n_keys[1..-1])
25
+ I18n.t(@i18n_keys[0], :default => @i18n_keys[1..-1])
18
26
  end
19
27
 
20
28
  def ==(other)
@@ -30,19 +38,5 @@ module Enumerize
30
38
  def predicate_call(value)
31
39
  value == self
32
40
  end
33
-
34
- def i18n_keys
35
- @i18n_keys ||= begin
36
- i18n_keys = i18n_scopes
37
- i18n_keys << :"enumerize.defaults.#{@attr.name}.#{self}"
38
- i18n_keys << :"enumerize.#{@attr.name}.#{self}"
39
- i18n_keys << self.underscore.humanize # humanize value if there are no translations
40
- i18n_keys
41
- end
42
- end
43
-
44
- def i18n_scopes
45
- @attr.i18n_scopes.map { |s| :"#{s}.#{self}" }
46
- end
47
41
  end
48
42
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enumerize
4
- VERSION = '2.2.2'
4
+ VERSION = '2.3.1'
5
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sequel
2
4
  module Plugins
3
5
  module Enumerize
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_record'
2
4
 
3
5
  silence_warnings do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails'
2
4
  require 'enumerize'
3
5
  require 'rspec/matchers/fail_matchers'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  if defined?(::ActiveModel::Attributes)
@@ -44,7 +44,10 @@ ActiveRecord::Base.connection.instance_eval do
44
44
  t.string :name
45
45
  t.string :interests
46
46
  t.integer :status
47
+ t.text :settings
48
+ t.integer :skill
47
49
  t.string :account_type, :default => :basic
50
+ t.string :foo
48
51
  end
49
52
 
50
53
  create_table :documents do |t|
@@ -78,13 +81,18 @@ class User < ActiveRecord::Base
78
81
  extend Enumerize
79
82
  include RoleEnum
80
83
 
81
- enumerize :sex, :in => [:male, :female]
84
+ store :settings, accessors: [:language]
85
+
86
+ enumerize :sex, :in => [:male, :female], scope: :shallow
87
+ enumerize :language, :in => [:en, :jp]
82
88
 
83
89
  serialize :interests, Array
84
90
  enumerize :interests, :in => [:music, :sports, :dancing, :programming], :multiple => true
85
91
 
86
92
  enumerize :status, :in => { active: 1, blocked: 2 }, scope: true
87
93
 
94
+ enumerize :skill, :in => { noob: 0, casual: 1, pro: 2 }, scope: :shallow
95
+
88
96
  enumerize :account_type, :in => [:basic, :premium]
89
97
 
90
98
  # There is no column for relationship enumeration for testing purposes: model
@@ -103,6 +111,26 @@ class InterestsRequiredUser < User
103
111
  validates :interests, presence: true
104
112
  end
105
113
 
114
+ class SkipValidationsUser < ActiveRecord::Base
115
+ self.table_name = "users"
116
+ include SkipValidationsEnum
117
+ end
118
+
119
+ class DoNotSkipValidationsUser < ActiveRecord::Base
120
+ self.table_name = "users"
121
+ include DoNotSkipValidationsEnum
122
+ end
123
+
124
+ class SkipValidationsLambdaUser < ActiveRecord::Base
125
+ self.table_name = "users"
126
+ include SkipValidationsLambdaEnum
127
+ end
128
+
129
+ class SkipValidationsLambdaWithParamUser < ActiveRecord::Base
130
+ self.table_name = "users"
131
+ include SkipValidationsLambdaWithParamEnum
132
+ end
133
+
106
134
  describe Enumerize::ActiveRecordSupport do
107
135
  it 'sets nil if invalid value is passed' do
108
136
  user = User.new
@@ -128,6 +156,21 @@ describe Enumerize::ActiveRecordSupport do
128
156
  end
129
157
  end
130
158
 
159
+ it 'sets nil if invalid stored attribute value is passed' do
160
+ user = User.new
161
+ user.language = :invalid
162
+ user.language.must_be_nil
163
+ end
164
+
165
+ it 'saves stored attribute value' do
166
+ User.delete_all
167
+ user = User.new
168
+ user.language = :en
169
+ user.save!
170
+ user.reload
171
+ user.language.must_equal 'en'
172
+ end
173
+
131
174
  it 'has default value' do
132
175
  User.new.role.must_equal 'user'
133
176
  User.new.attributes['role'].must_equal 'user'
@@ -173,6 +216,14 @@ describe Enumerize::ActiveRecordSupport do
173
216
  user.errors[:role].must_include 'is not included in the list'
174
217
  end
175
218
 
219
+ it 'sets value to enumerized field from db when record is reloaded' do
220
+ user = User.create!(interests: [:music])
221
+ User.find(user.id).update(interests: %i[music dancing])
222
+ user.interests.must_equal %w[music]
223
+ user.reload
224
+ user.interests.must_equal %w[music dancing]
225
+ end
226
+
176
227
  it 'validates inclusion when using write_attribute with string attribute' do
177
228
  user = User.new
178
229
  user.send(:write_attribute, 'role', 'wrong')
@@ -212,6 +263,31 @@ describe Enumerize::ActiveRecordSupport do
212
263
  user.read_attribute(:role).must_be_nil
213
264
  end
214
265
 
266
+ it 'validates inclusion when :skip_validations = false' do
267
+ user = DoNotSkipValidationsUser.new
268
+ user.foo = 'wrong'
269
+ user.wont_be :valid?
270
+ user.errors[:foo].must_include 'is not included in the list'
271
+ end
272
+
273
+ it 'does not validate inclusion when :skip_validations = true' do
274
+ user = SkipValidationsUser.new
275
+ user.foo = 'wrong'
276
+ user.must_be :valid?
277
+ end
278
+
279
+ it 'supports :skip_validations option as lambda' do
280
+ user = SkipValidationsLambdaUser.new
281
+ user.foo = 'wrong'
282
+ user.must_be :valid?
283
+ end
284
+
285
+ it 'supports :skip_validations option as lambda with a parameter' do
286
+ user = SkipValidationsLambdaWithParamUser.new
287
+ user.foo = 'wrong'
288
+ user.must_be :valid?
289
+ end
290
+
215
291
  it 'supports multiple attributes' do
216
292
  user = User.new
217
293
  user.interests.must_be_empty
@@ -263,7 +339,11 @@ describe Enumerize::ActiveRecordSupport do
263
339
  it 'stores custom values for multiple attributes' do
264
340
  User.delete_all
265
341
 
266
- klass = Class.new(User)
342
+ klass = Class.new(User) do
343
+ def self.name
344
+ 'UserSubclass'
345
+ end
346
+ end
267
347
  klass.enumerize :interests, in: { music: 0, sports: 1, dancing: 2, programming: 3}, multiple: true
268
348
 
269
349
  user = klass.new
@@ -281,6 +361,7 @@ describe Enumerize::ActiveRecordSupport do
281
361
 
282
362
  user_1 = User.create!(status: :active, role: :admin)
283
363
  user_2 = User.create!(status: :blocked)
364
+ user_3 = User.create!(sex: :male, skill: :pro)
284
365
 
285
366
  User.with_status(:active).must_equal [user_1]
286
367
  User.with_status(:blocked).must_equal [user_2]
@@ -289,7 +370,8 @@ describe Enumerize::ActiveRecordSupport do
289
370
  User.without_status(:active).must_equal [user_2]
290
371
  User.without_status(:active, :blocked).must_equal []
291
372
 
292
- User.having_role(:admin).must_equal [user_1]
373
+ User.male.must_equal [user_3]
374
+ User.pro.must_equal [user_3]
293
375
  end
294
376
 
295
377
  it 'ignores not enumerized values that passed to the scope method' do
@@ -433,7 +515,11 @@ describe Enumerize::ActiveRecordSupport do
433
515
  it 'allows using update_all for multiple enumerize' do
434
516
  User.delete_all
435
517
 
436
- klass = Class.new(User)
518
+ klass = Class.new(User) do
519
+ def self.name
520
+ 'UserSubclass'
521
+ end
522
+ end
437
523
  klass.enumerize :interests, in: { music: 0, sports: 1, dancing: 2, programming: 3}, multiple: true
438
524
 
439
525
  user = klass.create(status: :active)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  module Enumerize
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  describe Enumerize::Attribute do
@@ -14,6 +16,11 @@ describe Enumerize::Attribute do
14
16
  attr.values.must_equal %w[a b]
15
17
  end
16
18
 
19
+ it 'returns frozen values' do
20
+ build_attr nil, :foo, :in => [:a, :b]
21
+ attr.values.map(&:frozen?).must_equal [true, true]
22
+ end
23
+
17
24
  it 'converts name to symbol' do
18
25
  build_attr nil, 'foo', :in => %w[a b]
19
26
  attr.name.must_equal :foo
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  describe Enumerize::Base do
@@ -43,7 +45,7 @@ describe Enumerize::Base do
43
45
 
44
46
  it 'scopes translation by i18n key' do
45
47
  def kklass.model_name
46
- name = "ExampleClass"
48
+ name = String.new("ExampleClass")
47
49
  def name.i18n_key
48
50
  'example_class'
49
51
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  Formtastic::FormBuilder.action_class_finder = Formtastic::ActionClassFinder
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class ModuleAttributesSpec < MiniTest::Spec
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  begin
@@ -16,9 +18,11 @@ describe Enumerize do
16
18
 
17
19
  key :sex
18
20
  key :role
21
+ key :foo
19
22
 
20
- enumerize :sex, :in => %w[male female]
23
+ enumerize :sex, :in => %w[male female]
21
24
  enumerize :role, :in => %w[admin user], :default => 'user'
25
+ enumerize :foo, :in => %w[bar baz], :skip_validations => true
22
26
  end
23
27
 
24
28
  before { $VERBOSE = nil }
@@ -60,6 +64,12 @@ describe Enumerize do
60
64
  user.wont_be :valid?
61
65
  end
62
66
 
67
+ it 'does not validate inclusion when :skip_validations option passed' do
68
+ user = model.new
69
+ user.foo = 'wrong'
70
+ user.must_be :valid?
71
+ end
72
+
63
73
  it 'assigns value on loaded record' do
64
74
  model.delete_all
65
75
  model.create!(:sex => :male)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  begin
@@ -18,10 +20,16 @@ describe Enumerize do
18
20
 
19
21
  field :sex
20
22
  field :role
23
+ field :foo
24
+ field :skill
25
+
21
26
  enumerize :sex, :in => %w[male female], scope: true
22
27
  enumerize :status, :in => %w[notice warning error], scope: true
23
28
  enumerize :role, :in => %w[admin user], :default => 'user', scope: :having_role
24
29
  enumerize :mult, :in => %w[one two three four], :multiple => true
30
+ enumerize :foo, :in => %w[bar baz], :skip_validations => true
31
+ enumerize :skill, :in => { noob: 0, casual: 1, pro: 2 }, scope: :shallow
32
+ enumerize :account_type, :in => %w[basic premium], scope: :shallow
25
33
  end
26
34
 
27
35
  before { $VERBOSE = nil }
@@ -78,6 +86,20 @@ describe Enumerize do
78
86
  user.wont_be :valid?
79
87
  end
80
88
 
89
+ it 'does not validate inclusion when :skip_validations option passed' do
90
+ user = model.new
91
+ user.foo = 'wrong'
92
+ user.must_be :valid?
93
+ end
94
+
95
+ it 'sets value to enumerized field from db when record is reloaded' do
96
+ user = model.create!(mult: [:one])
97
+ model.find(user.id).update(mult: %i[two three])
98
+ user.mult.must_equal %w[one]
99
+ user.reload
100
+ user.mult.must_equal %w[two three]
101
+ end
102
+
81
103
  it 'assigns value on loaded record' do
82
104
  model.delete_all
83
105
  model.create!(:sex => :male)
@@ -99,17 +121,21 @@ describe Enumerize do
99
121
 
100
122
  user_1 = model.create!(sex: :male, role: :admin)
101
123
  user_2 = model.create!(sex: :female, role: :user)
124
+ user_3 = model.create!(skill: :pro, account_type: :premium)
102
125
 
103
126
  model.with_sex(:male).to_a.must_equal [user_1]
104
127
  model.with_sex(:female).to_a.must_equal [user_2]
105
128
  model.with_sex(:male, :female).to_set.must_equal [user_1, user_2].to_set
106
129
 
107
- model.without_sex(:male).to_a.must_equal [user_2]
108
- model.without_sex(:female).to_a.must_equal [user_1]
109
- model.without_sex(:male, :female).to_a.must_equal []
130
+ model.without_sex(:male).to_set.must_equal [user_2, user_3].to_set
131
+ model.without_sex(:female).to_set.must_equal [user_1, user_3].to_set
132
+ model.without_sex(:male, :female).to_a.must_equal [user_3]
110
133
 
111
134
  model.having_role(:admin).to_a.must_equal [user_1]
112
- model.having_role(:user).to_a.must_equal [user_2]
135
+ model.having_role(:user).to_a.must_equal [user_2, user_3]
136
+
137
+ model.pro.to_a.must_equal [user_3]
138
+ model.premium.to_a.must_equal [user_3]
113
139
  end
114
140
 
115
141
  it 'chains scopes' do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  describe Enumerize::Base do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  describe Enumerize::Predicates do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class RailsAdminSpec < MiniTest::Spec
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'sequel'
3
5
  require 'logger'
@@ -21,7 +23,9 @@ module SequelTest
21
23
  String :name
22
24
  String :interests
23
25
  String :status
26
+ Integer :skill
24
27
  String :account_type, default: "basic"
28
+ String :foo
25
29
  end
26
30
 
27
31
  DB.create_table :documents do
@@ -50,12 +54,14 @@ module SequelTest
50
54
  plugin :enumerize
51
55
  include RoleEnum
52
56
 
53
- enumerize :sex, :in => [:male, :female]
57
+ enumerize :sex, :in => [:male, :female], scope: :shallow
54
58
 
55
59
  enumerize :interests, :in => [:music, :sports, :dancing, :programming], :multiple => true
56
60
 
57
61
  enumerize :status, :in => { active: 1, blocked: 2 }, scope: true
58
62
 
63
+ enumerize :skill, :in => { noob: 0, casual: 1, pro: 2 }, scope: :shallow
64
+
59
65
  enumerize :account_type, :in => [:basic, :premium]
60
66
  end
61
67
 
@@ -67,6 +73,22 @@ module SequelTest
67
73
  end
68
74
  end
69
75
 
76
+ class SkipValidationsUser < Sequel::Model(:users)
77
+ include SkipValidationsEnum
78
+ end
79
+
80
+ class DoNotSkipValidationsUser < Sequel::Model(:users)
81
+ include DoNotSkipValidationsEnum
82
+ end
83
+
84
+ class SkipValidationsLambdaUser < Sequel::Model(:users)
85
+ include SkipValidationsLambdaEnum
86
+ end
87
+
88
+ class SkipValidationsLambdaWithParamUser < Sequel::Model(:users)
89
+ include SkipValidationsLambdaWithParamEnum
90
+ end
91
+
70
92
  describe Enumerize::SequelSupport do
71
93
  it 'sets nil if invalid value is passed' do
72
94
  user = User.new
@@ -150,6 +172,31 @@ module SequelTest
150
172
  user.values[:role].must_be_nil
151
173
  end
152
174
 
175
+ it 'validates inclusion when :skip_validations = false' do
176
+ user = DoNotSkipValidationsUser.new
177
+ user.foo = 'wrong'
178
+ user.wont_be :valid?
179
+ user.errors[:foo].must_include 'is not included in the list'
180
+ end
181
+
182
+ it 'does not validate inclusion when :skip_validations = true' do
183
+ user = SkipValidationsUser.new
184
+ user.foo = 'wrong'
185
+ user.must_be :valid?
186
+ end
187
+
188
+ it 'supports :skip_validations option as lambda' do
189
+ user = SkipValidationsLambdaUser.new
190
+ user.foo = 'wrong'
191
+ user.must_be :valid?
192
+ end
193
+
194
+ it 'supports :skip_validations option as lambda with a parameter' do
195
+ user = SkipValidationsLambdaWithParamUser.new
196
+ user.foo = 'wrong'
197
+ user.must_be :valid?
198
+ end
199
+
153
200
  it 'supports multiple attributes' do
154
201
  user = User.new
155
202
  user.interests ||= []
@@ -212,6 +259,7 @@ module SequelTest
212
259
 
213
260
  user_1 = User.create(status: :active, role: :admin)
214
261
  user_2 = User.create(status: :blocked)
262
+ user_3 = User.create(sex: :male, skill: :pro)
215
263
 
216
264
  User.with_status(:active).to_a.must_equal [user_1]
217
265
  User.with_status(:blocked).to_a.must_equal [user_2]
@@ -221,6 +269,8 @@ module SequelTest
221
269
  User.without_status(:active, :blocked).to_a.must_equal []
222
270
 
223
271
  User.having_role(:admin).to_a.must_equal [user_1]
272
+ User.male.to_a.must_equal [user_3]
273
+ User.pro.to_a.must_equal [user_3]
224
274
  end
225
275
 
226
276
  it 'allows either key or value as valid' do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'yaml'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'simple_form/version'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class MockController
2
4
  attr_writer :action_name
3
5
 
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record'
4
+ require 'sequel'
5
+
6
+ module EnumerizeExtention
7
+ def self.included(base)
8
+ case
9
+ when base < ActiveRecord::Base
10
+ base.extend Enumerize
11
+ when base < Sequel::Model
12
+ base.plugin :enumerize
13
+ end
14
+ end
15
+ end
16
+
17
+ module SkipValidationsEnum
18
+ def self.included(base)
19
+ base.include EnumerizeExtention
20
+ base.enumerize :foo, :in => [:bar, :baz], :skip_validations => true
21
+ end
22
+ end
23
+
24
+ module DoNotSkipValidationsEnum
25
+ def self.included(base)
26
+ base.include EnumerizeExtention
27
+ base.enumerize :foo, :in => [:bar, :baz], :skip_validations => false
28
+ end
29
+ end
30
+
31
+ module SkipValidationsLambdaEnum
32
+ def self.included(base)
33
+ base.include EnumerizeExtention
34
+ base.enumerize :foo, :in => [:bar, :baz], :skip_validations => lambda { true }
35
+ end
36
+ end
37
+
38
+ module SkipValidationsLambdaWithParamEnum
39
+ def self.included(base)
40
+ base.include EnumerizeExtention
41
+ base.enumerize :foo, :in => [:bar, :baz], :skip_validations => lambda { |record| true }
42
+ end
43
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
  require 'active_support/testing/setup_and_teardown'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'minitest/autorun'
2
4
  require 'minitest/spec'
3
5
  require 'active_support/core_ext/kernel/reporting'
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'yaml'
3
5
 
4
6
  describe Enumerize::Value do
5
- class Attr < Struct.new(:values)
7
+ class Attr < Struct.new(:values, :name, :i18n_scopes)
6
8
  end
7
9
 
8
- let(:attr) { Attr.new([]) }
9
- let(:val) { Enumerize::Value.new(attr, 'test_value', 1) }
10
+ let(:attr) { Attr.new([], "attribute_name", []) }
11
+ let(:val) { Enumerize::Value.new(attr, 'test_value', 1) }
10
12
 
11
13
  it 'is a string' do
12
14
  val.must_be_kind_of String
@@ -30,7 +32,6 @@ describe Enumerize::Value do
30
32
  end
31
33
 
32
34
  describe 'translation' do
33
- let(:attr) { Struct.new(:values, :name, :i18n_scopes).new([], "attribute_name", []) }
34
35
 
35
36
  it 'uses common translation' do
36
37
  store_translations(:en, :enumerize => {:attribute_name => {:test_value => "Common translation"}}) do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enumerize
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 2.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergey Nartimov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-06 00:00:00.000000000 Z
11
+ date: 2019-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -68,6 +68,7 @@ files:
68
68
  - lib/enumerize/scope/sequel.rb
69
69
  - lib/enumerize/sequel.rb
70
70
  - lib/enumerize/set.rb
71
+ - lib/enumerize/utils.rb
71
72
  - lib/enumerize/value.rb
72
73
  - lib/enumerize/version.rb
73
74
  - lib/sequel/plugins/enumerize.rb
@@ -89,6 +90,7 @@ files:
89
90
  - test/set_test.rb
90
91
  - test/simple_form_test.rb
91
92
  - test/support/mock_controller.rb
93
+ - test/support/shared_enums.rb
92
94
  - test/support/view_test_helper.rb
93
95
  - test/test_helper.rb
94
96
  - test/value_test.rb
@@ -112,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
114
  version: '0'
113
115
  requirements: []
114
116
  rubyforge_project:
115
- rubygems_version: 2.7.3
117
+ rubygems_version: 2.7.6
116
118
  signing_key:
117
119
  specification_version: 4
118
120
  summary: Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper support
@@ -135,6 +137,7 @@ test_files:
135
137
  - test/set_test.rb
136
138
  - test/simple_form_test.rb
137
139
  - test/support/mock_controller.rb
140
+ - test/support/shared_enums.rb
138
141
  - test/support/view_test_helper.rb
139
142
  - test/test_helper.rb
140
143
  - test/value_test.rb