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 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
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.2
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in enum.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rspec", "~> 3.0"
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
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Noomer
4
+ VERSION = "0.1.0"
5
+ end
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: []