optionil 1.0.1
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/LICENSE.txt +14 -0
- data/README.md +104 -0
- data/lib/optionil.rb +38 -0
- data/optionil.gemspec +19 -0
- metadata +50 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 474500fa83542c00beb133857cee7e313f69b2b438f34e71fdf7a951d0817812
|
4
|
+
data.tar.gz: 1666195eab82be90d11e36b150b6dd3859238ea7f3c974a1859fe40a025ff0bd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4d6186ddf704f47760efe275ce8246e38db9ac1018e0915d8dbde855b3c90bb8504bcc0cd4678b6a9701f4eea733a7e050e8c32ffe3ad0ffbadcc40856fbc89b
|
7
|
+
data.tar.gz: 3844681c0d3f6a6d7332236d0c83cb98d6f1a0c52c0150023bb69a627d6723fa71a17300c5824f649e03afb7e65ee13bee1d9211c478f21c3b7014c366582c17
|
data/LICENSE.txt
ADDED
@@ -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
|
+
|
data/README.md
ADDED
@@ -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?
|
data/lib/optionil.rb
ADDED
@@ -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
|
data/optionil.gemspec
ADDED
@@ -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
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: optionil
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ParadoxV5
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-11-11 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- LICENSE.txt
|
20
|
+
- README.md
|
21
|
+
- lib/optionil.rb
|
22
|
+
- optionil.gemspec
|
23
|
+
homepage: https://github.com/ParadoxV5/ruby-optionil
|
24
|
+
licenses:
|
25
|
+
- WTFPL
|
26
|
+
metadata:
|
27
|
+
homepage_uri: https://github.com/ParadoxV5/ruby-optionil
|
28
|
+
changelog_uri: https://github.com/ParadoxV5/ruby-optionil/commits
|
29
|
+
bug_tracker_uri: https://github.com/ParadoxV5/ruby-optionil/discussions
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '2.7'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubygems_version: 3.5.23
|
46
|
+
signing_key:
|
47
|
+
specification_version: 4
|
48
|
+
summary: Automatically apply the Optional pattern to all APIs globally, including
|
49
|
+
the Ruby Corelib!
|
50
|
+
test_files: []
|