ruby-enum 0.8.0 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -10
- data/Dangerfile +4 -0
- data/Gemfile +10 -1
- data/Gemfile.lock +143 -33
- data/LICENSE.md +1 -1
- data/README.md +202 -76
- data/RELEASING.md +4 -11
- data/Rakefile +7 -0
- data/UPGRADING.md +44 -0
- data/benchmarks/case.rb +45 -0
- data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc.png +0 -0
- data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
- data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_both.png +0 -0
- data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc.png +0 -0
- data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
- data/coverage/assets/0.12.3/application.css +1 -0
- data/coverage/assets/0.12.3/application.js +7 -0
- data/coverage/assets/0.12.3/colorbox/border.png +0 -0
- data/coverage/assets/0.12.3/colorbox/controls.png +0 -0
- data/coverage/assets/0.12.3/colorbox/loading.gif +0 -0
- data/coverage/assets/0.12.3/colorbox/loading_background.png +0 -0
- data/coverage/assets/0.12.3/favicon_green.png +0 -0
- data/coverage/assets/0.12.3/favicon_red.png +0 -0
- data/coverage/assets/0.12.3/favicon_yellow.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.12.3/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.12.3/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.12.3/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.12.3/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.12.3/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/assets/0.12.3/loading.gif +0 -0
- data/coverage/assets/0.12.3/magnify.png +0 -0
- data/coverage/index.html +8785 -0
- data/lib/ruby-enum/enum/case.rb +84 -0
- data/lib/ruby-enum/enum/i18n_mock.rb +19 -0
- data/lib/ruby-enum/enum.rb +14 -5
- data/lib/ruby-enum/errors/base.rb +3 -3
- data/lib/ruby-enum/version.rb +1 -1
- data/lib/ruby-enum.rb +15 -3
- data/ruby-enum.gemspec +2 -1
- data/spec/ruby-enum/enum/case_spec.rb +118 -0
- data/spec/ruby-enum/enum_spec.rb +143 -34
- data/spec/spec_helper.rb +4 -0
- data/spec_i18n/Gemfile +9 -0
- data/spec_i18n/Gemfile.lock +35 -0
- data/spec_i18n/Rakefile +12 -0
- data/spec_i18n/spec/i18n_spec.rb +48 -0
- data/spec_i18n/spec/spec_helper.rb +8 -0
- metadata +52 -24
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ruby
|
4
|
+
module Enum
|
5
|
+
##
|
6
|
+
# Adds a method to an enum class that allows for exhaustive matching on a value.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class Color
|
10
|
+
# include Ruby::Enum
|
11
|
+
# include Ruby::Enum::Case
|
12
|
+
#
|
13
|
+
# define :RED, :red
|
14
|
+
# define :GREEN, :green
|
15
|
+
# define :BLUE, :blue
|
16
|
+
# define :YELLOW, :yellow
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# Color.case(Color::RED, {
|
20
|
+
# [Color::RED, Color::GREEN] => -> { "red or green" },
|
21
|
+
# Color::BLUE => -> { "blue" },
|
22
|
+
# Color::YELLOW => -> { "yellow" },
|
23
|
+
# })
|
24
|
+
#
|
25
|
+
# Reserves the :else key for a default case:
|
26
|
+
# Color.case(Color::RED, {
|
27
|
+
# [Color::RED, Color::GREEN] => -> { "red or green" },
|
28
|
+
# else: -> { "blue or yellow" },
|
29
|
+
# })
|
30
|
+
module Case
|
31
|
+
def self.included(klass)
|
32
|
+
klass.extend(ClassMethods)
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# @see Ruby::Enum::Case
|
37
|
+
module ClassMethods
|
38
|
+
class ValuesNotDefinedError < StandardError
|
39
|
+
end
|
40
|
+
|
41
|
+
class NotAllCasesHandledError < StandardError
|
42
|
+
end
|
43
|
+
|
44
|
+
def case(value, cases)
|
45
|
+
validate_cases(cases)
|
46
|
+
|
47
|
+
filtered_cases = cases.select do |values, _proc|
|
48
|
+
values = [values] unless values.is_a?(Array)
|
49
|
+
values.include?(value)
|
50
|
+
end
|
51
|
+
|
52
|
+
return call_proc(cases[:else], value) if filtered_cases.none?
|
53
|
+
|
54
|
+
results = filtered_cases.map { |_values, proc| call_proc(proc, value) }
|
55
|
+
|
56
|
+
# Return the first result if there is only one result
|
57
|
+
results.size == 1 ? results.first : results
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def call_proc(proc, value)
|
63
|
+
return if proc.nil?
|
64
|
+
|
65
|
+
if proc.arity == 1
|
66
|
+
proc.call(value)
|
67
|
+
else
|
68
|
+
proc.call
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def validate_cases(cases)
|
73
|
+
all_values = cases.keys.flatten - [:else]
|
74
|
+
else_defined = cases.key?(:else)
|
75
|
+
superfluous_values = all_values - values
|
76
|
+
missing_values = values - all_values
|
77
|
+
|
78
|
+
raise ValuesNotDefinedError, "Value(s) not defined: #{superfluous_values.join(', ')}" if superfluous_values.any?
|
79
|
+
raise NotAllCasesHandledError, "Not all cases handled: #{missing_values.join(', ')}" if missing_values.any? && !else_defined
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :nocov:
|
4
|
+
module Ruby
|
5
|
+
module Enum
|
6
|
+
##
|
7
|
+
# Mock I18n module in case the i18n gem is not available.
|
8
|
+
module I18nMock
|
9
|
+
def self.load_path
|
10
|
+
[]
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.translate(key, _options = {})
|
14
|
+
key
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
# :nocov:
|
data/lib/ruby-enum/enum.rb
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
module Ruby
|
4
4
|
module Enum
|
5
|
+
class << self
|
6
|
+
# Needed for I18n mock
|
7
|
+
attr_accessor :i18n
|
8
|
+
end
|
9
|
+
|
5
10
|
attr_reader :key, :value
|
6
11
|
|
7
12
|
def initialize(key, value)
|
@@ -22,7 +27,7 @@ module Ruby
|
|
22
27
|
# === Parameters
|
23
28
|
# [key] Enumerator key.
|
24
29
|
# [value] Enumerator value.
|
25
|
-
def define(key, value)
|
30
|
+
def define(key, value = key)
|
26
31
|
@_enum_hash ||= {}
|
27
32
|
@_enums_by_value ||= {}
|
28
33
|
|
@@ -118,7 +123,13 @@ module Ruby
|
|
118
123
|
|
119
124
|
# Returns all enum values.
|
120
125
|
def values
|
121
|
-
@_enum_hash.values.map(&:value)
|
126
|
+
result = @_enum_hash.values.map(&:value)
|
127
|
+
|
128
|
+
if superclass < Ruby::Enum
|
129
|
+
superclass.values + result
|
130
|
+
else
|
131
|
+
result
|
132
|
+
end
|
122
133
|
end
|
123
134
|
|
124
135
|
# Iterate over all enumerated values.
|
@@ -138,9 +149,7 @@ module Ruby
|
|
138
149
|
end
|
139
150
|
|
140
151
|
def to_h
|
141
|
-
|
142
|
-
[key, enum.value]
|
143
|
-
end]
|
152
|
+
@_enum_hash.transform_values(&:value)
|
144
153
|
end
|
145
154
|
|
146
155
|
private
|
@@ -22,13 +22,13 @@ module Ruby
|
|
22
22
|
@summary = create_summary(key, attributes)
|
23
23
|
@resolution = create_resolution(key, attributes)
|
24
24
|
|
25
|
-
"\nProblem:\n #{@problem}"\
|
25
|
+
"\nProblem:\n #{@problem}" \
|
26
26
|
"\nSummary:\n #{@summary}" + "\nResolution:\n #{@resolution}"
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
30
30
|
|
31
|
-
BASE_KEY = 'ruby.enum.errors.messages'
|
31
|
+
BASE_KEY = 'ruby.enum.errors.messages' # :nodoc:
|
32
32
|
|
33
33
|
# Given the key of the specific error and the options hash, translate the
|
34
34
|
# message.
|
@@ -39,7 +39,7 @@ module Ruby
|
|
39
39
|
#
|
40
40
|
# Returns a localized error message string.
|
41
41
|
def translate(key, options)
|
42
|
-
::
|
42
|
+
Ruby::Enum.i18n.translate("#{BASE_KEY}.#{key}", locale: :en, **options).strip
|
43
43
|
end
|
44
44
|
|
45
45
|
# Create the problem.
|
data/lib/ruby-enum/version.rb
CHANGED
data/lib/ruby-enum.rb
CHANGED
@@ -1,11 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'i18n'
|
4
|
-
|
5
3
|
require 'ruby-enum/version'
|
6
4
|
require 'ruby-enum/enum'
|
5
|
+
require 'ruby-enum/enum/case'
|
6
|
+
require 'ruby-enum/enum/i18n_mock'
|
7
|
+
|
8
|
+
# Try to load the I18n gem and provide a mock if it is not available.
|
9
|
+
begin
|
10
|
+
require 'i18n'
|
11
|
+
Ruby::Enum.i18n = I18n
|
12
|
+
rescue LoadError
|
13
|
+
# I18n is not available
|
14
|
+
# :nocov:
|
15
|
+
# Tests for this loading are in the spec_i18n folder
|
16
|
+
Ruby::Enum.i18n = Ruby::Enum::I18nMock
|
17
|
+
# :nocov:
|
18
|
+
end
|
7
19
|
|
8
|
-
|
20
|
+
Ruby::Enum.i18n.load_path << File.join(File.dirname(__FILE__), 'config', 'locales', 'en.yml')
|
9
21
|
|
10
22
|
require 'ruby-enum/errors/base'
|
11
23
|
require 'ruby-enum/errors/uninitialized_constant_error'
|
data/ruby-enum.gemspec
CHANGED
@@ -10,10 +10,11 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.email = 'dblock@dblock.org'
|
11
11
|
s.platform = Gem::Platform::RUBY
|
12
12
|
s.required_rubygems_version = '>= 1.3.6'
|
13
|
+
s.required_ruby_version = '>= 2.7'
|
13
14
|
s.files = Dir['**/*']
|
14
15
|
s.require_paths = ['lib']
|
15
16
|
s.homepage = 'http://github.com/dblock/ruby-enum'
|
16
17
|
s.licenses = ['MIT']
|
17
18
|
s.summary = 'Enum-like behavior for Ruby.'
|
18
|
-
s.
|
19
|
+
s.metadata['rubygems_mfa_required'] = 'true'
|
19
20
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Ruby::Enum::Case do
|
6
|
+
test_enum =
|
7
|
+
Class.new do
|
8
|
+
include Ruby::Enum
|
9
|
+
include Ruby::Enum::Case
|
10
|
+
|
11
|
+
define :RED, :red
|
12
|
+
define :GREEN, :green
|
13
|
+
define :BLUE, :blue
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.case' do
|
17
|
+
context 'when all cases are defined' do
|
18
|
+
subject { test_enum.case(test_enum::RED, cases) }
|
19
|
+
|
20
|
+
let(:cases) do
|
21
|
+
{
|
22
|
+
[test_enum::RED, test_enum::GREEN] => -> { 'red or green' },
|
23
|
+
test_enum::BLUE => -> { 'blue' }
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
it { is_expected.to eq('red or green') }
|
28
|
+
|
29
|
+
context 'when the value is nil' do
|
30
|
+
subject { test_enum.case(nil, cases) }
|
31
|
+
|
32
|
+
it { is_expected.to be_nil }
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when the value is empty' do
|
36
|
+
subject { test_enum.case('', cases) }
|
37
|
+
|
38
|
+
it { is_expected.to be_nil }
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when the value is the value of the enum' do
|
42
|
+
subject { test_enum.case(:red, cases) }
|
43
|
+
|
44
|
+
it { is_expected.to eq('red or green') }
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when the value is used inside the lambda' do
|
48
|
+
subject { test_enum.case(test_enum::RED, cases) }
|
49
|
+
|
50
|
+
let(:cases) do
|
51
|
+
{
|
52
|
+
[test_enum::RED, test_enum::GREEN] => ->(color) { "is #{color}" },
|
53
|
+
test_enum::BLUE => -> { 'blue' }
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
it { is_expected.to eq('is red') }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when there are mutliple matches' do
|
62
|
+
subject do
|
63
|
+
test_enum.case(
|
64
|
+
test_enum::RED,
|
65
|
+
{
|
66
|
+
[test_enum::RED, test_enum::GREEN] => -> { 'red or green' },
|
67
|
+
test_enum::RED => -> { 'red' },
|
68
|
+
test_enum::BLUE => -> { 'blue' }
|
69
|
+
}
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
it { is_expected.to eq(['red or green', 'red']) }
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when not all cases are defined' do
|
77
|
+
it 'raises an error' do
|
78
|
+
expect do
|
79
|
+
test_enum.case(
|
80
|
+
test_enum::RED,
|
81
|
+
{ [test_enum::RED, test_enum::GREEN] => -> { 'red or green' } }
|
82
|
+
)
|
83
|
+
end.to raise_error(Ruby::Enum::Case::ClassMethods::NotAllCasesHandledError)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'when not all cases are defined but :else is specified (default case)' do
|
88
|
+
it 'does not raise an error' do
|
89
|
+
expect do
|
90
|
+
result = test_enum.case(
|
91
|
+
test_enum::BLUE,
|
92
|
+
{
|
93
|
+
[test_enum::RED, test_enum::GREEN] => -> { 'red or green' },
|
94
|
+
else: -> { 'blue' }
|
95
|
+
}
|
96
|
+
)
|
97
|
+
|
98
|
+
expect(result).to eq('blue')
|
99
|
+
end.not_to raise_error
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'when a superfluous case is defined' do
|
104
|
+
it 'raises an error' do
|
105
|
+
expect do
|
106
|
+
test_enum.case(
|
107
|
+
test_enum::RED,
|
108
|
+
{
|
109
|
+
[test_enum::RED, test_enum::GREEN] => -> { 'red or green' },
|
110
|
+
test_enum::BLUE => -> { 'blue' },
|
111
|
+
:something => -> { 'green' }
|
112
|
+
}
|
113
|
+
)
|
114
|
+
end.to raise_error(Ruby::Enum::Case::ClassMethods::ValuesNotDefinedError)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/spec/ruby-enum/enum_spec.rb
CHANGED
@@ -22,10 +22,28 @@ describe Ruby::Enum do
|
|
22
22
|
expect(Colors::RED).to eq 'red'
|
23
23
|
expect(Colors::GREEN).to eq 'green'
|
24
24
|
end
|
25
|
-
|
26
|
-
|
25
|
+
|
26
|
+
context 'when the i18n gem is loaded' do
|
27
|
+
it 'raises UninitializedConstantError on an invalid constant' do
|
28
|
+
expect do
|
29
|
+
Colors::ANYTHING
|
30
|
+
end.to raise_error Ruby::Enum::Errors::UninitializedConstantError, /The constant Colors::ANYTHING has not been defined./
|
31
|
+
end
|
27
32
|
end
|
28
|
-
|
33
|
+
|
34
|
+
context 'when the i18n gem is not loaded' do
|
35
|
+
before do
|
36
|
+
allow(described_class).to receive(:i18n).and_return(Ruby::Enum::I18nMock)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'raises UninitializedConstantError on an invalid constant' do
|
40
|
+
expect do
|
41
|
+
Colors::ANYTHING
|
42
|
+
end.to raise_error Ruby::Enum::Errors::UninitializedConstantError, /ruby.enum.errors.messages.uninitialized_constant.summary/
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#each' do
|
29
47
|
it 'iterates over constants' do
|
30
48
|
keys = []
|
31
49
|
enum_keys = []
|
@@ -40,7 +58,8 @@ describe Ruby::Enum do
|
|
40
58
|
expect(enum_values).to eq %w[red green]
|
41
59
|
end
|
42
60
|
end
|
43
|
-
|
61
|
+
|
62
|
+
describe '#map' do
|
44
63
|
it 'maps constants' do
|
45
64
|
key_key_values = Colors.map do |key, enum|
|
46
65
|
[key, enum.key, enum.value]
|
@@ -50,103 +69,152 @@ describe Ruby::Enum do
|
|
50
69
|
expect(key_key_values[1]).to eq [:GREEN, :GREEN, 'green']
|
51
70
|
end
|
52
71
|
end
|
53
|
-
|
72
|
+
|
73
|
+
describe '#parse' do
|
54
74
|
it 'parses exact value' do
|
55
75
|
expect(Colors.parse('red')).to eq(Colors::RED)
|
56
76
|
end
|
77
|
+
|
57
78
|
it 'is case-insensitive' do
|
58
79
|
expect(Colors.parse('ReD')).to eq(Colors::RED)
|
59
80
|
end
|
81
|
+
|
60
82
|
it 'returns nil for a null value' do
|
61
83
|
expect(Colors.parse(nil)).to be_nil
|
62
84
|
end
|
85
|
+
|
63
86
|
it 'returns nil for an invalid value' do
|
64
87
|
expect(Colors.parse('invalid')).to be_nil
|
65
88
|
end
|
66
89
|
end
|
67
|
-
|
90
|
+
|
91
|
+
describe '#key?' do
|
68
92
|
it 'returns true for valid keys accessed directly' do
|
69
93
|
Colors.keys.each do |key| # rubocop:disable Style/HashEachMethods
|
70
|
-
expect(Colors.key?(key)).to
|
94
|
+
expect(Colors.key?(key)).to be(true)
|
71
95
|
end
|
72
96
|
end
|
97
|
+
|
73
98
|
it 'returns true for valid keys accessed via each_keys' do
|
74
99
|
Colors.each_key do |key|
|
75
|
-
expect(Colors.key?(key)).to
|
100
|
+
expect(Colors.key?(key)).to be(true)
|
76
101
|
end
|
77
102
|
end
|
103
|
+
|
78
104
|
it 'returns false for invalid keys' do
|
79
|
-
expect(Colors.key?(:NOT_A_KEY)).to
|
105
|
+
expect(Colors.key?(:NOT_A_KEY)).to be(false)
|
80
106
|
end
|
81
107
|
end
|
82
|
-
|
108
|
+
|
109
|
+
describe '#value' do
|
83
110
|
it 'returns string values for keys' do
|
84
111
|
Colors.each do |key, enum|
|
85
112
|
expect(Colors.value(key)).to eq(enum.value)
|
86
113
|
end
|
87
114
|
end
|
115
|
+
|
88
116
|
it 'returns nil for an invalid key' do
|
89
117
|
expect(Colors.value(:NOT_A_KEY)).to be_nil
|
90
118
|
end
|
91
119
|
end
|
92
|
-
|
120
|
+
|
121
|
+
describe '#value?' do
|
93
122
|
it 'returns true for valid values accessed directly' do
|
94
123
|
Colors.values.each do |value| # rubocop:disable Style/HashEachMethods
|
95
|
-
expect(Colors.value?(value)).to
|
124
|
+
expect(Colors.value?(value)).to be(true)
|
96
125
|
end
|
97
126
|
end
|
127
|
+
|
98
128
|
it 'returns true for valid values accessed via each_value' do
|
99
129
|
Colors.each_value do |value|
|
100
|
-
expect(Colors.value?(value)).to
|
130
|
+
expect(Colors.value?(value)).to be(true)
|
101
131
|
end
|
102
132
|
end
|
133
|
+
|
103
134
|
it 'returns false for invalid values' do
|
104
|
-
expect(Colors.value?('I am not a value')).to
|
135
|
+
expect(Colors.value?('I am not a value')).to be(false)
|
105
136
|
end
|
106
137
|
end
|
107
|
-
|
138
|
+
|
139
|
+
describe '#key' do
|
108
140
|
it 'returns enum instances for values' do
|
109
|
-
Colors.each do |_, enum|
|
141
|
+
Colors.each do |_, enum| # rubocop:disable Style/HashEachMethods
|
110
142
|
expect(Colors.key(enum.value)).to eq(enum.key)
|
111
143
|
end
|
112
144
|
end
|
145
|
+
|
113
146
|
it 'returns nil for an invalid value' do
|
114
147
|
expect(Colors.key('invalid')).to be_nil
|
115
148
|
end
|
116
149
|
end
|
117
|
-
|
150
|
+
|
151
|
+
describe '#keys' do
|
118
152
|
it 'returns keys' do
|
119
153
|
expect(Colors.keys).to eq(%i[RED GREEN])
|
120
154
|
end
|
121
155
|
end
|
122
|
-
|
156
|
+
|
157
|
+
describe '#values' do
|
123
158
|
it 'returns values' do
|
124
159
|
expect(Colors.values).to eq(%w[red green])
|
125
160
|
end
|
126
161
|
end
|
127
|
-
|
162
|
+
|
163
|
+
describe '#to_h' do
|
128
164
|
it 'returns a hash of key:values' do
|
129
165
|
expect(Colors.to_h).to eq(RED: 'red', GREEN: 'green')
|
130
166
|
end
|
131
167
|
end
|
132
168
|
|
133
|
-
context '
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
169
|
+
context 'when a duplicate key is used' do
|
170
|
+
context 'when the i18n gem is loaded' do
|
171
|
+
it 'raises DuplicateKeyError' do
|
172
|
+
expect do
|
173
|
+
Colors.class_eval do
|
174
|
+
define :RED, 'some'
|
175
|
+
end
|
176
|
+
end.to raise_error Ruby::Enum::Errors::DuplicateKeyError, /The constant Colors::RED has already been defined./
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when the i18n gem is not loaded' do
|
181
|
+
before do
|
182
|
+
allow(described_class).to receive(:i18n).and_return(Ruby::Enum::I18nMock)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'raises DuplicateKeyError' do
|
186
|
+
expect do
|
187
|
+
Colors.class_eval do
|
188
|
+
define :RED, 'some'
|
189
|
+
end
|
190
|
+
end.to raise_error Ruby::Enum::Errors::DuplicateKeyError, /ruby.enum.errors.messages.duplicate_key.message/
|
191
|
+
end
|
140
192
|
end
|
141
193
|
end
|
142
194
|
|
143
|
-
context '
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
195
|
+
context 'when a duplicate value is used' do
|
196
|
+
context 'when the i18n gem is loaded' do
|
197
|
+
it 'raises a DuplicateValueError' do
|
198
|
+
expect do
|
199
|
+
Colors.class_eval do
|
200
|
+
define :Other, 'red'
|
201
|
+
end
|
202
|
+
end.to raise_error Ruby::Enum::Errors::DuplicateValueError, /The value red has already been defined./
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'when the i18n gem is not loaded' do
|
207
|
+
before do
|
208
|
+
allow(described_class).to receive(:i18n).and_return(Ruby::Enum::I18nMock)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'raises a DuplicateValueError' do
|
212
|
+
expect do
|
213
|
+
Colors.class_eval do
|
214
|
+
define :Other, 'red'
|
215
|
+
end
|
216
|
+
end.to raise_error Ruby::Enum::Errors::DuplicateValueError, /ruby.enum.errors.messages.duplicate_value.summary/
|
217
|
+
end
|
150
218
|
end
|
151
219
|
end
|
152
220
|
|
@@ -176,17 +244,49 @@ describe Ruby::Enum do
|
|
176
244
|
it 'contains its own enums' do
|
177
245
|
expect(FirstSubclass::ORANGE).to eq 'orange'
|
178
246
|
end
|
247
|
+
|
179
248
|
it 'parent class should not have enums defined in child classes' do
|
180
249
|
expect { Colors::ORANGE }.to raise_error Ruby::Enum::Errors::UninitializedConstantError
|
181
250
|
end
|
182
|
-
|
251
|
+
|
252
|
+
context 'when defining a 2 level depth subclass' do
|
183
253
|
subject { SecondSubclass }
|
254
|
+
|
184
255
|
it 'contains its own enums and all the enums defined in the parent classes' do
|
185
256
|
expect(subject::RED).to eq 'red'
|
186
257
|
expect(subject::GREEN).to eq 'green'
|
187
258
|
expect(subject::ORANGE).to eq 'orange'
|
188
259
|
expect(subject::PINK).to eq 'pink'
|
189
260
|
end
|
261
|
+
|
262
|
+
describe '#values' do
|
263
|
+
subject { SecondSubclass.values }
|
264
|
+
|
265
|
+
it 'contains the values from all of the parent classes' do
|
266
|
+
expect(subject).to eq(%w[red green orange pink])
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe '#values' do
|
272
|
+
subject { FirstSubclass.values }
|
273
|
+
|
274
|
+
it 'contains the values from the parent class' do
|
275
|
+
expect(subject).to eq(%w[red green orange])
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
describe 'default value' do
|
281
|
+
class Default
|
282
|
+
include Ruby::Enum
|
283
|
+
define :KEY
|
284
|
+
end
|
285
|
+
|
286
|
+
subject { Default::KEY }
|
287
|
+
|
288
|
+
it 'equals the key' do
|
289
|
+
expect(subject).to eq(:KEY)
|
190
290
|
end
|
191
291
|
end
|
192
292
|
|
@@ -195,17 +295,26 @@ describe Ruby::Enum do
|
|
195
295
|
include Ruby::Enum
|
196
296
|
define :created, 'Created'
|
197
297
|
define :published, 'Published'
|
298
|
+
define :undefined
|
198
299
|
end
|
199
300
|
subject { States }
|
301
|
+
|
200
302
|
it 'behaves like an enum' do
|
201
303
|
expect(subject.created).to eq 'Created'
|
202
304
|
expect(subject.published).to eq 'Published'
|
305
|
+
expect(subject.undefined).to eq :undefined
|
203
306
|
|
204
307
|
expect(subject.key?(:created)).to be true
|
205
308
|
expect(subject.key('Created')).to eq :created
|
206
309
|
|
207
310
|
expect(subject.value?('Created')).to be true
|
208
311
|
expect(subject.value(:created)).to eq 'Created'
|
312
|
+
|
313
|
+
expect(subject.key?(:undefined)).to be true
|
314
|
+
expect(subject.key(:undefined)).to eq :undefined
|
315
|
+
|
316
|
+
expect(subject.value?(:undefined)).to be true
|
317
|
+
expect(subject.value(:undefined)).to eq :undefined
|
209
318
|
end
|
210
319
|
end
|
211
320
|
end
|
data/spec/spec_helper.rb
CHANGED