typesafe_enum 0.1.8 → 0.3.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.
- checksums.yaml +5 -5
- data/.gitignore +206 -28
- data/.idea/.rakeTasks +7 -0
- data/.idea/codeStyles/Project.xml +45 -0
- data/.idea/codeStyles/codeStyleConfig.xml +5 -0
- data/.idea/go.imports.xml +6 -0
- data/.idea/inspectionProfiles/Project_Default.xml +17 -0
- data/.idea/misc.xml +9 -0
- data/.idea/modules.xml +8 -0
- data/.idea/typesafe_enum.iml +38 -0
- data/.idea/vcs.xml +6 -0
- data/.rubocop.yml +247 -12
- data/.ruby-version +1 -1
- data/.travis.yml +7 -0
- data/CHANGES.md +23 -0
- data/README.md +49 -20
- data/lib/typesafe_enum.rb +1 -1
- data/lib/typesafe_enum/base.rb +36 -30
- data/lib/typesafe_enum/module_info.rb +2 -2
- data/spec/.rubocop.yml +8 -5
- data/spec/unit/typesafe_enum/base_spec.rb +107 -24
- data/typesafe_enum.gemspec +10 -12
- metadata +36 -36
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.6.6
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,3 +1,26 @@
|
|
1
|
+
## 0.3.0
|
2
|
+
|
3
|
+
- Support explicit nil values
|
4
|
+
- Update author email in gemspec
|
5
|
+
- Update RuboCop to version 0.91 and pin version
|
6
|
+
- Set minimum required_ruby_version to 2.6.0
|
7
|
+
- Bump .ruby-version to 2.6.6
|
8
|
+
|
9
|
+
## 0.2.2 (23 April 2020)
|
10
|
+
|
11
|
+
- Implement [`Enumerable`](https://ruby-doc.org/core-2.6.5/Enumerable.html)
|
12
|
+
|
13
|
+
## 0.2.1 (12 March 2020)
|
14
|
+
|
15
|
+
- Update to Rake 12.3.3
|
16
|
+
|
17
|
+
## 0.2.0 (12 March 2020)
|
18
|
+
|
19
|
+
- Update to Ruby 2.6.5
|
20
|
+
- Update to Rake 10.4
|
21
|
+
- Update to RSpec 3.9
|
22
|
+
- Update to RuboCop 0.80
|
23
|
+
|
1
24
|
## 0.1.8 (22 December 2017)
|
2
25
|
|
3
26
|
- Update to Ruby 2.4.1
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# TypesafeEnum
|
2
2
|
|
3
|
-
[](https://github.com/
|
3
|
+
[](https://travis-ci.org/dmolesUC/typesafe_enum)
|
4
|
+
[](https://codeclimate.com/github/dmolesUC/typesafe_enum)
|
5
|
+
[](http://inch-ci.org/github/dmolesUC/typesafe_enum)
|
6
|
+
[](https://github.com/dmolesUC/typesafe_enum/releases)
|
7
7
|
|
8
8
|
A Ruby implementation of Joshua Bloch's
|
9
9
|
[typesafe enum pattern](http://www.oracle.com/technetwork/java/page1-139488.html#replaceenums),
|
@@ -14,23 +14,25 @@ with syntax loosely inspired by [Ruby::Enum](https://github.com/dblock/ruby-enum
|
|
14
14
|
- [Basic usage](#basic-usage)
|
15
15
|
- [Ordering](#ordering)
|
16
16
|
- [String representations](#string-representations)
|
17
|
+
- [Enumerable](#enumerable)
|
17
18
|
- [Convenience methods on enum classes](#convenience-methods-on-enum-classes)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
- [#to_a](#to_a)
|
20
|
+
- [#size](#size)
|
21
|
+
- [#each, <code>#each_with_index</code>, <code>#map</code> and <code>#flat_map</code>](#each-each_with_index-map-and-flat_map)
|
22
|
+
- [#find_by_key, <code>#find_by_value</code>, <code>#find_by_ord</code>](#find_by_key-find_by_value-find_by_ord)
|
23
|
+
- [#find_by_value_str](#find_by_value_str)
|
23
24
|
- [Enum classes with methods](#enum-classes-with-methods)
|
24
25
|
- [Enum instances with methods](#enum-instances-with-methods)
|
25
|
-
- [How is this different from Ruby::Enum
|
26
|
+
- [How is this different from <a href="https://github.com/dblock/ruby-enum">Ruby::Enum</a>?](#how-is-this-different-from-rubyenum)
|
26
27
|
- [How is this different from java.lang.Enum?](#how-is-this-different-from-javalangenum)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
- [Clunkier syntax](#clunkier-syntax)
|
29
|
+
- [No special switch/<code>case</code> support](#no-special-switchcase-support)
|
30
|
+
- [No serialization support](#no-serialization-support)
|
31
|
+
- [No support classes](#no-support-classes)
|
32
|
+
- [Enum classes are not closed](#enum-classes-are-not-closed)
|
32
33
|
- [Contributing](#contributing)
|
33
34
|
|
35
|
+
|
34
36
|
## Basic usage
|
35
37
|
|
36
38
|
Create a new enum class and a set of instances:
|
@@ -91,6 +93,20 @@ Scale::KILO.value
|
|
91
93
|
# => 1000
|
92
94
|
```
|
93
95
|
|
96
|
+
Even `nil` is a valid value (if set explicitly):
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
class Scheme < TypesafeEnum::Base
|
100
|
+
new :HTTP, 'http'
|
101
|
+
new :HTTPS, 'https'
|
102
|
+
new :EXAMPLE, 'example'
|
103
|
+
new :UNKNOWN, nil
|
104
|
+
end
|
105
|
+
|
106
|
+
Scheme::UNKNOWN.value
|
107
|
+
# => nil
|
108
|
+
```
|
109
|
+
|
94
110
|
Declaring two instances with the same key will produce an error:
|
95
111
|
|
96
112
|
```ruby
|
@@ -199,9 +215,19 @@ Suit::DIAMONDS.to_s
|
|
199
215
|
|
200
216
|
It can of course be overridden.
|
201
217
|
|
218
|
+
## `Enumerable`
|
219
|
+
|
220
|
+
As of version 0.2.2, `TypesafeEnum` classes implement
|
221
|
+
[`Enumerable`](https://ruby-doc.org/core-2.6.5/Enumerable.html),
|
222
|
+
so they support methods such as
|
223
|
+
[`#find`](https://ruby-doc.org/core-2.6.5/Enumerable.html#method-i-find),
|
224
|
+
[`#select`](https://ruby-doc.org/core-2.6.5/Enumerable.html#method-i-select),
|
225
|
+
and [`#reduce`](https://ruby-doc.org/core-2.6.5/Enumerable.html#method-i-reduce),
|
226
|
+
in addition to the convenience methods called out specifically below.
|
227
|
+
|
202
228
|
## Convenience methods on enum classes
|
203
229
|
|
204
|
-
###
|
230
|
+
### `#to_a`
|
205
231
|
|
206
232
|
Returns an array of the enum instances in declaration order:
|
207
233
|
|
@@ -210,7 +236,7 @@ Tarot.to_a
|
|
210
236
|
# => [#<Tarot:0x007fd4db30eca8 @key=:CUPS, @value="Cups", @ord=0>, #<Tarot:0x007fd4db30ebe0 @key=:COINS, @value="Coins", @ord=1>, #<Tarot:0x007fd4db30eaf0 @key=:WANDS, @value="Wands", @ord=2>, #<Tarot:0x007fd4db30e9b0 @key=:SWORDS, @value="Swords", @ord=3>]
|
211
237
|
```
|
212
238
|
|
213
|
-
###
|
239
|
+
### `#size`
|
214
240
|
|
215
241
|
Returns the number of enum instances:
|
216
242
|
|
@@ -219,7 +245,7 @@ Suit.size
|
|
219
245
|
# => 4
|
220
246
|
```
|
221
247
|
|
222
|
-
###
|
248
|
+
### `#each`, `#each_with_index`, `#map` and `#flat_map`
|
223
249
|
|
224
250
|
Iterate over the set of enum instances:
|
225
251
|
|
@@ -238,9 +264,12 @@ Suit.each_with_index { |s, i| puts "#{i}: #{s.key}" }
|
|
238
264
|
|
239
265
|
Suit.map(&:value)
|
240
266
|
# => ["clubs", "diamonds", "hearts", "spades"]
|
267
|
+
|
268
|
+
Suit.flat_map { |s| [s.key, s.value] }
|
269
|
+
# => [:CLUBS, "clubs", :DIAMONDS, "diamonds", :HEARTS, "hearts", :SPADES, "spades"]
|
241
270
|
```
|
242
271
|
|
243
|
-
###
|
272
|
+
### `#find_by_key`, `#find_by_value`, `#find_by_ord`
|
244
273
|
|
245
274
|
Look up an enum instance based on its key, value, or ordinal:
|
246
275
|
|
@@ -253,7 +282,7 @@ Tarot.find_by_ord(3)
|
|
253
282
|
# => #<Tarot:0x007faab19fd810 @key=:SWORDS, @value="Swords", @ord=3>
|
254
283
|
```
|
255
284
|
|
256
|
-
###
|
285
|
+
### `#find_by_value_str`
|
257
286
|
|
258
287
|
Look up an enum instance based on the string form of its value (as returned by `to_s`) --
|
259
288
|
useful for, e.g., XML or JSON mapping of enums with non-string values:
|
data/lib/typesafe_enum.rb
CHANGED
data/lib/typesafe_enum/base.rb
CHANGED
@@ -8,6 +8,7 @@ module TypesafeEnum
|
|
8
8
|
include Comparable
|
9
9
|
|
10
10
|
class << self
|
11
|
+
include Enumerable
|
11
12
|
|
12
13
|
# Returns an array of the enum instances in declaration order
|
13
14
|
# @return [Array<self>] All instances of this enum, in declaration order
|
@@ -18,32 +19,16 @@ module TypesafeEnum
|
|
18
19
|
# Returns the number of enum instances
|
19
20
|
# @return [Integer] the number of instances
|
20
21
|
def size
|
21
|
-
as_array
|
22
|
+
as_array.size
|
22
23
|
end
|
23
24
|
|
24
25
|
# Iterates over the set of enum instances
|
25
26
|
# @yield [self] Each instance of this enum, in declaration order
|
26
|
-
# @return [
|
27
|
+
# @return [Enumerator<self>] All instances of this enum, in declaration order
|
27
28
|
def each(&block)
|
28
29
|
to_a.each(&block)
|
29
30
|
end
|
30
31
|
|
31
|
-
# Iterates over the set of enum instances
|
32
|
-
# @yield [self, Integer] Each instance of this enum, in declaration order,
|
33
|
-
# with its ordinal index
|
34
|
-
# @return [Array<self>] All instances of this enum, in declaration order
|
35
|
-
def each_with_index(&block)
|
36
|
-
to_a.each_with_index(&block)
|
37
|
-
end
|
38
|
-
|
39
|
-
# Iterates over the set of enum instances
|
40
|
-
# @yield [self] Each instance of this enum, in declaration order
|
41
|
-
# @return [Array] An array containing the result of applying `&block`
|
42
|
-
# to each instance of this enum, in instance declaration order
|
43
|
-
def map(&block)
|
44
|
-
to_a.map(&block)
|
45
|
-
end
|
46
|
-
|
47
32
|
# Looks up an enum instance based on its key
|
48
33
|
# @param key [Symbol] the key to look up
|
49
34
|
# @return [self, nil] the corresponding enum instance, or nil
|
@@ -71,6 +56,7 @@ module TypesafeEnum
|
|
71
56
|
# @return [self, nil] the corresponding enum instance, or nil
|
72
57
|
def find_by_ord(ord)
|
73
58
|
return nil if ord > size || ord.negative?
|
59
|
+
|
74
60
|
as_array[ord]
|
75
61
|
end
|
76
62
|
|
@@ -93,21 +79,37 @@ module TypesafeEnum
|
|
93
79
|
end
|
94
80
|
|
95
81
|
def valid_key_and_value(instance)
|
82
|
+
return unless (key = valid_key(instance))
|
83
|
+
|
84
|
+
[key, valid_value(instance)]
|
85
|
+
end
|
86
|
+
|
87
|
+
def valid_key(instance)
|
96
88
|
key = instance.key
|
89
|
+
return key unless (found = find_by_key(key))
|
90
|
+
|
97
91
|
value = instance.value
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
92
|
+
raise NameError, "#{name}::#{key} already exists with value #{found.value.inspect}" unless value == found.value
|
93
|
+
|
94
|
+
warn("ignoring redeclaration of #{name}::#{key} with value #{value.inspect} (source: #{caller(6..6).first})")
|
95
|
+
end
|
96
|
+
|
97
|
+
def valid_value(instance)
|
98
|
+
value = instance.value
|
99
|
+
return value unless (found = find_by_value(value))
|
100
|
+
|
101
|
+
key = instance.key
|
102
|
+
raise NameError, "A #{name} instance with value #{value.inspect} already exists: #{found.key}" unless key == found.key
|
103
|
+
|
104
|
+
# valid_key() should already have warned us, and valid_key_and_value() should have exited early, but just in case
|
105
|
+
# :nocov:
|
106
|
+
warn("ignoring redeclaration of #{name}::#{key} with value #{value.inspect} (source: #{caller(6..6).first})")
|
107
|
+
# :nocov:
|
106
108
|
end
|
107
109
|
|
108
110
|
def register(instance)
|
109
111
|
key, value = valid_key_and_value(instance)
|
110
|
-
return unless key
|
112
|
+
return unless key
|
111
113
|
|
112
114
|
const_set(key.to_s, instance)
|
113
115
|
by_key[key] = instance
|
@@ -150,15 +152,19 @@ module TypesafeEnum
|
|
150
152
|
end
|
151
153
|
|
152
154
|
def to_s
|
153
|
-
"#{self.class}::#{key} [#{ord}] -> #{value}"
|
155
|
+
"#{self.class}::#{key} [#{ord}] -> #{value.inspect}"
|
154
156
|
end
|
155
157
|
|
156
158
|
private
|
157
159
|
|
158
|
-
|
160
|
+
IMPLICIT = Class.new.new
|
161
|
+
private_constant :IMPLICIT
|
162
|
+
|
163
|
+
def initialize(key, value = IMPLICIT, &block)
|
159
164
|
raise TypeError, "#{key} is not a symbol" unless key.is_a?(Symbol)
|
165
|
+
|
160
166
|
@key = key
|
161
|
-
@value = value
|
167
|
+
@value = value == IMPLICIT ? key.to_s.downcase : value
|
162
168
|
@ord = self.class.size
|
163
169
|
self.class.class_exec(self) do |instance|
|
164
170
|
register(instance)
|
@@ -5,8 +5,8 @@ module TypesafeEnum
|
|
5
5
|
NAME = 'typesafe_enum'
|
6
6
|
|
7
7
|
# The version of this gem
|
8
|
-
VERSION = '0.
|
8
|
+
VERSION = '0.3.0'
|
9
9
|
|
10
10
|
# The copyright notice for this gem
|
11
|
-
COPYRIGHT = 'Copyright (c)
|
11
|
+
COPYRIGHT = 'Copyright (c) 2020 The Regents of the University of California'
|
12
12
|
end
|
data/spec/.rubocop.yml
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
inherit_from: ../.rubocop.yml
|
2
2
|
|
3
|
-
|
3
|
+
Lint/ConstantDefinitionInBlock:
|
4
4
|
Enabled: false
|
5
5
|
|
6
|
-
|
6
|
+
Style/ClassAndModuleChildren:
|
7
7
|
Enabled: false
|
8
8
|
|
9
|
-
Metrics/
|
9
|
+
Metrics/AbcSize:
|
10
10
|
Enabled: false
|
11
11
|
|
12
|
-
|
12
|
+
Metrics/BlockLength:
|
13
13
|
Enabled: false
|
14
14
|
|
15
|
-
|
15
|
+
Metrics/ModuleLength:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Metrics/MethodLength:
|
16
19
|
Enabled: false
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
require 'spec_helper'
|
@@ -30,15 +29,31 @@ class Scale < TypesafeEnum::Base
|
|
30
29
|
new :MEGA, 1_000_000
|
31
30
|
end
|
32
31
|
|
32
|
+
class Scheme < TypesafeEnum::Base
|
33
|
+
new :HTTP, 'http'
|
34
|
+
new :HTTPS, 'https'
|
35
|
+
new :EXAMPLE, 'example'
|
36
|
+
new :UNKNOWN, nil
|
37
|
+
end
|
38
|
+
|
33
39
|
module TypesafeEnum
|
34
40
|
describe Base do
|
35
41
|
|
36
|
-
describe
|
37
|
-
it '
|
42
|
+
describe :new do
|
43
|
+
it 'news a constant enum value' do
|
38
44
|
enum = Suit::CLUBS
|
39
45
|
expect(enum).to be_a(Suit)
|
40
46
|
end
|
41
47
|
|
48
|
+
it 'allows nil values' do
|
49
|
+
expect do
|
50
|
+
class ::NilValues < Base
|
51
|
+
new :NONE, nil
|
52
|
+
end
|
53
|
+
end.not_to raise_error
|
54
|
+
expect(::NilValues.to_a).not_to be_empty
|
55
|
+
end
|
56
|
+
|
42
57
|
it 'insists symbols be symbols' do
|
43
58
|
expect do
|
44
59
|
class ::StringKeys < Base
|
@@ -81,6 +96,18 @@ module TypesafeEnum
|
|
81
96
|
expect(::DuplicateValues.find_by_key(:ALSO_SPADES)).to be_nil
|
82
97
|
end
|
83
98
|
|
99
|
+
it 'disallows duplicate nil values' do
|
100
|
+
expect do
|
101
|
+
class ::DuplicateNilValues < Base
|
102
|
+
new :NONE, nil
|
103
|
+
new :NULL, nil
|
104
|
+
end.to raise_error(NameError)
|
105
|
+
expect(::DuplicateNilValues.to_a).to eq([::DuplicateNilValues::NONE])
|
106
|
+
expect(::DuplicateNilValues::NONE.value).to be_nil
|
107
|
+
expect(::DuplicateNilValues.find_by_key(:NULL)).to be_nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
84
111
|
it 'disallows nil keys' do
|
85
112
|
expect do
|
86
113
|
class ::NilKeys < Base
|
@@ -94,7 +121,8 @@ module TypesafeEnum
|
|
94
121
|
class ::IdenticalInstances < Base
|
95
122
|
new :SPADES, 'spades'
|
96
123
|
end
|
97
|
-
|
124
|
+
expected_msg = /ignoring redeclaration of IdenticalInstances::SPADES with value "spades" \(source: .*base_spec.rb:[0-9]+:in `new'\)/
|
125
|
+
expect(::IdenticalInstances).to receive(:warn).once.with(expected_msg)
|
98
126
|
class ::IdenticalInstances < Base
|
99
127
|
new :SPADES, 'spades'
|
100
128
|
end
|
@@ -113,7 +141,7 @@ module TypesafeEnum
|
|
113
141
|
end
|
114
142
|
end
|
115
143
|
|
116
|
-
describe
|
144
|
+
describe :to_a do
|
117
145
|
it 'returns the values as an array' do
|
118
146
|
expect(Suit.to_a).to eq([Suit::CLUBS, Suit::DIAMONDS, Suit::HEARTS, Suit::SPADES])
|
119
147
|
end
|
@@ -125,13 +153,27 @@ module TypesafeEnum
|
|
125
153
|
end
|
126
154
|
end
|
127
155
|
|
128
|
-
describe
|
156
|
+
describe :size do
|
129
157
|
it 'returns the number of enum instnaces' do
|
130
158
|
expect(Suit.size).to eq(4)
|
131
159
|
end
|
132
160
|
end
|
133
161
|
|
134
|
-
describe
|
162
|
+
describe :count do
|
163
|
+
it 'returns the number of enum instnaces' do
|
164
|
+
expect(Suit.count).to eq(4)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'counts items' do
|
168
|
+
expect(Suit.count(Suit::SPADES)).to eq(1)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'counts items that match a predicate' do
|
172
|
+
expect(Suit.count { |s| s.value.length == 6 }).to eq(2)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe :each do
|
135
177
|
it 'iterates the enum values' do
|
136
178
|
expected = [Suit::CLUBS, Suit::DIAMONDS, Suit::HEARTS, Suit::SPADES]
|
137
179
|
index = 0
|
@@ -142,7 +184,7 @@ module TypesafeEnum
|
|
142
184
|
end
|
143
185
|
end
|
144
186
|
|
145
|
-
describe
|
187
|
+
describe :each_with_index do
|
146
188
|
it 'iterates the enum values with indices' do
|
147
189
|
expected = [Suit::CLUBS, Suit::DIAMONDS, Suit::HEARTS, Suit::SPADES]
|
148
190
|
Suit.each_with_index do |s, index|
|
@@ -151,14 +193,21 @@ module TypesafeEnum
|
|
151
193
|
end
|
152
194
|
end
|
153
195
|
|
154
|
-
describe
|
196
|
+
describe :map do
|
155
197
|
it 'maps enum values' do
|
156
198
|
all_keys = Suit.map(&:key)
|
157
199
|
expect(all_keys).to eq(%i[CLUBS DIAMONDS HEARTS SPADES])
|
158
200
|
end
|
159
201
|
end
|
160
202
|
|
161
|
-
describe
|
203
|
+
describe :flat_map do
|
204
|
+
it 'flatmaps enum values' do
|
205
|
+
result = Tarot.flat_map { |t| [t.key, t.value] }
|
206
|
+
expect(result).to eq([:CUPS, 'Cups', :COINS, 'Coins', :WANDS, 'Wands', :SWORDS, 'Swords'])
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe :<=> do
|
162
211
|
it 'orders enum instances' do
|
163
212
|
Suit.each_with_index do |s1, i1|
|
164
213
|
Suit.each_with_index do |s2, i2|
|
@@ -168,7 +217,7 @@ module TypesafeEnum
|
|
168
217
|
end
|
169
218
|
end
|
170
219
|
|
171
|
-
describe
|
220
|
+
describe :== do
|
172
221
|
it 'returns true for identical instances, false otherwise' do
|
173
222
|
Suit.each do |s1|
|
174
223
|
Suit.each do |s2|
|
@@ -190,6 +239,7 @@ module TypesafeEnum
|
|
190
239
|
end
|
191
240
|
end
|
192
241
|
|
242
|
+
# rubocop:disable Security/MarshalLoad
|
193
243
|
it 'survives marshalling' do
|
194
244
|
Suit.each do |s1|
|
195
245
|
dump = Marshal.dump(s1)
|
@@ -198,9 +248,10 @@ module TypesafeEnum
|
|
198
248
|
expect(s2 == s1).to eq(true)
|
199
249
|
end
|
200
250
|
end
|
251
|
+
# rubocop:enable Security/MarshalLoad
|
201
252
|
end
|
202
253
|
|
203
|
-
describe
|
254
|
+
describe :!= do
|
204
255
|
it 'returns false for identical instances, true otherwise' do
|
205
256
|
Suit.each do |s1|
|
206
257
|
Suit.each do |s2|
|
@@ -222,7 +273,7 @@ module TypesafeEnum
|
|
222
273
|
end
|
223
274
|
end
|
224
275
|
|
225
|
-
describe
|
276
|
+
describe :hash do
|
226
277
|
it 'gives consistent values' do
|
227
278
|
Suit.each do |s1|
|
228
279
|
Suit.each do |s2|
|
@@ -245,6 +296,7 @@ module TypesafeEnum
|
|
245
296
|
end
|
246
297
|
end
|
247
298
|
|
299
|
+
# rubocop:disable Security/MarshalLoad
|
248
300
|
it 'survives marshalling' do
|
249
301
|
Suit.each do |s1|
|
250
302
|
dump = Marshal.dump(s1)
|
@@ -252,6 +304,7 @@ module TypesafeEnum
|
|
252
304
|
expect(s2.hash).to eq(s1.hash)
|
253
305
|
end
|
254
306
|
end
|
307
|
+
# rubocop:enable Security/MarshalLoad
|
255
308
|
|
256
309
|
it 'always returns a Fixnum' do
|
257
310
|
Suit.each do |s1|
|
@@ -260,7 +313,7 @@ module TypesafeEnum
|
|
260
313
|
end
|
261
314
|
end
|
262
315
|
|
263
|
-
describe
|
316
|
+
describe :eql? do
|
264
317
|
it 'is consistent with #hash' do
|
265
318
|
Suit.each do |s1|
|
266
319
|
Suit.each do |s2|
|
@@ -270,16 +323,30 @@ module TypesafeEnum
|
|
270
323
|
end
|
271
324
|
end
|
272
325
|
|
273
|
-
describe
|
326
|
+
describe :value do
|
274
327
|
it 'returns the string value of the enum instance' do
|
275
328
|
expected = %w[clubs diamonds hearts spades]
|
276
329
|
Suit.each_with_index do |s, index|
|
277
330
|
expect(s.value).to eq(expected[index])
|
278
331
|
end
|
279
332
|
end
|
333
|
+
|
334
|
+
it 'returns an explicit value' do
|
335
|
+
expected = [10, 100, 1000, 1_000_000]
|
336
|
+
Scale.each_with_index do |s, index|
|
337
|
+
expect(s.value).to eq(expected[index])
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
it 'supports nil values' do
|
342
|
+
expected = ['http', 'https', 'example', nil]
|
343
|
+
Scheme.each_with_index do |s, index|
|
344
|
+
expect(s.value).to eq(expected[index])
|
345
|
+
end
|
346
|
+
end
|
280
347
|
end
|
281
348
|
|
282
|
-
describe
|
349
|
+
describe :key do
|
283
350
|
it 'returns the symbol key of the enum instance' do
|
284
351
|
expected = %i[CLUBS DIAMONDS HEARTS SPADES]
|
285
352
|
Suit.each_with_index do |s, index|
|
@@ -288,7 +355,7 @@ module TypesafeEnum
|
|
288
355
|
end
|
289
356
|
end
|
290
357
|
|
291
|
-
describe
|
358
|
+
describe :ord do
|
292
359
|
it 'returns the ord value of the enum instance' do
|
293
360
|
Suit.each_with_index do |s, index|
|
294
361
|
expect(s.ord).to eq(index)
|
@@ -296,13 +363,13 @@ module TypesafeEnum
|
|
296
363
|
end
|
297
364
|
end
|
298
365
|
|
299
|
-
describe
|
366
|
+
describe :to_s do
|
300
367
|
it 'provides an informative string' do
|
301
368
|
aggregate_failures 'informative string' do
|
302
|
-
[Suit, Tarot, RGBColor, Scale].each do |ec|
|
369
|
+
[Suit, Tarot, RGBColor, Scale, Scheme].each do |ec|
|
303
370
|
ec.each do |ev|
|
304
371
|
result = ev.to_s
|
305
|
-
[ec.to_s, ev.key, ev.ord, ev.value].each do |info|
|
372
|
+
[ec.to_s, ev.key, ev.ord, ev.value.inspect].each do |info|
|
306
373
|
expect(result).to include(info.to_s)
|
307
374
|
end
|
308
375
|
end
|
@@ -311,7 +378,7 @@ module TypesafeEnum
|
|
311
378
|
end
|
312
379
|
end
|
313
380
|
|
314
|
-
describe
|
381
|
+
describe :find_by_key do
|
315
382
|
it 'maps symbol keys to enum instances' do
|
316
383
|
keys = %i[CLUBS DIAMONDS HEARTS SPADES]
|
317
384
|
expected = Suit.to_a
|
@@ -325,7 +392,7 @@ module TypesafeEnum
|
|
325
392
|
end
|
326
393
|
end
|
327
394
|
|
328
|
-
describe
|
395
|
+
describe :find_by_value do
|
329
396
|
it 'maps values to enum instances' do
|
330
397
|
values = %w[clubs diamonds hearts spades]
|
331
398
|
expected = Suit.to_a
|
@@ -349,9 +416,15 @@ module TypesafeEnum
|
|
349
416
|
expect(Scale.find_by_value(s.value)).to be(s)
|
350
417
|
end
|
351
418
|
end
|
419
|
+
|
420
|
+
it 'supports enums with explicit nil values' do
|
421
|
+
Scheme.each do |s|
|
422
|
+
expect(Scheme.find_by_value(s.value)).to be(s)
|
423
|
+
end
|
424
|
+
end
|
352
425
|
end
|
353
426
|
|
354
|
-
describe
|
427
|
+
describe :find_by_value_str do
|
355
428
|
it 'maps string values to enum instances' do
|
356
429
|
values = %w[clubs diamonds hearts spades]
|
357
430
|
expected = Suit.to_a
|
@@ -375,9 +448,15 @@ module TypesafeEnum
|
|
375
448
|
expect(Scale.find_by_value_str(s.value.to_s)).to be(s)
|
376
449
|
end
|
377
450
|
end
|
451
|
+
|
452
|
+
it 'supports enums with explicit nil values' do
|
453
|
+
Scheme.each do |s|
|
454
|
+
expect(Scheme.find_by_value(s.value)).to be(s)
|
455
|
+
end
|
456
|
+
end
|
378
457
|
end
|
379
458
|
|
380
|
-
describe
|
459
|
+
describe :find_by_ord do
|
381
460
|
it 'maps ordinal indices to enum instances' do
|
382
461
|
Suit.each do |s|
|
383
462
|
expect(Suit.find_by_ord(s.ord)).to be(s)
|
@@ -432,5 +511,9 @@ module TypesafeEnum
|
|
432
511
|
|
433
512
|
expect(Operation.map { |op| op.eval(39, 23) }).to eq([39 + 23, 39 - 23])
|
434
513
|
end
|
514
|
+
|
515
|
+
it 'is an Enumerable' do
|
516
|
+
expect(Suit).to be_an(Enumerable)
|
517
|
+
end
|
435
518
|
end
|
436
519
|
end
|