enumerize 0.3.0 → 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 (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -1
  3. data/.rspec +2 -0
  4. data/.travis.yml +38 -11
  5. data/CHANGELOG.md +258 -0
  6. data/Gemfile +5 -11
  7. data/Gemfile.global +20 -0
  8. data/Gemfile.mongo_mapper +7 -0
  9. data/Gemfile.rails42 +7 -0
  10. data/Gemfile.rails50 +7 -0
  11. data/Gemfile.rails52 +7 -0
  12. data/README.md +405 -17
  13. data/Rakefile +7 -1
  14. data/enumerize.gemspec +6 -3
  15. data/lib/enumerize/activemodel.rb +47 -0
  16. data/lib/enumerize/activerecord.rb +127 -2
  17. data/lib/enumerize/attribute.rb +167 -7
  18. data/lib/enumerize/attribute_map.rb +4 -0
  19. data/lib/enumerize/base.rb +60 -61
  20. data/lib/enumerize/hooks/formtastic.rb +11 -12
  21. data/lib/enumerize/hooks/sequel_dataset.rb +17 -0
  22. data/lib/enumerize/hooks/simple_form.rb +21 -8
  23. data/lib/enumerize/hooks/uniqueness.rb +22 -0
  24. data/lib/enumerize/integrations/rails_admin.rb +18 -0
  25. data/lib/enumerize/integrations/rspec/matcher.rb +161 -0
  26. data/lib/enumerize/integrations/rspec.rb +19 -0
  27. data/lib/enumerize/module.rb +33 -0
  28. data/lib/enumerize/module_attributes.rb +3 -2
  29. data/lib/enumerize/mongoid.rb +29 -0
  30. data/lib/enumerize/predicatable.rb +23 -0
  31. data/lib/enumerize/predicates.rb +76 -0
  32. data/lib/enumerize/scope/activerecord.rb +49 -0
  33. data/lib/enumerize/scope/mongoid.rb +46 -0
  34. data/lib/enumerize/scope/sequel.rb +52 -0
  35. data/lib/enumerize/sequel.rb +62 -0
  36. data/lib/enumerize/set.rb +81 -0
  37. data/lib/enumerize/utils.rb +12 -0
  38. data/lib/enumerize/value.rb +19 -46
  39. data/lib/enumerize/version.rb +3 -1
  40. data/lib/enumerize.rb +56 -4
  41. data/lib/sequel/plugins/enumerize.rb +18 -0
  42. data/spec/enumerize/integrations/rspec/matcher_spec.rb +260 -0
  43. data/spec/spec_helper.rb +30 -0
  44. data/test/activemodel_test.rb +114 -0
  45. data/test/activerecord_test.rb +542 -8
  46. data/test/attribute_map_test.rb +2 -0
  47. data/test/attribute_test.rb +102 -4
  48. data/test/base_test.rb +61 -39
  49. data/test/formtastic_test.rb +102 -17
  50. data/test/module_attributes_test.rb +25 -2
  51. data/test/mongo_mapper_test.rb +84 -0
  52. data/test/mongoid_test.rb +98 -7
  53. data/test/multiple_test.rb +59 -0
  54. data/test/predicates_test.rb +65 -0
  55. data/test/rails_admin_test.rb +27 -0
  56. data/test/sequel_test.rb +341 -0
  57. data/test/set_test.rb +166 -0
  58. data/test/simple_form_test.rb +110 -4
  59. data/test/support/mock_controller.rb +11 -1
  60. data/test/support/shared_enums.rb +43 -0
  61. data/test/support/view_test_helper.rb +6 -0
  62. data/test/test_helper.rb +25 -6
  63. data/test/value_test.rb +102 -13
  64. metadata +62 -28
  65. data/gemfiles/Gemfile-ar-3.1.x +0 -13
data/test/set_test.rb ADDED
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'yaml'
5
+
6
+ describe Enumerize::Set do
7
+ let(:kklass) do
8
+ Class.new do
9
+ extend Enumerize
10
+ enumerize :foo, :in => %w(a b c), :multiple => true
11
+ end
12
+ end
13
+
14
+ let(:object) { kklass.new }
15
+
16
+ def build_set(values)
17
+ @set = Enumerize::Set.new(object, kklass.foo, values)
18
+ end
19
+
20
+ def set
21
+ @set
22
+ end
23
+
24
+ def assert_called(object, method)
25
+ called = false
26
+
27
+ object.singleton_class.class_eval do
28
+ define_method method do |*args, &block|
29
+ called = true
30
+ super(*args, &block)
31
+ end
32
+ end
33
+
34
+ yield
35
+
36
+ assert called, "Expected ##{method} to be called"
37
+ end
38
+
39
+ before do
40
+ build_set %w(a)
41
+ end
42
+
43
+ it 'equals to other set' do
44
+ set.must_equal Enumerize::Set.new(nil, kklass.foo, %w(a))
45
+ end
46
+
47
+ it 'equals to array' do
48
+ set.must_equal %w(a)
49
+ end
50
+
51
+ it 'equals to array of symbols' do
52
+ set.must_equal [:a]
53
+ end
54
+
55
+ it 'has unique values' do
56
+ set << :a
57
+ set.must_equal %w(a)
58
+ end
59
+
60
+ it 'equals to array with different value order' do
61
+ set << :b
62
+ set.must_equal %w(b a)
63
+ end
64
+
65
+ it "isn't equal to a part of values" do
66
+ set << :b
67
+ set.wont_equal %w(a)
68
+ end
69
+
70
+ describe '#push' do
71
+ it 'appends values' do
72
+ set.push :b
73
+ set.must_include :b
74
+ end
75
+
76
+ it 'reassigns attribute' do
77
+ assert_called object, :foo= do
78
+ set.push :b
79
+ end
80
+ end
81
+ end
82
+
83
+ describe '#delete' do
84
+ it 'deletes value' do
85
+ set.delete :a
86
+ set.wont_include :a
87
+ end
88
+
89
+ it 'reassigns attribute' do
90
+ assert_called object, :foo= do
91
+ set.delete :a
92
+ end
93
+ end
94
+ end
95
+
96
+ describe '#inspect' do
97
+ it 'returns custom string' do
98
+ set << :b
99
+ set.inspect.must_equal '#<Enumerize::Set {a, b}>'
100
+ end
101
+ end
102
+
103
+ describe '#to_ary' do
104
+ it 'returns array' do
105
+ set.to_ary.must_be_instance_of Array
106
+ end
107
+ end
108
+
109
+ describe '#texts' do
110
+ it 'returns array of text values' do
111
+ set.texts.must_equal ['A']
112
+ end
113
+ end
114
+
115
+ describe '#join' do
116
+ it 'joins values' do
117
+ set << :b
118
+ set.join(', ').must_equal 'a, b'
119
+ end
120
+ end
121
+
122
+ describe 'boolean methods comparison' do
123
+ it 'returns true if value equals method' do
124
+ set << :a
125
+ set.a?.must_equal true
126
+ end
127
+
128
+ it 'returns false if value does not equal method' do
129
+ set << :a
130
+ set.b?.must_equal false
131
+ end
132
+
133
+ it 'raises NoMethodError if there are no values like boolean method' do
134
+ proc {
135
+ set.some_method?
136
+ }.must_raise NoMethodError
137
+ end
138
+
139
+ it 'raises ArgumentError if arguments are passed' do
140
+ proc {
141
+ set.a?('<3')
142
+ }.must_raise ArgumentError
143
+ end
144
+
145
+ it 'responds to methods for existing values' do
146
+ set.must_respond_to :a?
147
+ set.must_respond_to :b?
148
+ set.must_respond_to :c?
149
+ end
150
+
151
+ it 'returns a method object' do
152
+ set.method(:a?).must_be_instance_of Method
153
+ end
154
+
155
+ it 'does not respond to a method for not existing value' do
156
+ set.wont_respond_to :some_method?
157
+ end
158
+ end
159
+
160
+ describe 'serialization' do
161
+ it 'is serialized to yaml as array' do
162
+ set << :a
163
+ assert_equal YAML.dump(%w(a)), YAML.dump(set)
164
+ end
165
+ end
166
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'simple_form/version'
3
5
 
@@ -5,11 +7,20 @@ class SimpleFormSpec < MiniTest::Spec
5
7
  include ViewTestHelper
6
8
  include SimpleForm::ActionViewExtensions::FormHelper
7
9
 
10
+ class Thing < Struct.new(:name)
11
+ extend ActiveModel::Naming
12
+ include ActiveModel::Conversion
13
+
14
+ def persisted?
15
+ false
16
+ end
17
+ end
18
+
8
19
  class User < Struct.new(:sex, :age)
9
20
  extend ActiveModel::Naming
10
21
  include ActiveModel::Conversion
11
22
 
12
- include Enumerize
23
+ extend Enumerize
13
24
 
14
25
  enumerize :sex, :in => [:male, :female]
15
26
 
@@ -18,7 +29,36 @@ class SimpleFormSpec < MiniTest::Spec
18
29
  end
19
30
  end
20
31
 
32
+ class Post < Struct.new(:category, :title)
33
+ extend ActiveModel::Naming
34
+ include ActiveModel::Conversion
35
+
36
+ extend Enumerize
37
+
38
+ enumerize :categories, :in => [:music, :games], :multiple => true
39
+
40
+ def persisted?
41
+ false
42
+ end
43
+ end
44
+
45
+ class Registration < Struct.new(:sex)
46
+ extend Enumerize
47
+
48
+ enumerize :sex, in: [:male, :female]
49
+ end
50
+
21
51
  let(:user) { User.new }
52
+ let(:post) { Post.new }
53
+
54
+ it 'renders select with enumerized values using input_field' do
55
+ concat(simple_form_for(user) do |f|
56
+ f.input_field(:sex)
57
+ end)
58
+
59
+ assert_select 'select option[value=male]'
60
+ assert_select 'select option[value=female]'
61
+ end
22
62
 
23
63
  it 'renders select with enumerized values' do
24
64
  concat(simple_form_for(user) do |f|
@@ -29,11 +69,52 @@ class SimpleFormSpec < MiniTest::Spec
29
69
  assert_select 'select option[value=female]'
30
70
  end
31
71
 
32
- it 'renders radio buttons with enumerated values' do
33
- as = SimpleForm::VERSION > '2.0' ? :radio_buttons : :radio
72
+ it 'renders multiple select with enumerized values' do
73
+ concat(simple_form_for(post) do |f|
74
+ f.input(:categories)
75
+ end)
76
+
77
+ assert_select 'select[multiple=multiple]'
78
+ assert_select 'select option[value=music]'
79
+ assert_select 'select option[value=games]'
80
+ end
34
81
 
82
+ it 'renders multiple select with selected enumerized value' do
83
+ post.categories << :music
84
+
85
+ concat(simple_form_for(post) do |f|
86
+ f.input(:categories)
87
+ end)
88
+
89
+ assert_select 'select[multiple=multiple]'
90
+ assert_select 'select option[value=music][selected=selected]'
91
+ assert_select 'select option[value=games][selected=selected]', count: 0
92
+ end
93
+
94
+ it 'renders checkboxes with enumerized values' do
95
+ concat(simple_form_for(post) do |f|
96
+ f.input(:categories, as: :check_boxes)
97
+ end)
98
+
99
+ assert_select 'select[multiple=multiple]', count: 0
100
+ assert_select 'input[type=checkbox][value=music]'
101
+ assert_select 'input[type=checkbox][value=games]'
102
+ end
103
+
104
+ it 'renders checkboxes with selected enumerized value' do
105
+ post.categories << :music
106
+
107
+ concat(simple_form_for(post) do |f|
108
+ f.input(:categories, as: :check_boxes)
109
+ end)
110
+
111
+ assert_select 'input[type=checkbox][value=music][checked=checked]'
112
+ assert_select 'input[type=checkbox][value=games][checked=checked]', count: 0
113
+ end
114
+
115
+ it 'renders radio buttons with enumerated values' do
35
116
  concat(simple_form_for(user) do |f|
36
- f.input(:sex, :as => as)
117
+ f.input(:sex, :as => :radio_buttons)
37
118
  end)
38
119
 
39
120
  assert_select 'input[type=radio][value=male]'
@@ -47,4 +128,29 @@ class SimpleFormSpec < MiniTest::Spec
47
128
 
48
129
  assert_select 'input.string'
49
130
  end
131
+
132
+ it 'does not affect not enumerized classes' do
133
+ concat(simple_form_for(Thing.new) do |f|
134
+ f.input(:name)
135
+ end)
136
+
137
+ assert_select 'input.string'
138
+ end
139
+
140
+ it 'renders select with enumerized values for non-ActiveModel object' do
141
+ concat(simple_form_for(Registration.new, as: 'registration', url: '/') do |f|
142
+ f.input(:sex)
143
+ end)
144
+
145
+ assert_select 'select option[value=male]'
146
+ assert_select 'select option[value=female]'
147
+ end
148
+
149
+ it 'does not affect forms without object' do
150
+ concat(simple_form_for('') do |f|
151
+ f.input(:name)
152
+ end)
153
+
154
+ assert_select 'input.string'
155
+ end
50
156
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class MockController
2
4
  attr_writer :action_name
3
5
 
@@ -17,5 +19,13 @@ class MockController
17
19
  self
18
20
  end
19
21
 
20
- def hash_for_users_path(*args); end
22
+ def url_options
23
+ {}
24
+ end
25
+
26
+ def hash_for_users_path(*); end
27
+
28
+ def polymorphic_mappings
29
+ {}
30
+ end
21
31
  end
@@ -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,6 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
  require 'active_support/testing/setup_and_teardown'
3
5
 
6
+ if defined?(ActionView::RoutingUrlFor)
7
+ ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor)
8
+ end
9
+
4
10
  module ViewTestHelper
5
11
  extend ActiveSupport::Concern
6
12
 
data/test/test_helper.rb CHANGED
@@ -1,17 +1,36 @@
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'
6
+ require 'active_model'
7
+ require 'rails'
8
+ begin
9
+ require 'mongoid'
10
+ rescue LoadError
11
+ end
4
12
 
5
- $VERBOSE=true
13
+ module RailsAdmin
14
+ end
6
15
 
7
- module SimpleForm
8
- module Rails
9
- def self.env
10
- ActiveSupport::StringInquirer.new("test")
11
- end
16
+ require 'simple_form'
17
+ SimpleForm.setup {}
18
+
19
+ require 'formtastic'
20
+
21
+ module EnumerizeTest
22
+ class Application < Rails::Application
23
+ config.active_support.deprecation = :stderr
24
+ config.active_support.test_order = :random
25
+ config.eager_load = false
26
+ config.secret_key_base = 'secret'
12
27
  end
13
28
  end
14
29
 
30
+ EnumerizeTest::Application.initialize!
31
+
32
+ $VERBOSE=true
33
+
15
34
  require 'enumerize'
16
35
 
17
36
  Dir["#{File.dirname(__FILE__)}/support/*.rb"].each do |file|
data/test/value_test.rb CHANGED
@@ -1,49 +1,138 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
4
+ require 'yaml'
2
5
 
3
6
  describe Enumerize::Value do
4
- let(:attr) { Struct.new(:values).new([]) }
5
- let(:value) { Enumerize::Value.new(attr, 'test_value') }
7
+ class Attr < Struct.new(:values, :name, :i18n_scopes)
8
+ end
9
+
10
+ let(:attr) { Attr.new([], "attribute_name", []) }
11
+ let(:val) { Enumerize::Value.new(attr, 'test_value', 1) }
6
12
 
7
13
  it 'is a string' do
8
- value.must_be_kind_of String
14
+ val.must_be_kind_of String
15
+ end
16
+
17
+ describe 'equality' do
18
+ it 'is compared to string' do
19
+ val.must_be :==, 'test_value'
20
+ val.wont_be :==, 'not_value'
21
+ end
22
+
23
+ it 'is compared to symbol' do
24
+ val.must_be :==, :test_value
25
+ val.wont_be :==, :not_value
26
+ end
27
+
28
+ it 'is compared to integer' do
29
+ val.must_be :==, 1
30
+ val.wont_be :==, 2
31
+ end
9
32
  end
10
33
 
11
- it 'is compared to string' do
12
- value.must_be :==, 'test_value'
34
+ describe 'translation' do
35
+
36
+ it 'uses common translation' do
37
+ store_translations(:en, :enumerize => {:attribute_name => {:test_value => "Common translation"}}) do
38
+ val.text.must_be :==, "Common translation"
39
+ end
40
+ end
41
+
42
+ it 'uses default translation from the "default" section if its present' do
43
+ store_translations(:en, :enumerize => {:defaults => {:attribute_name => {:test_value => "Common translation"}}}) do
44
+ val.text.must_be :==, "Common translation"
45
+ end
46
+ end
47
+
48
+ it 'uses model specific translation' do
49
+ attr.i18n_scopes = ["enumerize.model_name.attribute_name"]
50
+
51
+ store_translations(:en, :enumerize => {:model_name => {:attribute_name => {:test_value => "Model Specific translation"}}}) do
52
+ val.text.must_be :==, "Model Specific translation"
53
+ end
54
+ end
55
+
56
+ it 'uses model specific translation rather than common translation' do
57
+ attr.i18n_scopes = ["enumerize.model_name.attribute_name"]
58
+
59
+ store_translations(:en, :enumerize => {:attribute_name => {:test_value => "Common translation"}, :model_name => {:attribute_name => {:test_value => "Model Specific translation"}}}) do
60
+ val.text.must_be :==, "Model Specific translation"
61
+ end
62
+ end
63
+
64
+ it 'uses simply humanized value when translation is undefined' do
65
+ store_translations(:en, :enumerize => {}) do
66
+ val.text.must_be :==, "Test value"
67
+ end
68
+ end
69
+
70
+ it 'uses specified in options translation scope' do
71
+ attr.i18n_scopes = ["other.scope"]
72
+
73
+ store_translations(:en, :other => {:scope => {:test_value => "Scope specific translation"}}) do
74
+ val.text.must_be :==, "Scope specific translation"
75
+ end
76
+ end
77
+
78
+ it 'uses first found translation scope from options' do
79
+ attr.i18n_scopes = ["nonexistent.scope", "other.scope"]
80
+
81
+ store_translations(:en, :other => {:scope => {:test_value => "Scope specific translation"}}) do
82
+ val.text.must_be :==, "Scope specific translation"
83
+ end
84
+ end
13
85
  end
14
86
 
15
87
  describe 'boolean methods comparison' do
16
88
  before do
17
- attr.values = [value, Enumerize::Value.new(attr, 'other_value')]
89
+ attr.values = [val, Enumerize::Value.new(attr, 'other_value')]
18
90
  end
19
91
 
20
92
  it 'returns true if value equals method' do
21
- value.test_value?.must_equal true
93
+ val.test_value?.must_equal true
22
94
  end
23
95
 
24
96
  it 'returns false if value does not equal method' do
25
- value.other_value?.must_equal false
97
+ val.other_value?.must_equal false
26
98
  end
27
99
 
28
100
  it 'raises NoMethodError if there are no values like boolean method' do
29
101
  proc {
30
- value.some_method?
102
+ val.some_method?
31
103
  }.must_raise NoMethodError
32
104
  end
33
105
 
34
106
  it 'raises ArgumentError if arguments are passed' do
35
107
  proc {
36
- value.other_value?('<3')
108
+ val.other_value?('<3')
37
109
  }.must_raise ArgumentError
38
110
  end
39
111
 
40
112
  it 'responds to methods for existing values' do
41
- value.must_respond_to :test_value?
42
- value.must_respond_to :other_value?
113
+ val.must_respond_to :test_value?
114
+ val.must_respond_to :other_value?
115
+ end
116
+
117
+ it 'returns a method object' do
118
+ val.method(:test_value?).must_be_instance_of Method
43
119
  end
44
120
 
45
121
  it "doesn't respond to a method for not existing value" do
46
- value.wont_respond_to :some_method?
122
+ val.wont_respond_to :some_method?
123
+ end
124
+ end
125
+
126
+ describe 'serialization' do
127
+ let(:val) { Enumerize::Value.new(attr, 'test_value') }
128
+
129
+ it 'should be serialized to yaml as string value' do
130
+ assert_equal YAML.dump('test_value'), YAML.dump(val)
131
+ end
132
+
133
+ it 'serializes with Marshal' do
134
+ dump_value = Marshal.dump(val)
135
+ Marshal.load(dump_value).must_equal 'test_value'
47
136
  end
48
137
  end
49
138
  end