enumerize 2.2.2 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
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