Skip to content
This repository was archived by the owner on Jan 4, 2025. It is now read-only.

Commit f1ec468

Browse files
committed
commit
0 parents  commit f1ec468

File tree

4 files changed

+175
-0
lines changed

4 files changed

+175
-0
lines changed

LICENSE.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2+
Version 2, December 2004
3+
4+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
5+
6+
Everyone is permitted to copy and distribute verbatim or modified
7+
copies of this license document, and changing it is allowed as long
8+
as the name is changed.
9+
10+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12+
13+
0. You just DO WHAT THE FUCK YOU WANT TO.
14+

README.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
This is an extremely simplistic (lol, only the 4 essential files) library that adds the Optional (anti)[^A] design pattern too ALL methods globally.
2+
It even supports [logic operators (`and`, `or`, etc.)](#logic-operation)!
3+
4+
5+
## Synopsis
6+
```ruby
7+
some = Optionil[42] #=> Optionil::Some[42]
8+
none = Optionil[nil] #=> Optionil::None[] (you don't want Optionil::Some[nil], do you?…)
9+
Optionil::Some[nil] #!> NoMatchingPatternError (Do you???)
10+
none.equal? Optionil[] #=> true (the two are equivalent and all calls give the same constant)
11+
12+
Optionil::Some[] #!> wrong number of arguments (given 0, expected 1) (ArgumentError)
13+
Optionil::None[nil] #!> wrong number of arguments (given 1, expected 0) (ArgumentError)
14+
```
15+
16+
### Accessing
17+
```ruby
18+
some.value #=> some
19+
none.value #=> nil
20+
21+
some.value! #=> 42
22+
none.value! #!> NoMatchingPatternError
23+
24+
some.value { 0 } # => some
25+
some.value { raise } # => some
26+
none.value { 0 } # => 0
27+
none.value { Optionil[0] } # => Optionil::Some[0]
28+
29+
some.each {|n| -n } #=> -42
30+
some.each {|n| Optionil[-n] } #=> Optionil::Some[-42]
31+
none.each {|n| -n } #=> nil
32+
none.each {|n| raise } #=> nil
33+
```
34+
35+
### Pattern Matching
36+
```ruby
37+
Optionil === some #=> true
38+
Optionil === none #=> true
39+
Optionil::Some === some #=> true
40+
Optionil::Some === none #=> false
41+
Optionil::None === some #=> false
42+
Optionil::None === none #=> true
43+
44+
some.some? #=> true
45+
none.some? #=> false
46+
some.none? #=> false
47+
none.none? #=> true
48+
49+
some.some? Integer #=> true
50+
some.some? String #=> false
51+
none.some? Integer #=> false
52+
53+
some.some? &:even? #=> true
54+
some.some? &:odd? #=> false
55+
some.none? &:even? #=> false
56+
some.none? &:odd? #=> true
57+
```
58+
59+
### Logic Operation
60+
```ruby
61+
!some #=> false
62+
!none #=> true
63+
64+
som2 = Optionil::Some[-69]
65+
66+
some and som2 #=> som2
67+
some and none #=> none
68+
none and som2 #=> none
69+
70+
some or som2 #=> some
71+
some or none #=> some
72+
none or som2 #=> som2
73+
none or none #=> none
74+
75+
som0 = Optional::Some[false]
76+
!som0 #=> true
77+
som0 and some #=> som0
78+
# applies to `Optional::Some[nil]` as well
79+
```
80+
81+
### Method chaining
82+
I’m intentionally *not* supporting this.
83+
Please tune in to pipeine operator discussions instead, such as https://bugs.ruby-lang.org/issues/20770.
84+
85+
86+
## License
87+
Copyright © 2024 ParadoxV5
88+
89+
I made this little joke as entertainment in a day.
90+
I release it to the public domain; you can redistribute it and/or modify it under the “terms” of the
91+
[Do What The Fuck You Want To Public License, Version 2](http://www.wtfpl.net/).
92+
93+
[^A]: Cold take: the Optional pattern only exists because you can’t properlly handle `nil`s.
94+
95+
Yes, `null` is a billion-dollar mistake in traditional languages; but this is Ruby – we don’t have `null`s, we have `nil`s!
96+
A `String` can never be `nil`, only a `String?` (RBS) can!
97+
98+
Even for, say Java, `NonNull` exists
99+
([JetBrains](https://www.jetbrains.com/help/idea/annotating-source-code.html#nullability-annotations),
100+
[Android](https://developer.android.com/reference/androidx/annotation/NonNull),
101+
[Lombok](https://projectlombok.org/features/NonNull)),
102+
so nullable variables are already `Some|None` Schrödinger boxes, why bother adding `Option` as another layer of wrapper?
103+
You’d think `Optional[T]?` wouldn’t be a thing? Do you need `Optional[Optional[T]]` for that?
104+
JavaScript already has both `null` and `undefined`, questionably, yet how many *more* types of `nil`s do you still need?

lib/optionil.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
Optionil = Object
2+
class Optionil
3+
def self.[](x = nil)
4+
x
5+
end
6+
# {Some} is actually not a class. Take 1 arg
7+
def (Some = ->{ !_1.nil? }).[](x)
8+
case x
9+
in self
10+
x
11+
end
12+
end
13+
# Take 0 args
14+
# @return [nil]
15+
def (None = NilClass).[]
16+
end
17+
18+
def value(&blk)
19+
nil? ? blk&.() : self
20+
end
21+
def value!
22+
Some[self]
23+
end
24+
def each(&blk)
25+
if blk
26+
blk.(self) unless nil?
27+
else
28+
enum_for __callee__
29+
end
30+
end
31+
32+
def some?(matcher = nil, &blk)
33+
(matcher.nil? ? blk || Some : matcher) === self
34+
end
35+
def none?(...)
36+
!some?(...)
37+
end
38+
end

optionil.gemspec

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# frozen_string_literal: true
2+
3+
Gem::Specification.new do|spec|
4+
spec.name = 'optionil'
5+
spec.summary = 'Automatically apply the Optional pattern to all APIs globally, including the Ruby Corelib!'
6+
spec.version = '1.0.1'
7+
spec.author = 'ParadoxV5'
8+
spec.license = 'WTFPL'
9+
10+
github = "https://github.com/#{spec.author}/ruby-#{spec.name}"
11+
spec.metadata = {
12+
'homepage_uri' => spec.homepage = github,
13+
'changelog_uri' => File.join(github, 'commits'),
14+
'bug_tracker_uri' => File.join(github, 'discussions'),
15+
}
16+
17+
spec.files = Dir['**/*']
18+
spec.required_ruby_version = '>= 2.7'
19+
end

0 commit comments

Comments
 (0)