enumerize 2.1.2 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +10 -9
  3. data/CHANGELOG.md +50 -3
  4. data/Gemfile +2 -3
  5. data/Gemfile.global +1 -2
  6. data/Gemfile.mongo_mapper +2 -3
  7. data/Gemfile.rails60 +6 -0
  8. data/Gemfile.rails61 +6 -0
  9. data/README.md +37 -1
  10. data/Rakefile +2 -0
  11. data/lib/enumerize.rb +9 -0
  12. data/lib/enumerize/activemodel.rb +47 -0
  13. data/lib/enumerize/activerecord.rb +33 -3
  14. data/lib/enumerize/attribute.rb +19 -11
  15. data/lib/enumerize/attribute_map.rb +2 -0
  16. data/lib/enumerize/base.rb +6 -6
  17. data/lib/enumerize/hooks/formtastic.rb +4 -1
  18. data/lib/enumerize/hooks/sequel_dataset.rb +2 -0
  19. data/lib/enumerize/hooks/simple_form.rb +4 -1
  20. data/lib/enumerize/hooks/uniqueness.rb +5 -1
  21. data/lib/enumerize/integrations/rails_admin.rb +3 -1
  22. data/lib/enumerize/integrations/rspec.rb +2 -0
  23. data/lib/enumerize/integrations/rspec/matcher.rb +7 -2
  24. data/lib/enumerize/module.rb +2 -0
  25. data/lib/enumerize/module_attributes.rb +2 -0
  26. data/lib/enumerize/mongoid.rb +16 -0
  27. data/lib/enumerize/predicatable.rb +3 -1
  28. data/lib/enumerize/predicates.rb +2 -0
  29. data/lib/enumerize/scope/activerecord.rb +12 -0
  30. data/lib/enumerize/scope/mongoid.rb +11 -0
  31. data/lib/enumerize/scope/sequel.rb +12 -0
  32. data/lib/enumerize/sequel.rb +9 -4
  33. data/lib/enumerize/set.rb +2 -0
  34. data/lib/enumerize/utils.rb +12 -0
  35. data/lib/enumerize/value.rb +14 -15
  36. data/lib/enumerize/version.rb +1 -1
  37. data/lib/sequel/plugins/enumerize.rb +18 -0
  38. data/spec/enumerize/integrations/rspec/matcher_spec.rb +13 -10
  39. data/spec/spec_helper.rb +2 -0
  40. data/test/activemodel_test.rb +114 -0
  41. data/test/activerecord_test.rb +127 -5
  42. data/test/attribute_map_test.rb +2 -0
  43. data/test/attribute_test.rb +7 -0
  44. data/test/base_test.rb +35 -33
  45. data/test/formtastic_test.rb +25 -0
  46. data/test/module_attributes_test.rb +2 -0
  47. data/test/mongo_mapper_test.rb +12 -3
  48. data/test/mongoid_test.rb +30 -4
  49. data/test/multiple_test.rb +19 -11
  50. data/test/predicates_test.rb +12 -10
  51. data/test/rails_admin_test.rb +7 -5
  52. data/test/sequel_test.rb +62 -12
  53. data/test/set_test.rb +6 -4
  54. data/test/simple_form_test.rb +25 -0
  55. data/test/support/mock_controller.rb +2 -0
  56. data/test/support/shared_enums.rb +43 -0
  57. data/test/support/view_test_helper.rb +14 -1
  58. data/test/test_helper.rb +2 -0
  59. data/test/value_test.rb +33 -5
  60. metadata +15 -9
  61. data/Gemfile.rails42 +0 -7
  62. data/Gemfile.rails51 +0 -7
@@ -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
@@ -5,7 +7,8 @@ module Enumerize
5
7
  module FormtasticFormBuilderExtension
6
8
 
7
9
  def input(method, options={})
8
- klass = object.class
10
+ enumerized_object = convert_to_model(object)
11
+ klass = enumerized_object.class
9
12
 
10
13
  if klass.respond_to?(:enumerized_attributes) && (attr = klass.enumerized_attributes[method])
11
14
  options[:collection] ||= attr.options
@@ -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
@@ -17,7 +19,8 @@ module Enumerize
17
19
  private
18
20
 
19
21
  def add_input_options_for_enumerized_attribute(attribute_name, options)
20
- klass = object.class
22
+ enumerized_object = convert_to_model(object)
23
+ klass = enumerized_object.class
21
24
 
22
25
  if klass.respond_to?(:enumerized_attributes) && (attr = klass.enumerized_attributes[attribute_name])
23
26
  options[:collection] ||= attr.options
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
 
