enum-x 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,365 @@
1
+ require 'spec_helper'
2
+ require 'active_support'
3
+
4
+ describe EnumX do
5
+
6
+ # Stub the enum registry.
7
+ let(:registry) { EnumX::Registry.new }
8
+ before { allow(EnumX).to receive(:registry).and_return(registry) }
9
+
10
+ describe '.define and .undefine' do
11
+
12
+ it "should raise an error if a non-existing enum is obtained through a method call" do
13
+ expect { EnumX.test_enum }.to raise_error(NameError)
14
+ end
15
+ it "should return nil if a non-existing enum is obtained through an indexer" do
16
+ expect(EnumX[:test_enum]).to be_nil
17
+ end
18
+
19
+ it "should load an enum when it is defined" do
20
+ EnumX.define :test_enum, %w[ one two ]
21
+
22
+ expect(EnumX[:test_enum]).to be_a(EnumX)
23
+ expect(EnumX.test_enum).to be_a(EnumX)
24
+ end
25
+
26
+ it "should not load an enum when it is subsequently undefined" do
27
+ EnumX.define :test_enum, %w[ one two ]
28
+ EnumX.undefine :test_enum
29
+
30
+ expect(EnumX[:test_enum]).to be_nil
31
+ expect{ EnumX.test_enum }.to raise_error(NameError)
32
+ end
33
+ end
34
+
35
+ describe '.load_enums' do
36
+ before { allow(EnumX).to receive(:load_paths).and_return(%w[ one.yml ]) }
37
+
38
+ it "should load the right enums" do
39
+ # The load_file method is loaded twice because @registry is unset, though we've stubbed :registry.
40
+ expect(YAML).to receive(:load_file).twice.with('one.yml').and_return(
41
+ 'enum_one' => %w[ one two three ]
42
+ )
43
+
44
+ expect(EnumX[:enum_one]).to be_a(EnumX)
45
+ expect(EnumX[:enum_one].values).to eq([ :one, :two, :three ])
46
+ end
47
+ end
48
+
49
+ describe 'accessing' do
50
+ before { EnumX.define(:test_enum, %w[ one two ]) }
51
+
52
+ it "should load the enum through an indexer" do
53
+ expect(EnumX[:test_enum]).to be_a(EnumX)
54
+ expect(EnumX[:test_enum].values).to eq([ :one, :two ])
55
+ end
56
+ it "should load the same enum through a string index" do
57
+ expect(EnumX['test_enum']).to be(EnumX[:test_enum])
58
+ end
59
+ it "should load the same enum through a method call" do
60
+ expect(EnumX.test_enum).to be(EnumX[:test_enum])
61
+ end
62
+ end
63
+
64
+ describe "test_enum" do
65
+
66
+ let(:test_enum) { EnumX.new(:test_enum, %w[ one two ] + [{ :value => 'three', :number => '3' }]) }
67
+
68
+ it "should have a 3-item values array" do
69
+ expect(test_enum).to have(3).values
70
+ expect(test_enum.values[0]).to be_a(EnumX::Value)
71
+ end
72
+
73
+ describe "array conversion" do
74
+ specify { expect(test_enum.to_a).to eql(test_enum.values) }
75
+ specify { expect(test_enum.to_ary).to eql(test_enum.values) }
76
+ end
77
+
78
+ describe "as enumerable" do
79
+ specify { expect(EnumX).to include(Enumerable) }
80
+
81
+ it "should support #each" do
82
+ values = []
83
+ test_enum.each { |value| values << value }
84
+
85
+ expect(values).to have(3).items
86
+ expect(values[0]).to be(test_enum[:one])
87
+ expect(values[1]).to be(test_enum[:two])
88
+ expect(values[2]).to be(test_enum[:three])
89
+ end
90
+ end
91
+
92
+ describe "value accessing" do
93
+ it "should retrieve value :one correctly" do
94
+ expect(test_enum[:one]).to be_a(EnumX::Value)
95
+ expect(test_enum[:one].value).to eq('one')
96
+ end
97
+
98
+ it "should retrieve nil for an unexisting value" do
99
+ expect(test_enum[:four]).to be_nil
100
+ end
101
+
102
+ it "should allow accessing by integer" do
103
+ test_enum = EnumX.new(:test_enum, [ 50, 100 ])
104
+ expect(test_enum[50]).to be_a(EnumX::Value)
105
+ expect(test_enum[50].to_s).to eql('50')
106
+ end
107
+
108
+ it "should have indifferent access" do
109
+ expect(test_enum['one']).to be(test_enum[:one])
110
+ end
111
+ end
112
+
113
+ describe "#value_with_format" do
114
+
115
+ it "should find a value by a specific format" do
116
+ expect(test_enum.value_with_format(:number, 'three')).to be_nil
117
+ expect(test_enum.value_with_format(:number, '3')).to be(test_enum[:three])
118
+ end
119
+
120
+ it "should retrieve any value with an undefined format to be found by its name, as their formats default to it" do
121
+ expect(test_enum.value_with_format(:whatever, 'two')).to be(test_enum[:two])
122
+ end
123
+
124
+ it "should offer a shortcut #value_with_<format>" do
125
+ expect(test_enum.value_with_number('3')).to be(test_enum[:three])
126
+ expect(test_enum.value_with_whatever('two')).to be(test_enum[:two])
127
+ end
128
+
129
+ it "should accept exactly one argument in the shortcut form" do
130
+ expect{ test_enum.value_with_number() }.to raise_error(ArgumentError, "`value_with_number' accepts one argument, 0 given")
131
+ expect{ test_enum.value_with_number(1, 2) }.to raise_error(ArgumentError, "`value_with_number' accepts one argument, 2 given")
132
+ end
133
+
134
+ end
135
+
136
+ describe '#dup' do
137
+ let(:duplicate) { test_enum.dup }
138
+ specify { expect(duplicate.name).to eql('test_enum') }
139
+
140
+ it "should have the same values array, including specific format outputs" do
141
+ expect(duplicate).to have(3).values
142
+ expect(duplicate.values[2].to_number).to eql('3')
143
+ end
144
+ end
145
+
146
+ describe '#without' do
147
+ let(:duplicate) { test_enum.without(:one) }
148
+ specify { expect(duplicate.name).to eql('test_enum') }
149
+
150
+ it "should have removed the value :one" do
151
+ expect(duplicate).to have(2).values
152
+ expect(duplicate.values).not_to include('one')
153
+ expect(duplicate.values).to include('two')
154
+ expect(duplicate.values).to include('three')
155
+ end
156
+
157
+ it "should have the specific format output for three" do
158
+ expect(duplicate.values[1].to_number).to eql('3')
159
+ end
160
+ end
161
+
162
+ describe '#only' do
163
+ let(:duplicate) { test_enum.only(:two, :three) }
164
+ specify { expect(duplicate.name).to eql('test_enum') }
165
+
166
+ it "should have kept the values :two and three" do
167
+ expect(duplicate).to have(2).values
168
+ expect(duplicate.values).not_to include('one')
169
+ expect(duplicate.values).to include('two')
170
+ expect(duplicate.values).to include('three')
171
+ end
172
+
173
+ it "should have the specific format output for three" do
174
+ expect(duplicate.values[1].to_number).to eql('3')
175
+ end
176
+ end
177
+
178
+ describe '#extend!' do
179
+ it "should add one new value to the enum" do
180
+ test_enum.extend!('four')
181
+
182
+ expect(test_enum).to have(4).values
183
+ expect(test_enum.values).to include('four')
184
+ end
185
+
186
+ it "should add the given values to the enum" do
187
+ test_enum.extend!('four', 'five')
188
+
189
+ expect(test_enum).to have(5).values
190
+ expect(test_enum.values).to include('four')
191
+ expect(test_enum.values).to include('five')
192
+ end
193
+
194
+ it "should add values using a hash" do
195
+ test_enum.extend!(:value => 'four', :number => '4')
196
+
197
+ expect(test_enum).to have(4).values
198
+ expect(test_enum.values).to include('four')
199
+ expect(test_enum[:four].to_number).to eql('4')
200
+ end
201
+ end
202
+
203
+ describe EnumX::Value do
204
+
205
+ let(:simple_value) { test_enum.values[0] }
206
+ let(:complex_value) { test_enum.values[2] }
207
+
208
+ specify { expect(simple_value.enum).to be(test_enum) }
209
+
210
+ it "should require an enum" do
211
+ expect{ EnumX::Value.new(nil, :test) }.to raise_error(ArgumentError)
212
+ end
213
+ it "should require a value if a hash is specified" do
214
+ expect{ EnumX::Value.new(test_enum, { :test => :a }) }.to raise_error(ArgumentError, "key :value is required when a hash value is specified")
215
+ end
216
+ it "should not allow a format called :format if a hash is specified" do
217
+ expect{ EnumX::Value.new(test_enum, { :value => :a, :format => :b }) }.to raise_error(ArgumentError, "key :format is not allowed")
218
+ end
219
+
220
+ specify { expect(simple_value.value).to eql('one') }
221
+ specify { expect(simple_value.symbol).to eql(:one) }
222
+ specify { expect(simple_value.to_s).to eql('one') }
223
+ specify { expect(simple_value.to_sym).to eql(:one) }
224
+ specify { expect(simple_value.to_number).to eql('one') }
225
+ specify { expect(simple_value.to_xml).to eql('one') }
226
+ specify { expect(simple_value.to_json).to eql('"one"') }
227
+ specify { expect(simple_value.hash).to eql('one'.hash) }
228
+
229
+ specify { expect(complex_value.value).to eql('three') }
230
+ specify { expect(complex_value.symbol).to eql(:three) }
231
+ specify { expect(complex_value.to_s).to eql('three') }
232
+ specify { expect(complex_value.to_sym).to eql(:three) }
233
+ specify { expect(complex_value.to_number).to eql('3') }
234
+ specify { expect(complex_value.to_xml).to eql('three') }
235
+ specify { expect(complex_value.to_json).to eql('"three"') }
236
+ specify { expect(complex_value.hash).to eql('three'.hash) }
237
+
238
+ describe 'duplication' do
239
+ context "with a new enum owner" do
240
+ let(:other_enum) { EnumX.new(:test_enum, {}) }
241
+ let(:duplicate) { complex_value.dup(other_enum) }
242
+
243
+ specify { expect(duplicate.value).to eql('three') }
244
+
245
+ it "should update the enum reference" do
246
+ expect(duplicate.enum).to be(other_enum)
247
+ end
248
+
249
+ it "should keep the specific format output" do
250
+ expect(duplicate.to_number).to eql('3')
251
+ end
252
+ end
253
+ context "without a new enum owner" do
254
+ let(:duplicate) { complex_value.dup }
255
+ it "should keep the original enum reference" do
256
+ expect(duplicate.enum).to be(test_enum)
257
+ end
258
+ end
259
+ end
260
+
261
+ describe 'equality' do
262
+ specify { expect(simple_value).to eq('one') }
263
+ specify { expect(simple_value).to eq(EnumX::Value.new(test_enum, 'one')) }
264
+ specify { expect(simple_value).to eq(EnumX::Value.new(test_enum, :one)) }
265
+
266
+ specify { expect(simple_value).not_to eql('one') }
267
+ specify { expect(simple_value).to eql(EnumX::Value.new(test_enum, 'one')) }
268
+ specify { expect(simple_value).to eql(EnumX::Value.new(test_enum, :one)) }
269
+
270
+ specify { expect(complex_value).to eq('three') }
271
+ specify { expect(complex_value).to eql(EnumX::Value.new(test_enum, 'three')) }
272
+ specify { expect(complex_value).to eql(EnumX::Value.new(test_enum, :three)) }
273
+ specify { expect(complex_value).to eql(EnumX::Value.new(test_enum, { :value => 'three' })) }
274
+ end
275
+
276
+ describe "mnemonics" do
277
+
278
+ it "should respond to any value interrogation method for all the enum values" do
279
+ expect(simple_value).to respond_to(:one?)
280
+ expect(simple_value).to respond_to(:two?)
281
+ expect(simple_value).to respond_to(:three?)
282
+
283
+ expect(simple_value).not_to respond_to(:three)
284
+ expect(simple_value).not_to respond_to(:four?)
285
+ end
286
+
287
+ it "should reflect the current value's status" do
288
+ expect(simple_value.one?).to be_true
289
+ expect(simple_value.two?).to be_false
290
+ expect(simple_value.three?).to be_false
291
+
292
+ expect(complex_value.one?).to be_false
293
+ expect(complex_value.two?).to be_false
294
+ expect(complex_value.three?).to be_true
295
+ end
296
+
297
+ end
298
+
299
+ describe "translate" do
300
+ it "should translate the value, and provide a default value" do
301
+ expect(I18n).to receive(:translate).with('one', :scope => [ :enums, 'test_enum' ], :default => 'one').and_return('One')
302
+ expect(simple_value.translate).to eql('One')
303
+ end
304
+
305
+ it "should use a humanized default value using ActiveSupport if available" do
306
+ expect(I18n).to receive(:translate).with('test_value', :scope => [ :enums, 'test_enum' ], :default => 'test value').and_return('Test Value')
307
+ expect(EnumX::Value.new(test_enum, 'test_value').translate).to eql('Test Value')
308
+ end
309
+
310
+ it "should use the string version if ActiveSupport is not available" do
311
+ tmp = ::ActiveSupport
312
+ Object.send :remove_const, :ActiveSupport
313
+
314
+ expect(I18n).to receive(:translate).with('test_value', :scope => [ :enums, 'test_enum' ], :default => 'test_value').and_return('Test Value')
315
+ expect(EnumX::Value.new(test_enum, 'test_value').translate).to eql('Test Value')
316
+
317
+ Object::ActiveSupport = tmp
318
+ end
319
+ end
320
+ describe "translate!" do
321
+ it "should translate the value, and raise an error if no translation could be made" do
322
+ expect(I18n).to receive(:translate).with('one', :scope => [ :enums, 'test_enum' ], :raise => true).and_raise("translation not found")
323
+ expect{ simple_value.translate! }.to raise_error("translation not found")
324
+ end
325
+ end
326
+
327
+ describe "use in case statements" do
328
+ # Note - the case example is superfluous as the '===' method implies that it works with case statements. It's given here
329
+ # as a real life example of its usage.
330
+
331
+ context "using a symbol" do
332
+ let(:result) do
333
+ case test_enum[:one]
334
+ when :one then true
335
+ else false
336
+ end
337
+ end
338
+ specify { expect(:one).to be === test_enum[:one] }
339
+ specify { expect(result).to be_true }
340
+ end
341
+ context "using a string" do
342
+ let(:result) do
343
+ case test_enum[:one]
344
+ when 'one' then true
345
+ else false
346
+ end
347
+ end
348
+ specify { expect('one').to be === test_enum[:one] }
349
+ specify { expect(result).to be_true }
350
+ end
351
+ end
352
+
353
+ describe 'YAML conversion' do
354
+ before { allow(EnumX).to receive(:[]).and_return(EnumX.new(:test_enum, %w[ one two ])) }
355
+
356
+ context "to yaml" do
357
+ specify { expect(simple_value.to_yaml).to eql("--- one\n...\n") }
358
+ end
359
+
360
+ end
361
+
362
+ end
363
+
364
+ end
365
+ end
@@ -0,0 +1,19 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter "spec/"
4
+ end
5
+
6
+ require 'enum-x'
7
+ require 'rspec/autorun'
8
+
9
+ RSpec.configure do |config|
10
+
11
+ config.mock_with :rspec do |config|
12
+ config.syntax = :expect
13
+ end
14
+
15
+ end
16
+
17
+ # Requires supporting ruby files with custom matchers and macros, etc,
18
+ # in spec/support/ and its subdirectories.
19
+ Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: enum-x
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Joost Lubach
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activemodel
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.14'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '2.14'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Allows a finite set of values for any attribute.
84
+ email:
85
+ - joost@yoazt.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - .gitignore
91
+ - .ruby-gemset
92
+ - .ruby-version
93
+ - CHANGELOG.md
94
+ - Gemfile
95
+ - Gemfile.lock
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - enum-x.gemspec
100
+ - lib/enum-x.rb
101
+ - lib/enum_x.rb
102
+ - lib/enum_x/dsl.rb
103
+ - lib/enum_x/monkey.rb
104
+ - lib/enum_x/railtie.rb
105
+ - lib/enum_x/value.rb
106
+ - lib/enum_x/value_list.rb
107
+ - lib/enum_x/version.rb
108
+ - spec/enum_x/dsl_spec.rb
109
+ - spec/enum_x_spec.rb
110
+ - spec/spec_helper.rb
111
+ homepage: ''
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.1.4
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Allows a finite set of values for any attribute.
135
+ test_files: []
136
+ has_rdoc: