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.
Files changed (6) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +14 -0
  3. data/README.md +104 -0
  4. data/lib/optionil.rb +38 -0
  5. data/optionil.gemspec +19 -0
  6. 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: []