3
5
  module Enumerize
@@ -5,7 +7,9 @@ module Enumerize
5
7
  module UniquenessValidator
6
8
 
7
9
  def validate_each(record, name, value)
8
- if record.class.respond_to?(:enumerized_attributes) && (attr = record.class.enumerized_attributes[name])
10
+ klass = record.to_model.class
11
+
12
+ if klass.respond_to?(:enumerized_attributes) && (attr = klass.enumerized_attributes[name])
9
13
  value = attr.find_value(value).try(:value)
10
14
  end
11
15
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerize
2
4
  module Integrations
3
5
  module RailsAdmin
@@ -7,7 +9,7 @@ module Enumerize
7
9
 
8
10
  _enumerize_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
9
11
  def #{name}_enum
10
- self.class.enumerized_attributes[:#{name}].values.map{|v| [v.text, v.value]}
12
+ self.class.enumerized_attributes[:#{name}].options
11
13
  end
12
14
  RUBY
13
15
  end
@@ -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
@@ -108,7 +110,7 @@ module Enumerize
108
110
 
109
111
  def matches_predicates?
110
112
  if expected_predicates.is_a?(TrueClass)
111
- subject.respond_to?("#{sorted_values.first}?")
113
+ subject.respond_to?("#{enumerized_values.first}?")
112
114
  else
113
115
  subject.respond_to?("#{expected_attr}_#{attributes.values.first}?")
114
116
  end
@@ -119,8 +121,11 @@ module Enumerize
119
121
  end
120
122
 
121
123
  def matches_scope?
122
- if expected_scope.is_a?(TrueClass)
124
+ case expected_scope
125
+ when TrueClass
123
126
  subject_class.respond_to?("with_#{expected_attr}")
127
+ when :shallow
128
+ enumerized_values.all? { |value| subject_class.respond_to?(value) }
124
129
  else
125
130
  subject_class.respond_to?(expected_scope[:scope])
126
131
  end
@@ -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)
@@ -15,7 +17,7 @@ module Enumerize
15
17
  end
16
18
 
17
19
  def predicate_method?(method)
18
- method[-1] == '?' && @attr.values.include?(method[0..-2])
20
+ method[-1] == '?' && @attr && @attr.values.include?(method[0..-2])
19
21
  end
20
22
  end
21
23
  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
@@ -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,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'i18n'
4
+ require 'active_support/inflector'
2
5
 
3
6
  module Enumerize
4
7
  class Value < String
@@ -7,14 +10,24 @@ module Enumerize
7
10
  attr_reader :value
8
11
 
9
12
  def initialize(attr, name, value=nil)
13
+ if self.class.method_defined?("#{name}?")
14
+ warn("It's not recommended to use `#{name}` as a field value since `#{name}?` is defined. (#{attr.klass.name}##{attr.name})")
15
+ end
16
+
10
17
  @attr = attr
11
18
  @value = value.nil? ? name.to_s : value
12
19
 
13
20
  super(name.to_s)
21
+
22
+ @i18n_keys = @attr.i18n_scopes.map { |s| :"#{s}.#{self}" }
23
+ @i18n_keys << :"enumerize.defaults.#{@attr.name}.#{self}"
24
+ @i18n_keys << :"enumerize.#{@attr.name}.#{self}"
25
+ @i18n_keys << ActiveSupport::Inflector.humanize(ActiveSupport::Inflector.underscore(self)) # humanize value if there are no translations
26
+ @i18n_keys
14
27
  end
15
28
 
16
29
  def text
17
- I18n.t(i18n_keys[0], :default => i18n_keys[1..-1])
30
+ I18n.t(@i18n_keys[0], :default => @i18n_keys[1..-1]) if @i18n_keys
18
31
  end
19
32
 
20
33
  def ==(other)
@@ -30,19 +43,5 @@ module Enumerize
30
43
  def predicate_call(value)
31
44
  value == self
32
45
  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
46
  end
48
47
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enumerize
4
- VERSION = '2.1.2'
4
+ VERSION = '2.4.0'
5
5
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sequel
4
+ module Plugins
5
+ module Enumerize
6
+ # Depend on the def_dataset_method plugin
7
+ def self.apply(model)
8
+ model.plugin(:def_dataset_method) unless model.respond_to?(:def_dataset_method)
9
+ end
10
+
11
+ module InstanceMethods
12
+ def self.included(base)
13
+ base.extend ::Enumerize
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_record'
2
4
 
3
5
  silence_warnings do
@@ -11,6 +13,7 @@ ActiveRecord::Base.connection.instance_eval do
11
13
  t.string :sex
12
14
  t.string :role
13
15
  t.string :account_type
16
+ t.string :status
14
17
  end
15
18
  end
16
19
 
@@ -20,6 +23,7 @@ class User < ActiveRecord::Base
20
23
  enumerize :sex, :in => [:male, :female], scope: true
21
24
  enumerize :role, :in => [:user, :admin], scope: :having_role
22
25
  enumerize :account_type, :in => [:basic, :premium]
26
+ enumerize :status, :in => [:active, :disabled], scope: :shallow
23
27
  end
24
28
 
25
29
  RSpec.describe Enumerize::Integrations::RSpec::Matcher do
@@ -39,7 +43,6 @@ RSpec.describe Enumerize::Integrations::RSpec::Matcher do
39
43
  end
40
44
 
41
45
  describe 'without qualifier' do
42
-
43
46
  it 'accepts when has defined a enumerize' do
44
47
  model.enumerize(:sex, :in => [:male, :female])
45
48
  expect(subject).to enumerize(:sex)
@@ -54,9 +57,7 @@ RSpec.describe Enumerize::Integrations::RSpec::Matcher do
54
57
  end
55
58
 
56
59
  describe '#in' do
57
-
58
60
  context 'defined as array' do
59
-
60
61
  before do
61
62
  model.enumerize(:sex, :in => [:male, :female])
62
63
  end
@@ -89,7 +90,6 @@ RSpec.describe Enumerize::Integrations::RSpec::Matcher do
89
90
  end
90
91
 
91
92
  context 'defined as hash' do
92
-
93
93
  before do
94
94
  model.enumerize(:sex, :in => { male: 0, female: 1 })
95
95
  end
@@ -128,7 +128,6 @@ RSpec.describe Enumerize::Integrations::RSpec::Matcher do
128
128
  end
129
129
 
130
130
  describe '#with_default' do
131
-
132
131
  before do
133
132
  model.enumerize(:sex, :in => [:male, :female], default: :female)
134
133
  end
@@ -159,9 +158,7 @@ RSpec.describe Enumerize::Integrations::RSpec::Matcher do
159
158
  end
160
159
 
161
160
  describe '#with_i18n_scope' do
162
-
163
161
  context 'defined as string' do
164
-
165
162
  before do
166
163
  model.enumerize(:sex, :in => [:male, :female], i18n_scope: 'sex')
167
164
  end
@@ -198,7 +195,6 @@ RSpec.describe Enumerize::Integrations::RSpec::Matcher do
198
195
  end
199
196
 
200
197
  describe '#with_predicates' do
201
-
202
198
  it 'accepts when predicates is defined as a boolean' do
203
199
  model.enumerize(:sex, :in => [:male, :female], predicates: true)
204
200
  expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(true)
@@ -209,6 +205,11 @@ RSpec.describe Enumerize::Integrations::RSpec::Matcher do
209
205
  expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(prefix: true)
210
206
  end
211
207
 
208
+ it 'accepts when custom values are used as attribute' do
209
+ model.enumerize(:sex, :in => { male: 0, female: 1 }, predicates: true)
210
+ expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(true)
211
+ end
212
+
212
213
  it 'rejects when predicates is not defined' do
213
214
  model.enumerize(:sex, :in => [:male, :female])
214
215
  message = 'Expected Model to define enumerize :sex in: "female", "male" predicates: true'
@@ -219,7 +220,6 @@ RSpec.describe Enumerize::Integrations::RSpec::Matcher do
219
220
  end
220
221
 
221
222
  describe '#with_multiple' do
222
-
223
223
  it 'accepts when has defined the multiple' do
224
224
  model.enumerize(:sex, :in => [:male, :female], multiple: true)
225
225
  expect(subject).to enumerize(:sex).in(:male, :female).with_multiple(true)
@@ -235,7 +235,6 @@ RSpec.describe Enumerize::Integrations::RSpec::Matcher do
235
235
  end
236
236
 
237
237
  describe '#with_scope' do
238
-
239
238
  subject do
240
239
  User.new
241
240
  end
@@ -248,6 +247,10 @@ RSpec.describe Enumerize::Integrations::RSpec::Matcher do
248
247
  expect(subject).to enumerize(:role).in(:user, :admin).with_scope(scope: :having_role)
249
248
  end
250
249
 
250
+ it 'accepts shallow scope' do
251
+ expect(subject).to enumerize(:status).in(:active, :disabled).with_scope(:shallow)
252
+ end
253
+
251
254
  it 'rejects when scope is not defined' do
252
255
  message = 'Expected User to define enumerize :account_type in: "basic", "premium" scope: true'
253
256
  expect do