enum-x 1.0.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.
@@ -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: