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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -10
  3. data/Dangerfile +4 -0
  4. data/Gemfile +10 -1
  5. data/Gemfile.lock +143 -33
  6. data/LICENSE.md +1 -1
  7. data/README.md +202 -76
  8. data/RELEASING.md +4 -11
  9. data/Rakefile +7 -0
  10. data/UPGRADING.md +44 -0
  11. data/benchmarks/case.rb +45 -0
  12. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc.png +0 -0
  13. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
  14. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_both.png +0 -0
  15. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc.png +0 -0
  16. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
  17. data/coverage/assets/0.12.3/application.css +1 -0
  18. data/coverage/assets/0.12.3/application.js +7 -0
  19. data/coverage/assets/0.12.3/colorbox/border.png +0 -0
  20. data/coverage/assets/0.12.3/colorbox/controls.png +0 -0
  21. data/coverage/assets/0.12.3/colorbox/loading.gif +0 -0
  22. data/coverage/assets/0.12.3/colorbox/loading_background.png +0 -0
  23. data/coverage/assets/0.12.3/favicon_green.png +0 -0
  24. data/coverage/assets/0.12.3/favicon_red.png +0 -0
  25. data/coverage/assets/0.12.3/favicon_yellow.png +0 -0
  26. data/coverage/assets/0.12.3/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  27. data/coverage/assets/0.12.3/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  28. data/coverage/assets/0.12.3/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  29. data/coverage/assets/0.12.3/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  30. data/coverage/assets/0.12.3/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  31. data/coverage/assets/0.12.3/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  32. data/coverage/assets/0.12.3/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  33. data/coverage/assets/0.12.3/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  34. data/coverage/assets/0.12.3/images/ui-icons_222222_256x240.png +0 -0
  35. data/coverage/assets/0.12.3/images/ui-icons_2e83ff_256x240.png +0 -0
  36. data/coverage/assets/0.12.3/images/ui-icons_454545_256x240.png +0 -0
  37. data/coverage/assets/0.12.3/images/ui-icons_888888_256x240.png +0 -0
  38. data/coverage/assets/0.12.3/images/ui-icons_cd0a0a_256x240.png +0 -0
  39. data/coverage/assets/0.12.3/loading.gif +0 -0
  40. data/coverage/assets/0.12.3/magnify.png +0 -0
  41. data/coverage/index.html +8785 -0
  42. data/lib/ruby-enum/enum/case.rb +84 -0
  43. data/lib/ruby-enum/enum/i18n_mock.rb +19 -0
  44. data/lib/ruby-enum/enum.rb +14 -5
  45. data/lib/ruby-enum/errors/base.rb +3 -3
  46. data/lib/ruby-enum/version.rb +1 -1
  47. data/lib/ruby-enum.rb +15 -3
  48. data/ruby-enum.gemspec +2 -1
  49. data/spec/ruby-enum/enum/case_spec.rb +118 -0
  50. data/spec/ruby-enum/enum_spec.rb +143 -34
  51. data/spec/spec_helper.rb +4 -0
  52. data/spec_i18n/Gemfile +9 -0
  53. data/spec_i18n/Gemfile.lock +35 -0
  54. data/spec_i18n/Rakefile +12 -0
  55. data/spec_i18n/spec/i18n_spec.rb +48 -0
  56. data/spec_i18n/spec/spec_helper.rb +8 -0
  57. 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:
@@ -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
- Hash[@_enum_hash.map do |key, enum|
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' #:nodoc:
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
- ::I18n.translate("#{BASE_KEY}.#{key}", { locale: :en }.merge(options)).strip
42
+ Ruby::Enum.i18n.translate("#{BASE_KEY}.#{key}", locale: :en, **options).strip
43
43
  end
44
44
 
45
45
  # Create the problem.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ruby
4
4
  module Enum
5
- VERSION = '0.8.0'
5
+ VERSION = '1.0.0'
6
6
  end
7
7
  end
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
- I18n.load_path << File.join(File.dirname(__FILE__), 'config', 'locales', 'en.yml')
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.add_dependency 'i18n'
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
@@ -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
- it 'raises UninitializedConstantError on an invalid constant' do
26
- expect { Colors::ANYTHING }.to raise_error Ruby::Enum::Errors::UninitializedConstantError, /The constant Colors::ANYTHING has not been defined./
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
- context '#each' do
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
- context '#map' do
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
- context '#parse' do
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
- context '#key?' do
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 eq(true)
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 eq(true)
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 eq(false)
105
+ expect(Colors.key?(:NOT_A_KEY)).to be(false)
80
106
  end
81
107
  end
82
- context '#value' do
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
- context '#value?' do
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 eq(true)
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 eq(true)
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 eq(false)
135
+ expect(Colors.value?('I am not a value')).to be(false)
105
136
  end
106
137
  end
107
- context '#key' do
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
- context '#keys' do
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
- context '#values' do
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
- context '#to_h' do
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 'on duplicate keys' do
134
- it 'raises DuplicateKeyError' do
135
- expect do
136
- Colors.class_eval do
137
- define :RED, 'some'
138
- end
139
- end.to raise_error Ruby::Enum::Errors::DuplicateKeyError, /The constant Colors::RED has already been defined./
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 'on duplicate values' do
144
- it 'raises a DuplicateValueError' do
145
- expect do
146
- Colors.class_eval do
147
- define :Other, 'red'
148
- end
149
- end.to raise_error Ruby::Enum::Errors::DuplicateValueError, /The value red has already been defined./
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
- context 'Given a 2 level depth subclass' do
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
@@ -3,6 +3,10 @@
3
3
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
4
 
5
5
  require 'rubygems'
6
+
7
+ require 'simplecov'
8
+ SimpleCov.start
9
+
6
10
  require 'rspec'
7
11
  require 'ruby-enum'
8
12
 
data/spec_i18n/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'http://rubygems.org'
4
+
5
+ gemspec path: '../', name: 'ruby-enum'
6
+
7
+ # This Gemfile should not include any gem that has i18n as a dependency.
8
+ gem 'rake'
9
+ gem 'rspec', '~> 3.0'