enumerize 0.3.0 → 2.3.1

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