optionil 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []