null 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +2 -0
- data/lib/null.rb +181 -0
- data/test/null.rb +119 -0
- metadata +89 -0
- metadata.gz.sig +0 -0
data.tar.gz.sig
ADDED
data/lib/null.rb
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
class Object
|
2
|
+
# +truthy?+ is +false+ iff we are +nil+, +false+, or an instance of NullClass.
|
3
|
+
def truthy?
|
4
|
+
true
|
5
|
+
end
|
6
|
+
|
7
|
+
# +falsy?+ is +true+ iff we are +nil+, +false+, or an instance of NullClass.
|
8
|
+
def falsy?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
# This is an alias for +falsy?+.
|
13
|
+
def !()
|
14
|
+
falsy?
|
15
|
+
end
|
16
|
+
|
17
|
+
# Are we +null+?
|
18
|
+
def null?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
# +null.to_nil?+ returns +nil+; everything else returns +self+.
|
23
|
+
def to_nil?()
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
# +obj.tap?()+ is equivalent to +obj.tap()+ unless +obj+ is an instance of
|
28
|
+
# NullClass, in which case a block must still be given, but will not be
|
29
|
+
# executed.
|
30
|
+
def tap? # yield: self
|
31
|
+
yield(self)
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Make falsy things tell you so.
|
37
|
+
module Falsiness
|
38
|
+
def truthy? # :nodoc:
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
def falsy? # :nodoc:
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def !() # :nodoc:
|
47
|
+
true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Make boolean logic work with truthiness. Note that this makes these operators
|
52
|
+
# asymmetric in that calling boolean operators on +null+ will return +null+.
|
53
|
+
|
54
|
+
class NilClass
|
55
|
+
include Falsiness
|
56
|
+
def &(obj) false end
|
57
|
+
def |(obj) !!obj end
|
58
|
+
def ^(obj) !!obj end
|
59
|
+
end
|
60
|
+
|
61
|
+
class FalseClass
|
62
|
+
include Falsiness
|
63
|
+
def &(obj) false end
|
64
|
+
def |(obj) !!obj end
|
65
|
+
def ^(obj) !!obj end
|
66
|
+
end
|
67
|
+
|
68
|
+
class TrueClass
|
69
|
+
def &(obj) !!obj end
|
70
|
+
def |(obj) true end
|
71
|
+
def ^(obj) !obj end
|
72
|
+
end
|
73
|
+
|
74
|
+
# An object including us will convert like +nil+.
|
75
|
+
module NillishConversions
|
76
|
+
# +[]+
|
77
|
+
def to_a() [] end
|
78
|
+
alias to_ary to_a
|
79
|
+
|
80
|
+
# +(0+0i)+
|
81
|
+
def to_c() to_i.to_c end
|
82
|
+
|
83
|
+
# +0.0+
|
84
|
+
def to_f() to_i.to_f end
|
85
|
+
|
86
|
+
# +0+
|
87
|
+
def to_i() 0 end
|
88
|
+
|
89
|
+
# +"null"+
|
90
|
+
def to_json() 'null' end
|
91
|
+
|
92
|
+
# +nil+
|
93
|
+
def to_nil?() nil end
|
94
|
+
|
95
|
+
# +nil+
|
96
|
+
def to_param() nil end
|
97
|
+
|
98
|
+
# +(0/1)+
|
99
|
+
def to_r() to_i.to_r end
|
100
|
+
alias rationalize to_r
|
101
|
+
|
102
|
+
# +""+
|
103
|
+
def to_s() '' end
|
104
|
+
alias to_str to_s
|
105
|
+
|
106
|
+
# +nil+
|
107
|
+
def =~(obj) nil end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Define boolean operators based on truthiness.
|
111
|
+
module TruthyBooleanOperators
|
112
|
+
def &(obj) truthy? & obj end
|
113
|
+
def |(obj) truthy? | obj end
|
114
|
+
def ^(obj) truthy? ^ obj end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Define +method_missing+ to return +self+.
|
118
|
+
module RecursiveMethodMissing
|
119
|
+
# We always return +self+.
|
120
|
+
def method_missing(meth, *args)
|
121
|
+
self
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# We implement the Null Object Pattern, i.e. most methods called on us will
|
126
|
+
# return +self+. Also, boolean logical operators for +true+, +false+, and +nil+
|
127
|
+
# have been redefined so that they depend on the +falsy?+
|
128
|
+
class NullClass
|
129
|
+
include Falsiness
|
130
|
+
include TruthyBooleanOperators
|
131
|
+
include RecursiveMethodMissing
|
132
|
+
|
133
|
+
def to_s() nil end # +""+
|
134
|
+
def nil?() true end # :nodoc:
|
135
|
+
def null?() true end # :nodoc:
|
136
|
+
def empty?() true end # :nodoc:
|
137
|
+
def to_nil?() nil end # :nodoc:
|
138
|
+
def inspect() 'null' end # +"null"+
|
139
|
+
def present?() false end # :nodoc:
|
140
|
+
|
141
|
+
# Require a block, but don't use it; then return +self+.
|
142
|
+
def tap? # :nodoc:
|
143
|
+
raise(LocalJumpError, 'no block given') unless block_given?
|
144
|
+
self
|
145
|
+
end
|
146
|
+
|
147
|
+
# Make Numeric operations involving +null+ return +null+.
|
148
|
+
def coerce(x)
|
149
|
+
[null, null]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# VoidClass instances act like NullClass instances except
|
154
|
+
class VoidClass < NullClass
|
155
|
+
include NillishConversions
|
156
|
+
|
157
|
+
# Become 0 in mathematical operations.
|
158
|
+
def coerce(x) to_i.coerce(x) end
|
159
|
+
def +(x) x end
|
160
|
+
def -(x) -x end
|
161
|
+
def *(x) x*self end
|
162
|
+
def /(x) to_i/x end
|
163
|
+
|
164
|
+
# +"void"+
|
165
|
+
def inspect
|
166
|
+
'void'
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
NULL = NullClass.new
|
171
|
+
# This is an alias for +NULL+, which is an instance of NullObject.
|
172
|
+
def null
|
173
|
+
NULL
|
174
|
+
end
|
175
|
+
|
176
|
+
VOID = VoidClass.new
|
177
|
+
# +void+ is an alias for +VOID+, which is like +null+, except that its +to_*+
|
178
|
+
# methods are like +nil+'s.
|
179
|
+
def void
|
180
|
+
VOID
|
181
|
+
end
|
data/test/null.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require_relative '../lib/null'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class NullTest < Test::Unit::TestCase
|
6
|
+
TRUTHY_TEST_OBJECTS = [1024, 4.20, 4, :twenty, Class.new, Object.new, true,
|
7
|
+
method(:method), Array.new, {}, 0, 0.0]
|
8
|
+
NULL_TEST_OBJECTS = [null, void, NullClass.new, VoidClass.new]
|
9
|
+
|
10
|
+
TRUTHY_BOOLEAN_OBJECTS = [true]
|
11
|
+
GENERATED_FALSIES = [false, nil]
|
12
|
+
RECURSOR_TEST_OBJECTS = []
|
13
|
+
|
14
|
+
[
|
15
|
+
[TruthyBooleanOperators, TRUTHY_BOOLEAN_OBJECTS],
|
16
|
+
[Falsiness, GENERATED_FALSIES],
|
17
|
+
[RecursiveMethodMissing, RECURSOR_TEST_OBJECTS]
|
18
|
+
].each do |mod, array|
|
19
|
+
array << Object.new.extend(mod)
|
20
|
+
end
|
21
|
+
|
22
|
+
ALL_FALSIES = GENERATED_FALSIES + NULL_TEST_OBJECTS
|
23
|
+
NON_NULL = TRUTHY_TEST_OBJECTS + TRUTHY_BOOLEAN_OBJECTS + GENERATED_FALSIES +
|
24
|
+
RECURSOR_TEST_OBJECTS + [false, nil]
|
25
|
+
|
26
|
+
def test_truthiness
|
27
|
+
TRUTHY_TEST_OBJECTS.each do |truthy|
|
28
|
+
msg = "#{truthy} is false"
|
29
|
+
assert truthy.truthy?, msg
|
30
|
+
assert !truthy.falsy?, msg
|
31
|
+
assert !!truthy, msg
|
32
|
+
end
|
33
|
+
|
34
|
+
ALL_FALSIES.each do |falsy|
|
35
|
+
msg = "#{falsy} is false"
|
36
|
+
assert !falsy.truthy?, msg
|
37
|
+
assert falsy.falsy?, msg
|
38
|
+
assert !falsy, msg
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_boolean_logic
|
43
|
+
TRUTHY_BOOLEAN_OBJECTS.product(ALL_FALSIES).each do |truthy, falsy|
|
44
|
+
if truthy.singleton_class.include?(TruthyBooleanOperators)
|
45
|
+
assert_equal(true, truthy ^ falsy, "#{truthy} ^ #{falsy} is true")
|
46
|
+
assert_equal(true, truthy | falsy, "#{truthy} | #{falsy} is false")
|
47
|
+
assert_equal(false, truthy & falsy, "#{truthy} & #{falsy} is false")
|
48
|
+
end
|
49
|
+
|
50
|
+
if falsy.singleton_class.include?(TruthyBooleanOperators)
|
51
|
+
assert_equal(true, falsy ^ truthy, "#{falsy} ^ #{truthy} is true")
|
52
|
+
assert_equal(true, falsy | truthy, "#{falsy} | #{truthy} is true")
|
53
|
+
assert_equal(false, falsy & truthy, "#{falsy} & #{truthy} is false")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_nil_checks
|
59
|
+
assert !nil.null?
|
60
|
+
assert nil.nil?
|
61
|
+
assert_equal nil, nil.to_nil?()
|
62
|
+
|
63
|
+
NON_NULL.each do |truthy|
|
64
|
+
assert !truthy.null?
|
65
|
+
|
66
|
+
tap_ran = false
|
67
|
+
truthy.tap? do |t|
|
68
|
+
tap_ran = true
|
69
|
+
assert_equal(truthy, t)
|
70
|
+
end
|
71
|
+
assert tap_ran
|
72
|
+
|
73
|
+
assert_equal truthy, truthy.to_nil?()
|
74
|
+
end
|
75
|
+
|
76
|
+
NULL_TEST_OBJECTS.each do |nto|
|
77
|
+
assert nto.nil?
|
78
|
+
assert nto.null?
|
79
|
+
nto.tap? { flunk }
|
80
|
+
assert_equal nil, nto.to_nil?()
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_sink
|
85
|
+
NULL_TEST_OBJECTS.each do |nto|
|
86
|
+
%w{ijfdn edfksliwsauli rdwjsnxs vdsjkg_njdc3ese objectifd kill! doom? fcs
|
87
|
+
noki i n self}.each do |func|
|
88
|
+
[[5], [1,2], [], Array.new(50, :o), {a: null}].each do |msg|
|
89
|
+
assert_equal(nto, nto.send(func, *msg))
|
90
|
+
assert_equal(nto, nto.send(func, *msg){flunk})
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
assert_equal null, (5*8+1/1.7)**null
|
96
|
+
assert_equal null, null + 5
|
97
|
+
assert_equal null, null/0
|
98
|
+
assert_equal null, (0 * null) + 5
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_voidness
|
102
|
+
assert_equal 48, (void+8)*6
|
103
|
+
assert_equal 0, void + 0
|
104
|
+
|
105
|
+
{
|
106
|
+
void.to_a => [],
|
107
|
+
void.to_ary => [],
|
108
|
+
Array.new(void) => [],
|
109
|
+
void.to_c => 0,
|
110
|
+
void.to_param => nil,
|
111
|
+
void.to_nil? => nil,
|
112
|
+
(void =~ '') => nil,
|
113
|
+
"#{void}" => '',
|
114
|
+
void.rationalize => Rational(0, 1)
|
115
|
+
}.each do |real, expected|
|
116
|
+
assert_equal(expected, real)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: 'null'
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- katmagic
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain:
|
12
|
+
- ! '-----BEGIN CERTIFICATE-----
|
13
|
+
|
14
|
+
MIIDQDCCAiigAwIBAgIBADANBgkqhkiG9w0BAQUFADBGMRgwFgYDVQQDDA90aGUu
|
15
|
+
|
16
|
+
bWFnaWNhbC5rYXQxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixk
|
17
|
+
|
18
|
+
ARkWA2NvbTAeFw0xMTA4MjEyMjMyMDFaFw0xMjA4MjAyMjMyMDFaMEYxGDAWBgNV
|
19
|
+
|
20
|
+
BAMMD3RoZS5tYWdpY2FsLmthdDEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYK
|
21
|
+
|
22
|
+
CZImiZPyLGQBGRYDY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
23
|
+
|
24
|
+
pBt20nwjs5W03djpRN6FAbpiio286NHMTk6HhmjV6GZKOi5ZUX5onTnKUg2Vc35z
|
25
|
+
|
26
|
+
/nK+aIPReyRfBgIcfSjhoXh1A1Dp+2laNgTtU/3eMupruatgORAPCSaG9Ns+HSyR
|
27
|
+
|
28
|
+
vySbz1QUrwvlvF0qkhhApNQ6dsLl2LMOV3QcluY+Y3CVccOWOSHdQcnAbPuzM9Hf
|
29
|
+
|
30
|
+
4ChI4OGL7+DwLA5OK2S5uewRAa2iLkJSN0WugnQlJqMT59GRaqTDOtnYQpiyKEBy
|
31
|
+
|
32
|
+
QjVPO4LNk7iDsJP22YBrveIzm8/YYRBTU4LTHMEMOyCszrYqD2S1Lwp2rtCJzQCl
|
33
|
+
|
34
|
+
BA0LtBKrZl5mwZm7qyj+TwIDAQABozkwNzAJBgNVHRMEAjAAMB0GA1UdDgQWBBSm
|
35
|
+
|
36
|
+
s5arhjp61kmGl6wsmLYkqerdqDALBgNVHQ8EBAMCBLAwDQYJKoZIhvcNAQEFBQAD
|
37
|
+
|
38
|
+
ggEBAA6cQNQMOPRy4yrj7Nh5Mb9qq8t/8ho/JQvjzVof9qRd+kfKrOoOhXfEO+Rm
|
39
|
+
|
40
|
+
sWcaOnBCVC4DnZuNDSLygVhCDtMnHjg/JsfO/GBF/QlNTJOO1jkoQiS6w0KARlBm
|
41
|
+
|
42
|
+
cpXaWg/oMtXJ2PaUga6WkNeXYf9Mad36P4yuGQScjs+WkUUy7DNZvTGReIcCWOR8
|
43
|
+
|
44
|
+
jteSvvCMobQKGr2DfFOU9Jiddh2FPpz/KOM2ijzwsVNUMUr7R58LoCnQZrZ/YaRW
|
45
|
+
|
46
|
+
ob6QnVgwqu5SUAKQxlFJ/aKlPMj735z8EogaZC1ZHgg3vkgGGyu57N/8BDDG0TzC
|
47
|
+
|
48
|
+
Zn3u2leVae/fJ03zYGArhuJKPgc=
|
49
|
+
|
50
|
+
-----END CERTIFICATE-----
|
51
|
+
|
52
|
+
'
|
53
|
+
date: 2012-02-01 00:00:00.000000000 Z
|
54
|
+
dependencies: []
|
55
|
+
description: null is null.
|
56
|
+
email: the.magical.kat@gmail.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- lib/null.rb
|
62
|
+
- test/null.rb
|
63
|
+
homepage: https://github.com/katmagic/null
|
64
|
+
licenses: []
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ! '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.8.10
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: null is a Null Object.
|
87
|
+
test_files:
|
88
|
+
- test/null.rb
|
89
|
+
has_rdoc:
|
metadata.gz.sig
ADDED
Binary file
|