noomer 0.1.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 +7 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +34 -0
- data/LICENSE +21 -0
- data/README.md +161 -0
- data/Rakefile +8 -0
- data/lib/noomer/version.rb +5 -0
- data/lib/noomer.rb +67 -0
- metadata +53 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: be396d0dfca2322d065927b71e614eca3380760ce6d27a855bdc755293e59623
|
4
|
+
data.tar.gz: 3f902f864d81f1ab71c02d853199c522304d84a73a7e1f3db1827650f88cd7ee
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f34136746ff00b71b4fa1b8fb3ab7fa4294114fd347a831e46143ead35356e62a99d773d41326e0756f18f68d4017ff07b6fbe15181fa19aa420524aca3860dd
|
7
|
+
data.tar.gz: 9ece085daf505ceaa21d9b19651419f7feaf17b45c4d26f1e22465021c4c37851d4db4af32c355519a897a4da76857a6813683665d3eff88d8b5bdc7e0e7740d
|
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.2.2
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
noomer (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.5.0)
|
10
|
+
rake (13.0.6)
|
11
|
+
rspec (3.12.0)
|
12
|
+
rspec-core (~> 3.12.0)
|
13
|
+
rspec-expectations (~> 3.12.0)
|
14
|
+
rspec-mocks (~> 3.12.0)
|
15
|
+
rspec-core (3.12.2)
|
16
|
+
rspec-support (~> 3.12.0)
|
17
|
+
rspec-expectations (3.12.3)
|
18
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
19
|
+
rspec-support (~> 3.12.0)
|
20
|
+
rspec-mocks (3.12.6)
|
21
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
22
|
+
rspec-support (~> 3.12.0)
|
23
|
+
rspec-support (3.12.1)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
x86_64-darwin-22
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
noomer!
|
30
|
+
rake (~> 13.0)
|
31
|
+
rspec (~> 3.0)
|
32
|
+
|
33
|
+
BUNDLED WITH
|
34
|
+
2.4.10
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2023 DanOlson
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
# Noomer
|
2
|
+
|
3
|
+
A basic enum implementation for Ruby.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'noomer'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install noomer
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Define a PORO to hold your variants, and include the `Noomer` module. This provides an `enum` method you can use to declare your enum variants.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
class Color
|
27
|
+
include Noomer
|
28
|
+
|
29
|
+
# Declare your variants with the `enum` method
|
30
|
+
Red = enum
|
31
|
+
Green = enum
|
32
|
+
Blue = enum
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
The `enum` method returns a subclass of the including class. In the above example, it returns a subclass of `Color`. When the result of the `enum` method is assigned to a constant, a method named after the constant is defined which returns an instance of the new subclass. In the above example, `enum` is invoked three times, each one creating a new subclass of `Color`. Three methods are defined, each one returning an instance of the corresponding subclass:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
Color::Red()
|
40
|
+
# => #<Color::Red 0x000000010a27ccb0 @value=nil>
|
41
|
+
|
42
|
+
Color::Green()
|
43
|
+
# => #<Color::Green:0x000000010d146b40 @value=nil>
|
44
|
+
|
45
|
+
Color::Blue()
|
46
|
+
# => #<Color::Blue:0x000000010d26c600 @value=nil>
|
47
|
+
```
|
48
|
+
|
49
|
+
These methods can be invoked repeatedly, and will always return the same instance.
|
50
|
+
|
51
|
+
Now we have three new classes, and three new methods:
|
52
|
+
|
53
|
+
| Class | Method |
|
54
|
+
|----------------|------------------|
|
55
|
+
| `Color::Red` | `Color::Red()` |
|
56
|
+
| `Color::Green` | `Color::Green()` |
|
57
|
+
| `Color::Blue` | `Color::Blue()` |
|
58
|
+
|
59
|
+
`Color::Red()` returns an instance of `Color::Red`, which `is_a?` `Color`.
|
60
|
+
|
61
|
+
### Associated Data
|
62
|
+
|
63
|
+
`Enum` also supports declaring variants with associated data:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
class Book
|
67
|
+
attr_reader :title
|
68
|
+
|
69
|
+
def initialize(title) = @title = title
|
70
|
+
end
|
71
|
+
|
72
|
+
class Subject
|
73
|
+
include Noomer
|
74
|
+
|
75
|
+
Math = enum(Book)
|
76
|
+
Literature = enum(Book)
|
77
|
+
Science = enum(Book)
|
78
|
+
PhyEd = enum
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
Here we have a `Subject` class that includes `Enum`, and four variants are declared; three of which require a book and one that does not. When `enum` is called with an argument that is a `Class`, the accompanying constructor method requires an argument that is an instance of that class. In the above example:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
math_book = Book.new('Beyond Algebra')
|
86
|
+
# => #<Book:0x000000010d145f88 @title="Beyond Algebra">
|
87
|
+
math = Subject::Math(math_book)
|
88
|
+
# => #<Subject::Math:0x000000010d1a8bb0 @value=#<Book:0x000000010d145f88 @title="Beyond Algebra">>
|
89
|
+
math.value == math_book
|
90
|
+
# => true
|
91
|
+
```
|
92
|
+
|
93
|
+
If you provide an argument that is not an instance of `Book`, you'll get an error:
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
Pencil = Struct.new(:number)
|
97
|
+
pencil = Pencil.new(2)
|
98
|
+
Subject::Math(pencil)
|
99
|
+
# => ArgumentError
|
100
|
+
```
|
101
|
+
|
102
|
+
Enum classes works well with `case` statements. Using the example above:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
# @param subject [Subject]
|
106
|
+
# @return [void]
|
107
|
+
def study(subject)
|
108
|
+
case subject
|
109
|
+
when Subject::Math, Subject::Literature, Subject::Science
|
110
|
+
book = subject.value
|
111
|
+
book.open_to_chapter(assignment.chapter)
|
112
|
+
read(book)
|
113
|
+
when Subject::PhyEd
|
114
|
+
stretch
|
115
|
+
jog
|
116
|
+
pushups
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
### Explicit Discriminators
|
122
|
+
|
123
|
+
Variants with can be declared with explicit discriminators. A variation on the `Color` example above:
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
class Color
|
127
|
+
include Noomer
|
128
|
+
|
129
|
+
Red = enum('#ff0000')
|
130
|
+
Green = enum('#00ff00')
|
131
|
+
Blue = enum('#0000ff')
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
When instantiated, the value of each variant is that of the provided discriminator:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
red = Color::Red()
|
139
|
+
green = Color::Green()
|
140
|
+
blue = Color::Blue()
|
141
|
+
red.value
|
142
|
+
# => "#ff0000"
|
143
|
+
green.value
|
144
|
+
# => "#00ff00"
|
145
|
+
blue.value
|
146
|
+
# => "#0000ff"
|
147
|
+
```
|
148
|
+
|
149
|
+
## Development
|
150
|
+
|
151
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
152
|
+
|
153
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
154
|
+
|
155
|
+
### TODOs
|
156
|
+
|
157
|
+
- Support Ruby versions < 3.2
|
158
|
+
|
159
|
+
## Contributing
|
160
|
+
|
161
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/DanOlson/noomer.
|
data/Rakefile
ADDED
data/lib/noomer.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "noomer/version"
|
4
|
+
|
5
|
+
module Noomer
|
6
|
+
def self.included(base) = base.extend(ClassMethods)
|
7
|
+
|
8
|
+
attr_reader :value
|
9
|
+
|
10
|
+
def initialize(value = nil)
|
11
|
+
@value = value
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
attr_reader :type_holder
|
16
|
+
|
17
|
+
def enum(type = nil)
|
18
|
+
Class.new(self) do
|
19
|
+
self.type_holder = TypeHolder.new(type) if type
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_writer :type_holder
|
26
|
+
|
27
|
+
def registry = @registry ||= Registry.new
|
28
|
+
|
29
|
+
def const_added(const)
|
30
|
+
constant = const_get(const)
|
31
|
+
return unless constant.is_a?(Class)
|
32
|
+
return unless constant < self
|
33
|
+
|
34
|
+
type = constant.type_holder&.type
|
35
|
+
defn = case type
|
36
|
+
when Class
|
37
|
+
proc do |instance|
|
38
|
+
raise ArgumentError unless instance.is_a?(type)
|
39
|
+
registry.fetch(instance) { constant.new(instance).freeze }
|
40
|
+
end
|
41
|
+
when nil
|
42
|
+
proc do
|
43
|
+
registry.fetch(constant) { constant.new.freeze }
|
44
|
+
end
|
45
|
+
else
|
46
|
+
proc do
|
47
|
+
registry.fetch(type) { constant.new(type).freeze }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
self.class.define_method(const, &defn)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Registry
|
55
|
+
def initialize = @registry = {}
|
56
|
+
|
57
|
+
def fetch(key, &blk) = @registry[key] ||= blk.call
|
58
|
+
end
|
59
|
+
private_constant :Registry
|
60
|
+
|
61
|
+
class TypeHolder
|
62
|
+
attr_reader :type
|
63
|
+
|
64
|
+
def initialize(type) = @type = type
|
65
|
+
end
|
66
|
+
private_constant :TypeHolder
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: noomer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dan Olson
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-09-18 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: An enum implementation in Ruby
|
14
|
+
email:
|
15
|
+
- olson_dan@yahoo.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".rspec"
|
21
|
+
- ".ruby-version"
|
22
|
+
- Gemfile
|
23
|
+
- Gemfile.lock
|
24
|
+
- LICENSE
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- lib/noomer.rb
|
28
|
+
- lib/noomer/version.rb
|
29
|
+
homepage: https://github.com/DanOlson/noomer
|
30
|
+
licenses: []
|
31
|
+
metadata:
|
32
|
+
homepage_uri: https://github.com/DanOlson/noomer
|
33
|
+
source_code_uri: https://github.com/DanOlson/noomer
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 3.2.0
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubygems_version: 3.4.10
|
50
|
+
signing_key:
|
51
|
+
specification_version: 4
|
52
|
+
summary: Enum implementation in Ruby
|
53
|
+
test_files: []
|