careacademy-enumerize 2.8.0

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 (66) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby.yml +69 -0
  3. data/.gitignore +23 -0
  4. data/.rspec +2 -0
  5. data/CHANGELOG.md +327 -0
  6. data/Gemfile +6 -0
  7. data/Gemfile.global +12 -0
  8. data/Gemfile.mongo_mapper +6 -0
  9. data/Gemfile.rails60 +6 -0
  10. data/Gemfile.rails61 +6 -0
  11. data/Gemfile.rails70 +9 -0
  12. data/Gemfile.railsmaster +5 -0
  13. data/MIT-LICENSE +22 -0
  14. data/README.md +641 -0
  15. data/Rakefile +17 -0
  16. data/enumerize.gemspec +22 -0
  17. data/lib/enumerize/activemodel.rb +47 -0
  18. data/lib/enumerize/activerecord.rb +142 -0
  19. data/lib/enumerize/attribute.rb +192 -0
  20. data/lib/enumerize/attribute_map.rb +40 -0
  21. data/lib/enumerize/base.rb +112 -0
  22. data/lib/enumerize/hooks/formtastic.rb +27 -0
  23. data/lib/enumerize/hooks/sequel_dataset.rb +17 -0
  24. data/lib/enumerize/hooks/simple_form.rb +37 -0
  25. data/lib/enumerize/hooks/uniqueness.rb +22 -0
  26. data/lib/enumerize/integrations/rails_admin.rb +18 -0
  27. data/lib/enumerize/integrations/rspec/matcher.rb +164 -0
  28. data/lib/enumerize/integrations/rspec.rb +19 -0
  29. data/lib/enumerize/module.rb +33 -0
  30. data/lib/enumerize/module_attributes.rb +12 -0
  31. data/lib/enumerize/mongoid.rb +29 -0
  32. data/lib/enumerize/predicatable.rb +23 -0
  33. data/lib/enumerize/predicates.rb +76 -0
  34. data/lib/enumerize/scope/activerecord.rb +53 -0
  35. data/lib/enumerize/scope/mongoid.rb +50 -0
  36. data/lib/enumerize/scope/sequel.rb +56 -0
  37. data/lib/enumerize/sequel.rb +62 -0
  38. data/lib/enumerize/set.rb +81 -0
  39. data/lib/enumerize/utils.rb +12 -0
  40. data/lib/enumerize/value.rb +47 -0
  41. data/lib/enumerize/version.rb +5 -0
  42. data/lib/enumerize.rb +90 -0
  43. data/lib/sequel/plugins/enumerize.rb +18 -0
  44. data/spec/enumerize/integrations/rspec/matcher_spec.rb +261 -0
  45. data/spec/spec_helper.rb +30 -0
  46. data/test/activemodel_test.rb +114 -0
  47. data/test/activerecord_test.rb +679 -0
  48. data/test/attribute_map_test.rb +70 -0
  49. data/test/attribute_test.rb +141 -0
  50. data/test/base_test.rb +230 -0
  51. data/test/formtastic_test.rb +152 -0
  52. data/test/module_attributes_test.rb +52 -0
  53. data/test/mongo_mapper_test.rb +83 -0
  54. data/test/mongoid_test.rb +164 -0
  55. data/test/multiple_test.rb +65 -0
  56. data/test/predicates_test.rb +65 -0
  57. data/test/rails_admin_test.rb +27 -0
  58. data/test/sequel_test.rb +344 -0
  59. data/test/set_test.rb +166 -0
  60. data/test/simple_form_test.rb +156 -0
  61. data/test/support/mock_controller.rb +31 -0
  62. data/test/support/shared_enums.rb +43 -0
  63. data/test/support/view_test_helper.rb +46 -0
  64. data/test/test_helper.rb +53 -0
  65. data/test/value_test.rb +158 -0
  66. metadata +143 -0
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'i18n'
4
+ require 'active_support/inflector'
5
+
6
+ module Enumerize
7
+ class Value < String
8
+ include Predicatable
9
+
10
+ attr_reader :value
11
+
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
+
17
+ @attr = attr
18
+ @value = value.nil? ? name.to_s : value
19
+
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
27
+ end
28
+
29
+ def text
30
+ I18n.t(@i18n_keys[0], :default => @i18n_keys[1..-1]) if @i18n_keys
31
+ end
32
+
33
+ def ==(other)
34
+ super(other.to_s) || value == other
35
+ end
36
+
37
+ def encode_with(coder)
38
+ coder.represent_object(self.class.superclass, @value)
39
+ end
40
+
41
+ private
42
+
43
+ def predicate_call(value)
44
+ value == self
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Enumerize
4
+ VERSION = '2.8.0'
5
+ end
data/lib/enumerize.rb ADDED
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+ require 'active_support/core_ext/object/blank'
5
+ require 'enumerize/version'
6
+
7
+ module Enumerize
8
+ autoload :Attribute, 'enumerize/attribute'
9
+ autoload :AttributeMap, 'enumerize/attribute_map'
10
+ autoload :Value, 'enumerize/value'
11
+ autoload :Set, 'enumerize/set'
12
+ autoload :Base, 'enumerize/base'
13
+ autoload :Module, 'enumerize/module'
14
+ autoload :Predicates, 'enumerize/predicates'
15
+ autoload :Predicatable, 'enumerize/predicatable'
16
+ autoload :Utils, 'enumerize/utils'
17
+ autoload :ModuleAttributes, 'enumerize/module_attributes'
18
+
19
+ autoload :ActiveModelAttributesSupport, 'enumerize/activemodel'
20
+ autoload :ActiveRecordSupport, 'enumerize/activerecord'
21
+ autoload :SequelSupport, 'enumerize/sequel'
22
+ autoload :MongoidSupport, 'enumerize/mongoid'
23
+
24
+ module Scope
25
+ autoload :ActiveRecord, 'enumerize/scope/activerecord'
26
+ autoload :Sequel, 'enumerize/scope/sequel'
27
+ autoload :Mongoid, 'enumerize/scope/mongoid'
28
+ end
29
+
30
+ def self.included(base)
31
+ ActiveSupport::Deprecation.warn '`include Enumerize` was deprecated. Please use `extend Enumerize`.', caller
32
+ extended(base)
33
+ end
34
+
35
+ def self.extended(base)
36
+ base.send :include, Enumerize::Base
37
+ base.extend Enumerize::Predicates
38
+
39
+ if defined?(::ActiveModel::Attributes)
40
+ base.extend Enumerize::ActiveModelAttributesSupport
41
+ end
42
+
43
+ if defined?(::ActiveRecord::Base)
44
+ base.extend Enumerize::ActiveRecordSupport
45
+ base.extend Enumerize::Scope::ActiveRecord
46
+ end
47
+
48
+ if defined?(::Mongoid::Document)
49
+ base.extend Enumerize::MongoidSupport
50
+ base.extend Enumerize::Scope::Mongoid
51
+ end
52
+
53
+ if defined?(::Sequel::Model)
54
+ base.extend Enumerize::SequelSupport
55
+ base.extend Enumerize::Scope::Sequel
56
+ end
57
+
58
+ if defined?(::RailsAdmin)
59
+ require 'enumerize/integrations/rails_admin'
60
+ base.extend Enumerize::Integrations::RailsAdmin
61
+ end
62
+
63
+ if ::Module === base
64
+ base.extend Enumerize::Base::ClassMethods
65
+ base.extend Enumerize::ModuleAttributes
66
+ end
67
+
68
+ super
69
+ end
70
+
71
+ begin
72
+ require 'simple_form'
73
+ require 'enumerize/hooks/simple_form'
74
+ require 'enumerize/form_helper'
75
+ rescue LoadError
76
+ end
77
+
78
+ begin
79
+ require 'formtastic'
80
+ require 'enumerize/hooks/formtastic'
81
+ rescue LoadError
82
+ end
83
+
84
+ begin
85
+ require 'rspec'
86
+ rescue LoadError
87
+ else
88
+ require 'enumerize/integrations/rspec'
89
+ end
90
+ 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
@@ -0,0 +1,261 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record'
4
+
5
+ silence_warnings do
6
+ ActiveRecord::Migration.verbose = false
7
+ ActiveRecord::Base.logger = Logger.new(nil)
8
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
9
+ end
10
+
11
+ ActiveRecord::Base.connection.instance_eval do
12
+ create_table :users do |t|
13
+ t.string :sex
14
+ t.string :role
15
+ t.string :account_type
16
+ t.string :status
17
+ end
18
+ end
19
+
20
+ class User < ActiveRecord::Base
21
+ extend Enumerize
22
+
23
+ enumerize :sex, :in => [:male, :female], scope: true
24
+ enumerize :role, :in => [:user, :admin], scope: :having_role
25
+ enumerize :account_type, :in => [:basic, :premium]
26
+ enumerize :status, :in => [:active, :disabled], scope: :shallow
27
+ end
28
+
29
+ RSpec.describe Enumerize::Integrations::RSpec::Matcher do
30
+
31
+ let(:model) do
32
+ Class.new do
33
+ extend Enumerize
34
+
35
+ def self.name
36
+ 'Model'
37
+ end
38
+ end
39
+ end
40
+
41
+ subject do
42
+ model.new
43
+ end
44
+
45
+ describe 'without qualifier' do
46
+ it 'accepts when has defined a enumerize' do
47
+ model.enumerize(:sex, :in => [:male, :female])
48
+ expect(subject).to enumerize(:sex)
49
+ end
50
+
51
+ it 'rejects when has not defined a enumerize' do
52
+ message = 'Expected Model to define enumerize :sex'
53
+ expect do
54
+ expect(subject).to enumerize(:sex)
55
+ end.to fail_with(message)
56
+ end
57
+ end
58
+
59
+ describe '#in' do
60
+ context 'defined as array' do
61
+ before do
62
+ model.enumerize(:sex, :in => [:male, :female])
63
+ end
64
+
65
+ it 'accepts the right params as an array' do
66
+ expect(subject).to enumerize(:sex).in([:male, :female])
67
+ end
68
+
69
+ it 'accepts the right params as regular params' do
70
+ expect(subject).to enumerize(:sex).in(:male, :female)
71
+ end
72
+
73
+ it 'accepts the the right params in a different order' do
74
+ expect(subject).to enumerize(:sex).in(:female, :male)
75
+ end
76
+
77
+ it 'rejects wrong params' do
78
+ message = 'Expected Model to define enumerize :sex in: "boy", "girl"'
79
+ expect do
80
+ expect(subject).to enumerize(:sex).in(:boy, :girl)
81
+ end.to fail_with(message)
82
+ end
83
+
84
+ it 'has the right message when negated' do
85
+ message = 'Did not expect Model to define enumerize :sex in: "female", "male"'
86
+ expect do
87
+ expect(subject).to_not enumerize(:sex).in(:male, :female)
88
+ end.to fail_with(message)
89
+ end
90
+ end
91
+
92
+ context 'defined as hash' do
93
+ before do
94
+ model.enumerize(:sex, :in => { male: 0, female: 1 })
95
+ end
96
+
97
+ it 'accepts the right params as an array' do
98
+ expect(subject).to enumerize(:sex).in(:male, :female)
99
+ end
100
+
101
+ it 'accepts the right params as a hash' do
102
+ expect(subject).to enumerize(:sex).in(male: 0, female: 1)
103
+ end
104
+
105
+ it 'accepts the right params as a hash in a different order' do
106
+ expect(subject).to enumerize(:sex).in(female: 1, male: 0)
107
+ end
108
+
109
+ it 'rejects wrong keys' do
110
+ message = 'Expected Model to define enumerize :sex in: "{:boy=>0, :girl=>1}"'
111
+ expect do
112
+ expect(subject).to enumerize(:sex).in(boy: 0, girl: 1)
113
+ end.to fail_with(message)
114
+ end
115
+
116
+ it 'rejects wrong values' do
117
+ message = 'Expected Model to define enumerize :sex in: "{:male=>2, :female=>3}"'
118
+ expect do
119
+ expect(subject).to enumerize(:sex).in(male: 2, female: 3)
120
+ end.to fail_with(message)
121
+ end
122
+ end
123
+
124
+ it 'has the right description' do
125
+ matcher = enumerize(:sex).in(:male, :female)
126
+ expect(matcher.description).to eq('define enumerize :sex in: "female", "male"')
127
+ end
128
+ end
129
+
130
+ describe '#with_default' do
131
+ before do
132
+ model.enumerize(:sex, :in => [:male, :female], default: :female)
133
+ end
134
+
135
+ it 'accepts the right default value' do
136
+ expect(subject).to enumerize(:sex).in(:male, :female).with_default(:female)
137
+ end
138
+
139
+ it 'rejects the wrong default value' do
140
+ message = 'Expected Model to define enumerize :sex in: "female", "male" with "male" as default value'
141
+ expect do
142
+ expect(subject).to enumerize(:sex).in(:male, :female).with_default(:male)
143
+ end.to fail_with(message)
144
+ end
145
+
146
+ it 'rejects if the `in` is wrong with a correct default value' do
147
+ message = 'Expected Model to define enumerize :sex in: "boy", "girl" with "female" as default value'
148
+ expect do
149
+ expect(subject).to enumerize(:sex).in(:boy, :girl).with_default(:female)
150
+ end.to fail_with(message)
151
+ end
152
+
153
+ it 'has the right description' do
154
+ matcher = enumerize(:sex).in(:male, :female).with_default(:female)
155
+ message = 'define enumerize :sex in: "female", "male" with "female" as default value'
156
+ expect(matcher.description).to eq(message)
157
+ end
158
+ end
159
+
160
+ describe '#with_i18n_scope' do
161
+ context 'defined as string' do
162
+ before do
163
+ model.enumerize(:sex, :in => [:male, :female], i18n_scope: 'sex')
164
+ end
165
+
166
+ it 'accepts the right i18n_scope' do
167
+ expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope('sex')
168
+ end
169
+
170
+ it 'rejects the wrong i18n_scope' do
171
+ message = 'Expected Model to define enumerize :sex in: "female", "male" i18n_scope: "gender"'
172
+ expect do
173
+ expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope('gender')
174
+ end.to fail_with(message)
175
+ end
176
+ end
177
+
178
+ context 'defined as array' do
179
+
180
+ before do
181
+ model.enumerize(:sex, :in => [:male, :female], i18n_scope: ['sex', 'more.sex'])
182
+ end
183
+
184
+ it 'accepts the wrong i18n_scope' do
185
+ expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope(['sex', 'more.sex'])
186
+ end
187
+
188
+ it 'rejects the wrong i18n_scope' do
189
+ message = 'Expected Model to define enumerize :sex in: "female", "male" i18n_scope: ["sex"]'
190
+ expect do
191
+ expect(subject).to enumerize(:sex).in(:male, :female).with_i18n_scope(['sex'])
192
+ end.to fail_with(message)
193
+ end
194
+ end
195
+ end
196
+
197
+ describe '#with_predicates' do
198
+ it 'accepts when predicates is defined as a boolean' do
199
+ model.enumerize(:sex, :in => [:male, :female], predicates: true)
200
+ expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(true)
201
+ end
202
+
203
+ it 'accepts when predicates is defined as a hash' do
204
+ model.enumerize(:sex, :in => [:male, :female], predicates: { prefix: true })
205
+ expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(prefix: true)
206
+ end
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
+
213
+ it 'rejects when predicates is not defined' do
214
+ model.enumerize(:sex, :in => [:male, :female])
215
+ message = 'Expected Model to define enumerize :sex in: "female", "male" predicates: true'
216
+ expect do
217
+ expect(subject).to enumerize(:sex).in(:male, :female).with_predicates(true)
218
+ end.to fail_with(message)
219
+ end
220
+ end
221
+
222
+ describe '#with_multiple' do
223
+ it 'accepts when has defined the multiple' do
224
+ model.enumerize(:sex, :in => [:male, :female], multiple: true)
225
+ expect(subject).to enumerize(:sex).in(:male, :female).with_multiple(true)
226
+ end
227
+
228
+ it 'rejects when has not defined the multiple' do
229
+ model.enumerize(:sex, :in => [:male, :female])
230
+ message = 'Expected Model to define enumerize :sex in: "female", "male" multiple: true'
231
+ expect do
232
+ expect(subject).to enumerize(:sex).in(:male, :female).with_multiple(true)
233
+ end.to fail_with(message)
234
+ end
235
+ end
236
+
237
+ describe '#with_scope' do
238
+ subject do
239
+ User.new
240
+ end
241
+
242
+ it 'accepts when scope is defined as a boolean' do
243
+ expect(subject).to enumerize(:sex).in(:male, :female).with_scope(true)
244
+ end
245
+
246
+ it 'accepts when scope is defined as a hash' do
247
+ expect(subject).to enumerize(:role).in(:user, :admin).with_scope(scope: :having_role)
248
+ end
249
+
250
+ it 'accepts shallow scope' do
251
+ expect(subject).to enumerize(:status).in(:active, :disabled).with_scope(:shallow)
252
+ end
253
+
254
+ it 'rejects when scope is not defined' do
255
+ message = 'Expected User to define enumerize :account_type in: "basic", "premium" scope: true'
256
+ expect do
257
+ expect(subject).to enumerize(:account_type).in(:basic, :premium).with_scope(true)
258
+ end.to fail_with(message)
259
+ end
260
+ end
261
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails'
4
+ require 'enumerize'
5
+ require 'rspec/matchers/fail_matchers'
6
+
7
+ RSpec.configure do |config|
8
+ config.disable_monkey_patching!
9
+ config.order = :random
10
+ Kernel.srand config.seed
11
+ config.filter_run focus: true
12
+ config.run_all_when_everything_filtered = true
13
+
14
+ config.expect_with :rspec do |expectations|
15
+ expectations.syntax = :expect
16
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
17
+ end
18
+
19
+ config.mock_with :rspec do |mocks|
20
+ mocks.syntax = :expect
21
+ mocks.verify_partial_doubles = true
22
+ end
23
+
24
+ if config.files_to_run.one?
25
+ config.default_formatter = 'doc'
26
+ end
27
+
28
+ config.warnings = true
29
+ config.include RSpec::Matchers::FailMatchers
30
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ if defined?(::ActiveModel::Attributes)
6
+
7
+ describe Enumerize do
8
+ class ActiveModelUser
9
+ include ActiveModel::Model
10
+ include ActiveModel::Attributes
11
+ extend Enumerize
12
+
13
+ attribute :name, :string
14
+ enumerize :sex, :in => %w[male female]
15
+ enumerize :role, :in => %w[admin user], :default => 'user'
16
+ enumerize :interests, :in => [:music, :sports, :dancing, :programming], :multiple => true
17
+ end
18
+
19
+ class InterestsRequiredActiveModelUser < ActiveModelUser
20
+ validates :interests, presence: true
21
+ end
22
+
23
+ let(:model) { ActiveModelUser }
24
+
25
+ it 'initialize value' do
26
+ user = model.new(:name => 'active_model_user', :sex => :male, :role => :user, :interests => [:music, :programming])
27
+ expect(user.sex).must_equal 'male'
28
+ expect(user.sex_text).must_equal 'Male'
29
+ expect(user.role).must_equal 'user'
30
+ expect(user.role_text).must_equal 'User'
31
+ expect(user.interests).must_equal %w(music programming)
32
+ end
33
+
34
+ it 'sets nil if invalid value is passed' do
35
+ user = model.new
36
+ user.sex = :invalid
37
+ expect(user.sex).must_be_nil
38
+ end
39
+
40
+ it 'stores value' do
41
+ user = model.new
42
+ user.sex = :female
43
+ expect(user.sex).must_equal 'female'
44
+ end
45
+
46
+ it 'has default value' do
47
+ expect(model.new.role).must_equal 'user'
48
+ end
49
+
50
+ it 'validates inclusion' do
51
+ user = model.new
52
+ user.role = 'wrong'
53
+ expect(user).wont_be :valid?
54
+ end
55
+
56
+ it 'supports multiple attributes' do
57
+ user = ActiveModelUser.new
58
+ expect(user.interests).must_be_instance_of Enumerize::Set
59
+ expect(user.interests).must_be_empty
60
+ user.interests << :music
61
+ expect(user.interests).must_equal %w(music)
62
+ user.interests << :sports
63
+ expect(user.interests).must_equal %w(music sports)
64
+
65
+ user.interests = []
66
+ interests = user.interests
67
+ interests << :music
68
+ expect(interests).must_equal %w(music)
69
+ interests << :dancing
70
+ expect(interests).must_equal %w(music dancing)
71
+ end
72
+
73
+ it 'returns invalid multiple value for validation' do
74
+ user = ActiveModelUser.new
75
+ user.interests << :music
76
+ user.interests << :invalid
77
+ values = user.read_attribute_for_validation(:interests)
78
+ expect(values).must_equal %w(music invalid)
79
+ end
80
+
81
+ it 'validates multiple attributes' do
82
+ user = ActiveModelUser.new
83
+ user.interests << :invalid
84
+ expect(user).wont_be :valid?
85
+
86
+ user.interests = Object.new
87
+ expect(user).wont_be :valid?
88
+
89
+ user.interests = ['music', '']
90
+ expect(user).must_be :valid?
91
+ end
92
+
93
+ it 'validates presence with multiple attributes' do
94
+ user = InterestsRequiredActiveModelUser.new
95
+ user.interests = []
96
+ user.valid?
97
+
98
+ expect(user.errors[:interests]).wont_be :empty?
99
+
100
+ user.interests = ['']
101
+ user.valid?
102
+
103
+ expect(user.errors[:interests]).wont_be :empty?
104
+
105
+ user.interests = [:dancing, :programming]
106
+ user.valid?
107
+
108
+ expect(user.errors[:interests]).must_be_empty
109
+ end
110
+ end
111
+
112
+ else
113
+ # Skip
114
+ end