literal_enums 1.1.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/workflows/ci.yml +29 -0
- data/.gitignore +2 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/Gemfile +7 -3
- data/README.md +15 -43
- data/bench.rb +18 -0
- data/lib/enum.rb +58 -21
- data/lib/literal_enums/transitions.rb +16 -18
- data/lib/literal_enums/version.rb +1 -1
- data/lib/literal_enums.rb +3 -5
- data/literal_enums.gemspec +2 -5
- metadata +8 -61
- data/.github/workflows/ruby.yml +0 -24
- data/Gemfile.lock +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7e6724b81f59fbf8d701b0567dc17c344c53c677c318992a7a799acf3242c05
|
4
|
+
data.tar.gz: 735a34d71b23525d8285e4fccb39063946ba1af6ff691081471d9b14f869bc40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4331f3a30ca04be1eb49fb20463a673eb36a9a721fab8ae7fd0fb8ecab1a1c37d0ba9e43b34b20416230f43fac8f3c738cfff0127b4cfdc8feb3a5d30f1ea064
|
7
|
+
data.tar.gz: d25213819f531fb985c7556171a8fc4820d87672f7bad03a41c1cdda26cb7c20c0974db96f832016aba3251a1581337f0000aebe7c4a00fb128884266e67de19
|
data/.github/FUNDING.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ main ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ main ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
tests:
|
11
|
+
strategy:
|
12
|
+
matrix:
|
13
|
+
os: ['ubuntu-latest', 'macos-latest']
|
14
|
+
ruby-version: ['2.7', '3.0', '3.1', 'head']
|
15
|
+
runs-on: ${{ matrix.os }}
|
16
|
+
steps:
|
17
|
+
- uses: actions/checkout@v3
|
18
|
+
|
19
|
+
- name: Setup
|
20
|
+
uses: ruby/setup-ruby@v1
|
21
|
+
with:
|
22
|
+
ruby-version: ${{ matrix.ruby-version }}
|
23
|
+
bundler-cache: false
|
24
|
+
|
25
|
+
- name: Install dependencies
|
26
|
+
run: bundle install
|
27
|
+
|
28
|
+
- name: Tests
|
29
|
+
run: bundle exec rake
|
data/.gitignore
CHANGED
data/CODE_OF_CONDUCT.md
CHANGED
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
|
|
55
55
|
## Enforcement
|
56
56
|
|
57
57
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
-
reported by contacting the project team at joel
|
58
|
+
reported by contacting the project team at joel@drapper.me. All
|
59
59
|
complaints will be reviewed and investigated and will result in a response that
|
60
60
|
is deemed necessary and appropriate to the circumstances. The project team is
|
61
61
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
data/Gemfile
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
source "https://rubygems.org"
|
4
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
4
5
|
|
5
|
-
# Specify your gem's dependencies in literal_enums.gemspec
|
6
6
|
gemspec
|
7
|
+
|
8
|
+
gem "rake"
|
9
|
+
gem "minitest"
|
10
|
+
gem "benchmark-ips"
|
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
This documentation is for Literal Enums 2.0, which is not yet supported by Literal Enums Rails. You can see documentaiton for Literal Enums v1 [here](https://github.com/joeldrapper/literal_enums/tree/d49eeba40f01f24c6b26d4dcdc6abb0da28e9ccb#readme).
|
2
|
+
|
1
3
|
# literal_enums
|
2
4
|
|
3
5
|
Literal Enums makes Enumerations first-class citizens in Ruby, providing a literal definition syntax.
|
@@ -8,9 +10,9 @@ You can define an enum by subclassing `Enum` and using the literal syntax.
|
|
8
10
|
|
9
11
|
```ruby
|
10
12
|
class Color < Enum
|
11
|
-
Red
|
12
|
-
Green
|
13
|
-
Blue
|
13
|
+
Red
|
14
|
+
Green
|
15
|
+
Blue
|
14
16
|
end
|
15
17
|
```
|
16
18
|
|
@@ -20,7 +22,7 @@ Here we’ve enumerated `Color::Red`, `Color::Green`, and `Color::Blue` constant
|
|
20
22
|
Color::Red.is_a?(Color) # returns true
|
21
23
|
```
|
22
24
|
|
23
|
-
Enum classes have synthetic methods for looking up their members. `Color.members` will return
|
25
|
+
Enum classes have synthetic methods for looking up their members. `Color.members` will return an `Array` of members of the `Color` enumeration: `Color::Red`, `Color::Green`, and `Color::Blue`.
|
24
26
|
|
25
27
|
Members also have polymorphic predicate methods for each member of the enumeration in lower-snake-case.
|
26
28
|
|
@@ -46,7 +48,7 @@ end
|
|
46
48
|
Then we can look up all the values.
|
47
49
|
|
48
50
|
```ruby
|
49
|
-
Color.values # returns
|
51
|
+
Color.values # returns an Array of ["ff0000", "00ff00", "0000f"].
|
50
52
|
```
|
51
53
|
|
52
54
|
We can also look at the value for any member directly.
|
@@ -90,50 +92,20 @@ It is also possible to define a more complex state machine by defining `transiti
|
|
90
92
|
|
91
93
|
```ruby
|
92
94
|
class State < Enum
|
93
|
-
Pending
|
94
|
-
|
95
|
-
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
Approved do
|
100
|
-
def transitions_to
|
101
|
-
Published
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
Rejected do
|
106
|
-
def transitions_to
|
107
|
-
Deleted
|
108
|
-
end
|
109
|
-
end
|
95
|
+
Pending -> { [Approved, Rejected] }
|
96
|
+
Approved -> { Published }
|
97
|
+
Rejected -> { Deleted }
|
110
98
|
|
111
|
-
Deleted
|
112
|
-
Published
|
99
|
+
Deleted
|
100
|
+
Published
|
113
101
|
end
|
114
102
|
```
|
115
103
|
|
116
|
-
Given the above definition, we can transition from one state to another by calling
|
117
|
-
|
118
|
-
```ruby
|
119
|
-
State::Pending.transition_to(State::Approved) # returns State::Approved.
|
120
|
-
State::Pending.transition_to(State::Published) # raises a LiteralEnums::TransitionError.
|
121
|
-
```
|
122
|
-
|
123
|
-
Alternatively, we can call the new state as a method on the old state.
|
124
|
-
|
125
|
-
```ruby
|
126
|
-
State::Pending.approved # returns State::Approved.
|
127
|
-
```
|
128
|
-
|
129
|
-
An invalid transition would return a `NoMethodErorr` in this case as the method is not defined.
|
130
|
-
|
131
|
-
The advantage of using method calls to transition from one state to anotehr is the method calls can be chained.
|
104
|
+
Given the above definition, we can transition from one state to another by calling `>>` with the newly desired state. This will raise a `LiteralEnums::TransitionError` if the transition is invalid.
|
132
105
|
|
133
106
|
```ruby
|
134
|
-
State::Pending
|
135
|
-
|
136
|
-
# valid to move to State::Approved from State::Pending.
|
107
|
+
State::Pending >> State::Approved # returns State::Approved.
|
108
|
+
State::Pending >> State::Published # raises a LiteralEnums::TransitionError.
|
137
109
|
```
|
138
110
|
|
139
111
|
## Installation
|
data/bench.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "literal_enums"
|
5
|
+
require "benchmark/ips"
|
6
|
+
|
7
|
+
class Color < Enum
|
8
|
+
Red("#f00")
|
9
|
+
Green("#0f0")
|
10
|
+
Blue("#00f")
|
11
|
+
end
|
12
|
+
|
13
|
+
Benchmark.ips do |x|
|
14
|
+
x.report("Cast") { Color.cast("f00") }
|
15
|
+
x.report("Lookup") { Color::Red }
|
16
|
+
x.report("Members") { Color.members }
|
17
|
+
x.report("Values") { Color.values }
|
18
|
+
end
|
data/lib/enum.rb
CHANGED
@@ -7,57 +7,94 @@ class Enum
|
|
7
7
|
alias_method :inspect, :name
|
8
8
|
|
9
9
|
def initialize(name, value)
|
10
|
+
@short_name = name.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase!
|
10
11
|
@name = "#{self.class.name}::#{name}"
|
11
|
-
@value = value
|
12
|
+
@value = value
|
12
13
|
end
|
13
14
|
|
14
15
|
class << self
|
16
|
+
attr_reader :members
|
17
|
+
|
18
|
+
def inherited(child)
|
19
|
+
TracePoint.new(:end) do |tp|
|
20
|
+
if tp.self == child
|
21
|
+
tp.self.freeze
|
22
|
+
tp.disable
|
23
|
+
end
|
24
|
+
end.enable
|
25
|
+
|
26
|
+
child.instance_eval do
|
27
|
+
@values = {}
|
28
|
+
@members = []
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def const_missing(name)
|
33
|
+
return super if frozen?
|
34
|
+
new(name)
|
35
|
+
end
|
36
|
+
|
15
37
|
def method_missing(name, *args, **kwargs, &block)
|
16
|
-
return super
|
38
|
+
return super if frozen?
|
39
|
+
return super unless name[0] =~ /[A-Z]/
|
17
40
|
new(name, *args, **kwargs, &block)
|
18
41
|
end
|
19
42
|
|
20
43
|
def cast(value)
|
21
|
-
|
44
|
+
@values[value]
|
22
45
|
end
|
23
46
|
|
24
47
|
def values
|
25
|
-
|
48
|
+
@values.keys
|
26
49
|
end
|
27
50
|
|
28
51
|
def each(&block)
|
29
|
-
members.each(&block)
|
30
|
-
end
|
31
|
-
|
32
|
-
def members
|
33
|
-
constants.map { |c| const_get(c) }.to_set
|
52
|
+
@members.each(&block)
|
34
53
|
end
|
35
54
|
|
36
55
|
private
|
37
56
|
|
38
|
-
def new(name,
|
39
|
-
|
40
|
-
|
57
|
+
def new(name, a = nil, b = nil, &block)
|
58
|
+
|
59
|
+
# If only one positional argument is provided and it's a proc, treat it as the transitions_to definition. Otherwise, the first argument is the value and the second argument is the transitions_to definition.
|
60
|
+
|
61
|
+
if !b && Proc === a
|
62
|
+
transitions_to = a
|
63
|
+
value = name
|
64
|
+
else
|
65
|
+
value = a || name
|
66
|
+
transitions_to = b
|
41
67
|
end
|
42
68
|
|
43
|
-
if
|
44
|
-
raise ArgumentError,
|
69
|
+
if self == Enum
|
70
|
+
raise ArgumentError,
|
71
|
+
"You can't add values to the abstract Enum class itself."
|
45
72
|
end
|
46
73
|
|
47
|
-
if
|
48
|
-
raise ArgumentError,
|
74
|
+
if const_defined?(name)
|
75
|
+
raise ArgumentError,
|
76
|
+
"Name conflict: '#{self.name}::#{name}' is already defined."
|
49
77
|
end
|
50
78
|
|
51
|
-
|
52
|
-
|
79
|
+
if @values[value]
|
80
|
+
raise ArgumentError,
|
81
|
+
"Value conflict: the value '#{value}' is defined for '#{self.cast(value).name}'."
|
82
|
+
end
|
53
83
|
|
54
84
|
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
55
|
-
def #{name.to_s.
|
56
|
-
|
85
|
+
def #{name.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase!}?
|
86
|
+
@short_name == "#{name.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase!}"
|
57
87
|
end
|
58
88
|
RUBY
|
59
89
|
|
60
|
-
|
90
|
+
member = super(name, value)
|
91
|
+
member.instance_eval(&block) if block_given?
|
92
|
+
member.define_singleton_method(:transitions_to, transitions_to) if transitions_to
|
93
|
+
member.freeze
|
94
|
+
|
95
|
+
const_set(name, member)
|
96
|
+
@members << member
|
97
|
+
@values[value] = member
|
61
98
|
end
|
62
99
|
end
|
63
100
|
end
|
@@ -1,32 +1,30 @@
|
|
1
1
|
module LiteralEnums
|
2
2
|
module Transitions
|
3
|
-
def
|
4
|
-
return
|
5
|
-
valid_next_states.any? { |m| m.name.to_s.demodulize.underscore.to_sym == name }
|
6
|
-
end
|
3
|
+
def >>(new_state)
|
4
|
+
return self if new_state == self
|
7
5
|
|
8
|
-
|
9
|
-
|
6
|
+
if transitions_to?(new_state)
|
7
|
+
new_state
|
8
|
+
else
|
9
|
+
raise TransitionError,
|
10
|
+
"You can't transition from #{self.name} to #{new_state.name}."
|
11
|
+
end
|
10
12
|
end
|
11
13
|
|
12
|
-
def
|
13
|
-
|
14
|
+
def transitions_to?(new_state)
|
15
|
+
possible_states = transitions_to
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
raise ArgumentError "You can only transition to another #{self.class.name}."
|
17
|
+
case possible_states
|
18
|
+
when Enum
|
19
|
+
possible_states == new_state
|
20
|
+
when Array
|
21
|
+
possible_states.include?(new_state)
|
21
22
|
end
|
22
|
-
|
23
|
-
valid_next_states.include?(new_state)
|
24
23
|
end
|
25
24
|
|
26
25
|
private
|
27
26
|
|
28
|
-
def
|
29
|
-
return Array(transitions_to) if respond_to? :transitions_to
|
27
|
+
def transitions_to
|
30
28
|
[]
|
31
29
|
end
|
32
30
|
end
|
data/lib/literal_enums.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
require "active_support"
|
2
|
-
require "active_support/core_ext/string"
|
3
|
-
|
4
1
|
require "literal_enums/version"
|
5
2
|
require "literal_enums/transitions"
|
6
3
|
require "enum"
|
7
4
|
|
8
5
|
module LiteralEnums
|
9
|
-
|
10
|
-
|
6
|
+
Error = Module.new
|
7
|
+
StandardError = Class.new(StandardError) { include Error }
|
8
|
+
TransitionError = Class.new(StandardError) { include Error }
|
11
9
|
end
|
data/literal_enums.gemspec
CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.metadata["homepage_uri"] = spec.homepage
|
18
18
|
spec.metadata["source_code_uri"] = "https://github.com/joeldrapper/literal_enums"
|
19
19
|
spec.metadata["changelog_uri"] = "https://github.com/joeldrapper/literal_enums"
|
20
|
+
spec.metadata["funding_uri"] = "https://github.com/sponsors/joeldrapper"
|
20
21
|
|
21
22
|
# Specify which files should be added to the gem when it is released.
|
22
23
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
@@ -28,9 +29,5 @@ Gem::Specification.new do |spec|
|
|
28
29
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
30
|
spec.require_paths = ["lib"]
|
30
31
|
|
31
|
-
spec.
|
32
|
-
spec.add_development_dependency "rake", "~> 12.3.3"
|
33
|
-
spec.add_development_dependency "minitest", "~> 5.0"
|
34
|
-
|
35
|
-
spec.add_dependency "activesupport", ">= 7.0"
|
32
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
36
33
|
end
|
metadata
CHANGED
@@ -1,71 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: literal_enums
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Drapper
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
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: 2.3.7
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 2.3.7
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 12.3.3
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 12.3.3
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: minitest
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '5.0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '5.0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: activesupport
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '7.0'
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '7.0'
|
11
|
+
date: 2022-12-14 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
69
13
|
description: A comprehensive Enum library for Ruby with literal-style syntax.
|
70
14
|
email:
|
71
15
|
- joel@drapper.me
|
@@ -73,15 +17,16 @@ executables: []
|
|
73
17
|
extensions: []
|
74
18
|
extra_rdoc_files: []
|
75
19
|
files:
|
76
|
-
- ".github/
|
20
|
+
- ".github/FUNDING.yml"
|
21
|
+
- ".github/workflows/ci.yml"
|
77
22
|
- ".gitignore"
|
78
23
|
- ".ruby-version"
|
79
24
|
- CODE_OF_CONDUCT.md
|
80
25
|
- Gemfile
|
81
|
-
- Gemfile.lock
|
82
26
|
- LICENSE.txt
|
83
27
|
- README.md
|
84
28
|
- Rakefile
|
29
|
+
- bench.rb
|
85
30
|
- bin/console
|
86
31
|
- bin/setup
|
87
32
|
- lib/enum.rb
|
@@ -96,6 +41,8 @@ metadata:
|
|
96
41
|
homepage_uri: https://github.com/joeldrapper/literal_enums
|
97
42
|
source_code_uri: https://github.com/joeldrapper/literal_enums
|
98
43
|
changelog_uri: https://github.com/joeldrapper/literal_enums
|
44
|
+
funding_uri: https://github.com/sponsors/joeldrapper
|
45
|
+
rubygems_mfa_required: 'true'
|
99
46
|
post_install_message:
|
100
47
|
rdoc_options: []
|
101
48
|
require_paths:
|
data/.github/workflows/ruby.yml
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
name: Ruby
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches: [ main ]
|
6
|
-
pull_request:
|
7
|
-
branches: [ main ]
|
8
|
-
|
9
|
-
jobs:
|
10
|
-
test:
|
11
|
-
runs-on: ubuntu-latest
|
12
|
-
strategy:
|
13
|
-
matrix:
|
14
|
-
ruby-version: ['2.7', '3.0']
|
15
|
-
|
16
|
-
steps:
|
17
|
-
- uses: actions/checkout@v2
|
18
|
-
- name: Set up Ruby
|
19
|
-
uses: ruby/setup-ruby@v1
|
20
|
-
with:
|
21
|
-
ruby-version: ${{ matrix.ruby-version }}
|
22
|
-
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
23
|
-
- name: Run tests
|
24
|
-
run: bundle exec rake
|
data/Gemfile.lock
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
literal_enums (1.1.0)
|
5
|
-
activesupport (~> 7.0.2.2)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
activesupport (7.0.2.3)
|
11
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
12
|
-
i18n (>= 1.6, < 2)
|
13
|
-
minitest (>= 5.1)
|
14
|
-
tzinfo (~> 2.0)
|
15
|
-
concurrent-ruby (1.1.9)
|
16
|
-
i18n (1.10.0)
|
17
|
-
concurrent-ruby (~> 1.0)
|
18
|
-
minitest (5.15.0)
|
19
|
-
rake (12.3.3)
|
20
|
-
tzinfo (2.0.4)
|
21
|
-
concurrent-ruby (~> 1.0)
|
22
|
-
|
23
|
-
PLATFORMS
|
24
|
-
arm64-darwin-21
|
25
|
-
x86_64-linux
|
26
|
-
|
27
|
-
DEPENDENCIES
|
28
|
-
bundler (~> 2.3.7)
|
29
|
-
literal_enums!
|
30
|
-
minitest (~> 5.0)
|
31
|
-
rake (~> 12.3.3)
|
32
|
-
|
33
|
-
BUNDLED WITH
|
34
|
-
2.3.7
|