custom_boolean 0.1.0
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.
- data/CHANGELOG +2 -0
- data/README.markdown +46 -0
- data/Rakefile +27 -0
- data/examples/example.rb +18 -0
- data/lib/custom_boolean/version.rb +3 -0
- data/lib/custom_boolean.rb +102 -0
- data/test/test.rb +324 -0
- metadata +73 -0
data/CHANGELOG
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
Custom Boolean
|
2
|
+
==============
|
3
|
+
|
4
|
+
Cute hack to have if/else_if/else conditions with user-defined truthiness
|
5
|
+
|
6
|
+
Normal conditionals:
|
7
|
+
--------------------
|
8
|
+
if!(0) {
|
9
|
+
puts 'true'
|
10
|
+
}.
|
11
|
+
else {
|
12
|
+
puts 'false'
|
13
|
+
}
|
14
|
+
|
15
|
+
#=> 'true'
|
16
|
+
|
17
|
+
A Pythonic truthiness:
|
18
|
+
----------------------
|
19
|
+
|
20
|
+
# redefine truthiness with the `truth_test` method
|
21
|
+
CustomBoolean.truth_test = proc { |b| b && b != 0 && b != [] }
|
22
|
+
|
23
|
+
if!(0) {
|
24
|
+
puts 'true'
|
25
|
+
}.
|
26
|
+
else {
|
27
|
+
puts 'false'
|
28
|
+
}
|
29
|
+
|
30
|
+
#=> false
|
31
|
+
|
32
|
+
A full example:
|
33
|
+
------------------------
|
34
|
+
|
35
|
+
x = 5
|
36
|
+
if!(x == 4) {
|
37
|
+
puts 'x is 4'
|
38
|
+
}.
|
39
|
+
else_if(x == 5) {
|
40
|
+
puts 'x is 5'
|
41
|
+
}.
|
42
|
+
else {
|
43
|
+
puts 'x is neither 4 nor 5'
|
44
|
+
}
|
45
|
+
|
46
|
+
#=> "x is 5"
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rake/gempackagetask'
|
2
|
+
require './lib/custom_boolean/version'
|
3
|
+
|
4
|
+
$dlext = Config::CONFIG['DLEXT']
|
5
|
+
|
6
|
+
specification = Gem::Specification.new do |s|
|
7
|
+
s.name = "custom_boolean"
|
8
|
+
s.summary = "Handrolled if/else expressions with customizable truthiness"
|
9
|
+
s.version = CustomBoolean::VERSION
|
10
|
+
s.date = Time.now.strftime '%Y-%m-%d'
|
11
|
+
s.author = "John Mair (banisterfiend)"
|
12
|
+
s.email = 'jrmair@gmail.com'
|
13
|
+
s.description = s.summary
|
14
|
+
s.require_path = 'lib'
|
15
|
+
s.platform = Gem::Platform::RUBY
|
16
|
+
s.homepage = "http://banisterfiend.wordpress.com"
|
17
|
+
s.has_rdoc = false
|
18
|
+
s.files = ["Rakefile", "README.markdown", "CHANGELOG",
|
19
|
+
"lib/custom_boolean.rb", "lib/custom_boolean/version.rb"] +
|
20
|
+
FileList["examples/*.rb", "test/*.rb"].to_a
|
21
|
+
end
|
22
|
+
|
23
|
+
Rake::GemPackageTask.new(specification) do |package|
|
24
|
+
package.need_zip = false
|
25
|
+
package.need_tar = false
|
26
|
+
end
|
27
|
+
|
data/examples/example.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require './lib/custom_boolean'
|
2
|
+
|
3
|
+
x = 7
|
4
|
+
if!(x == 4) {
|
5
|
+
puts 'x is 4'
|
6
|
+
}.
|
7
|
+
else_if(x == 5) {
|
8
|
+
puts "x is #{x} (first else_if)"
|
9
|
+
}.
|
10
|
+
else_if(x == 7) {
|
11
|
+
puts "x is #{x} (second else_if)"
|
12
|
+
}.
|
13
|
+
else_if(x == 10) {
|
14
|
+
puts 'x is #{x} (third else_if)'
|
15
|
+
}.
|
16
|
+
else {
|
17
|
+
puts 'reached else'
|
18
|
+
}
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# CustomBoolean by John Mair (banisterfiend)
|
2
|
+
# MIT license
|
3
|
+
|
4
|
+
module CustomBooleanOperators
|
5
|
+
def &(other)
|
6
|
+
CustomBoolean.truthy?(self) && CustomBoolean.truthy?(other)
|
7
|
+
end
|
8
|
+
alias and &
|
9
|
+
|
10
|
+
def |(other)
|
11
|
+
CustomBoolean.truthy?(self) || CustomBoolean.truthy?(other)
|
12
|
+
end
|
13
|
+
alias or |
|
14
|
+
end
|
15
|
+
|
16
|
+
true.extend(CustomBooleanOperators)
|
17
|
+
false.extend(CustomBooleanOperators)
|
18
|
+
Object.send(:include, CustomBooleanOperators)
|
19
|
+
|
20
|
+
def negate(other)
|
21
|
+
!CustomBoolean.truthy?(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def if_(condition, &block)
|
25
|
+
truth = !!CustomBoolean.truthy?(condition)
|
26
|
+
bvalue = block.call if truth
|
27
|
+
CustomBoolean.new(truth, bvalue)
|
28
|
+
end
|
29
|
+
|
30
|
+
# bunch of aliases for if_
|
31
|
+
alias if! if_
|
32
|
+
alias _if if_
|
33
|
+
alias if? if_
|
34
|
+
|
35
|
+
class CustomBoolean
|
36
|
+
attr_accessor :truth_value, :value
|
37
|
+
|
38
|
+
class << self
|
39
|
+
attr_accessor :truth_test
|
40
|
+
|
41
|
+
def truthy?(condition)
|
42
|
+
self.truth_test.call(condition)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# exception raised when conditionals invoked after an else
|
47
|
+
InvalidConditional = Class.new(StandardError)
|
48
|
+
|
49
|
+
# various ideas of truth
|
50
|
+
RUBY_TRUTH = proc { |expr| expr }
|
51
|
+
PYTHON_TRUTH = proc { |expr| expr && !(expr.respond_to?(:empty?) && expr.empty?) && expr != 0 }
|
52
|
+
STRICT_TRUTH = proc { |expr| raise "Expression must be strictly true or false." if expr != true && expr != false; expr }
|
53
|
+
PERL_TRUTH = proc { |expr| expr && expr != 0 && expr != "" && expr != "0" }
|
54
|
+
C_TRUTH = proc { |expr| expr && expr != 0 }
|
55
|
+
|
56
|
+
# default truth test is Ruby's
|
57
|
+
self.truth_test = RUBY_TRUTH
|
58
|
+
|
59
|
+
def initialize(truth_value, block_value)
|
60
|
+
self.truth_value = truth_value
|
61
|
+
self.value = block_value
|
62
|
+
end
|
63
|
+
|
64
|
+
def +@
|
65
|
+
self.value
|
66
|
+
end
|
67
|
+
|
68
|
+
def else_if(condition, &block)
|
69
|
+
raise InvalidConditional, "No further conditionals allowed after an else." if self.truth_value == :else_reached
|
70
|
+
|
71
|
+
if self.truth_value
|
72
|
+
CustomBoolean.new(true, self.value)
|
73
|
+
else
|
74
|
+
truth = !!CustomBoolean.truthy?(condition)
|
75
|
+
bvalue = block.call if truth
|
76
|
+
CustomBoolean.new(truth, bvalue)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# a bunch of aliases for else_if
|
81
|
+
alias else_if? else_if
|
82
|
+
alias else_if! else_if
|
83
|
+
alias elsif else_if
|
84
|
+
alias elsif? else_if
|
85
|
+
alias elsif! else_if
|
86
|
+
|
87
|
+
def else(&block)
|
88
|
+
raise InvalidConditional, "No further conditionals allowed after an else." if self.truth_value == :else_reached
|
89
|
+
|
90
|
+
if self.truth_value
|
91
|
+
CustomBoolean.new(:else_reached, self.value)
|
92
|
+
else
|
93
|
+
bvalue = block.call
|
94
|
+
CustomBoolean.new(:else_reached, bvalue)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# a bunch of aliases for else
|
99
|
+
alias else? else
|
100
|
+
alias else! else
|
101
|
+
end
|
102
|
+
|
data/test/test.rb
ADDED
@@ -0,0 +1,324 @@
|
|
1
|
+
|
2
|
+
require '../lib/custom_boolean'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class CustomBooleanTest < Test::Unit::TestCase
|
6
|
+
def test_if_true
|
7
|
+
result = if?(5 == 5) { :is_equal }
|
8
|
+
|
9
|
+
assert_equal(true, result.truth_value)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_if_false
|
13
|
+
result = if?(5 == 6) { :is_equal }
|
14
|
+
|
15
|
+
assert_equal(false, result.truth_value)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_else_if_true
|
19
|
+
result = (if?(5 == 5) { :is_equal }.
|
20
|
+
else_if?(6 == 6) { :is_equal })
|
21
|
+
|
22
|
+
assert_equal(true, result.truth_value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_else_if_false
|
26
|
+
result = (if?(5 == 6) { :is_equal }.
|
27
|
+
else_if?(6 == 7) { :is_equal })
|
28
|
+
|
29
|
+
assert_equal(false, result.truth_value)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_else_true
|
33
|
+
result = (if?(5 == 5) { :is_equal }.
|
34
|
+
else? { :is_equal })
|
35
|
+
|
36
|
+
assert_equal(:is_equal, result.value)
|
37
|
+
assert_equal(:else_reached, result.truth_value)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_else_false
|
41
|
+
result = (if?(5 == 6) { :is_equal }.
|
42
|
+
else? { :is_equal })
|
43
|
+
|
44
|
+
assert_equal(:is_equal, result.value)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_else_if_else_false
|
48
|
+
result = if?(5 == 6) { :is_equal }.
|
49
|
+
else_if?(5 == 7) { :is_equal }.
|
50
|
+
else? { :is_equal }
|
51
|
+
|
52
|
+
assert_equal(:is_equal, result.value)
|
53
|
+
assert_equal(:else_reached, result.truth_value)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_else_if_true
|
57
|
+
result = if?(5 == 5) { :is_equal_if }.
|
58
|
+
else_if?(5 == 7) { :is_equal_else_if }.
|
59
|
+
else? { :is_equal }
|
60
|
+
|
61
|
+
assert_equal(:is_equal_if, result.value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_else
|
65
|
+
result = if?(5 == 0) { :is_equal }.
|
66
|
+
else? { :in_else }
|
67
|
+
|
68
|
+
assert_equal(:in_else, result.value)
|
69
|
+
|
70
|
+
result = if?(5 == 5) { :is_equal }.
|
71
|
+
else? { :in_else }
|
72
|
+
|
73
|
+
assert_equal(:else_reached, result.truth_value)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_custom_truth
|
77
|
+
CustomBoolean.truth_test = proc { |b| b && b != 0 }
|
78
|
+
|
79
|
+
result = if?(0) { :is_equal }
|
80
|
+
|
81
|
+
assert_equal(false, result.truth_value)
|
82
|
+
|
83
|
+
# reset truth test
|
84
|
+
CustomBoolean.truth_test = CustomBoolean::RUBY_TRUTH
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_custom_truth_else
|
88
|
+
CustomBoolean.truth_test = proc { |b| b && b != 0 }
|
89
|
+
|
90
|
+
result = if?(0) { :is_equal }.
|
91
|
+
else? { :in_else }
|
92
|
+
|
93
|
+
assert_equal(:in_else, result.value)
|
94
|
+
|
95
|
+
# reset truth test
|
96
|
+
CustomBoolean.truth_test = CustomBoolean::RUBY_TRUTH
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_nested_if
|
100
|
+
CustomBoolean.truth_test = proc { |b| b && b != 0 }
|
101
|
+
|
102
|
+
y = :blah
|
103
|
+
result = if?(1) {
|
104
|
+
if?(0) { }.
|
105
|
+
else_if?(1) {
|
106
|
+
y = :nested
|
107
|
+
}
|
108
|
+
|
109
|
+
}.
|
110
|
+
else_if?(1) {
|
111
|
+
y = :else_if
|
112
|
+
}
|
113
|
+
|
114
|
+
assert_equal(:nested, y)
|
115
|
+
|
116
|
+
CustomBoolean.truth_test = CustomBoolean::RUBY_TRUTH
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_values
|
120
|
+
val = :outside_if
|
121
|
+
val = if?(true) {
|
122
|
+
:in_if
|
123
|
+
}
|
124
|
+
assert_equal(:in_if, val.value)
|
125
|
+
|
126
|
+
val = if?(true) {
|
127
|
+
:in_if
|
128
|
+
}.
|
129
|
+
else_if?(true) {
|
130
|
+
:in_
|
131
|
+
}
|
132
|
+
|
133
|
+
assert_equal(:in_if, val.value)
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_values_else_if_chain
|
137
|
+
val = if?(true) {
|
138
|
+
:hello
|
139
|
+
}.
|
140
|
+
elsif?(true) {
|
141
|
+
}.
|
142
|
+
else_if?(true) {
|
143
|
+
}
|
144
|
+
|
145
|
+
assert_equal(:hello, val.value)
|
146
|
+
|
147
|
+
val = if?(false) {
|
148
|
+
}.
|
149
|
+
elsif?(true) {
|
150
|
+
:goodbye
|
151
|
+
}.
|
152
|
+
else_if?(true) {
|
153
|
+
}
|
154
|
+
|
155
|
+
assert_equal(:goodbye, val.value)
|
156
|
+
|
157
|
+
val = if?(false) {
|
158
|
+
}.
|
159
|
+
elsif?(false) {
|
160
|
+
}.
|
161
|
+
else_if?(true) {
|
162
|
+
:tiger
|
163
|
+
}
|
164
|
+
|
165
|
+
assert_equal(:tiger, val.value)
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_conditional_after_else_exception
|
169
|
+
|
170
|
+
assert_raises(CustomBoolean::InvalidConditional) do
|
171
|
+
if?(true) {}.
|
172
|
+
else? {}.
|
173
|
+
else? {}
|
174
|
+
end
|
175
|
+
|
176
|
+
assert_raises(CustomBoolean::InvalidConditional) do
|
177
|
+
if?(false) {}.
|
178
|
+
else_if?(true) {}.
|
179
|
+
else? {}.
|
180
|
+
else_if?(false) {}
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_else_if_aliases
|
185
|
+
assert_nothing_thrown do
|
186
|
+
if?(false) {}.
|
187
|
+
else_if(false) {}.
|
188
|
+
else_if!(false) {}.
|
189
|
+
else_if?(false) {}.
|
190
|
+
elsif?(true) {}.
|
191
|
+
elsif!(true) {}.
|
192
|
+
elsif(true) {}.
|
193
|
+
else {}
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_perl_truth
|
198
|
+
CustomBoolean.truth_test = CustomBoolean::PERL_TRUTH
|
199
|
+
|
200
|
+
["0", "", 0].each do |v|
|
201
|
+
val = if?(v) {
|
202
|
+
true
|
203
|
+
}.
|
204
|
+
else? {
|
205
|
+
false
|
206
|
+
}
|
207
|
+
assert_equal(false, val.value)
|
208
|
+
end
|
209
|
+
|
210
|
+
val = if?("hello") {
|
211
|
+
true
|
212
|
+
}.
|
213
|
+
else? {
|
214
|
+
false
|
215
|
+
}
|
216
|
+
assert_equal(true, val.value)
|
217
|
+
|
218
|
+
CustomBoolean.truth_test = CustomBoolean::RUBY_TRUTH
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_python_truth
|
222
|
+
CustomBoolean.truth_test = CustomBoolean::PYTHON_TRUTH
|
223
|
+
|
224
|
+
[{}, [], "", 0].each do |v|
|
225
|
+
val = if?(v) {
|
226
|
+
true
|
227
|
+
}.
|
228
|
+
else? {
|
229
|
+
false
|
230
|
+
}
|
231
|
+
assert_equal(false, val.value)
|
232
|
+
end
|
233
|
+
|
234
|
+
val = if?("hello") {
|
235
|
+
true
|
236
|
+
}.
|
237
|
+
else? {
|
238
|
+
false
|
239
|
+
}
|
240
|
+
assert_equal(true, val.value)
|
241
|
+
|
242
|
+
CustomBoolean.truth_test = CustomBoolean::RUBY_TRUTH
|
243
|
+
end
|
244
|
+
|
245
|
+
def test_strict_truth
|
246
|
+
CustomBoolean.truth_test = CustomBoolean::STRICT_TRUTH
|
247
|
+
|
248
|
+
assert_nothing_thrown do
|
249
|
+
val = if?(true) {
|
250
|
+
true
|
251
|
+
}.
|
252
|
+
else? {
|
253
|
+
false
|
254
|
+
}
|
255
|
+
|
256
|
+
assert_equal(true, val.value)
|
257
|
+
|
258
|
+
val = if?(false) {
|
259
|
+
true
|
260
|
+
}.
|
261
|
+
else? {
|
262
|
+
false
|
263
|
+
}
|
264
|
+
|
265
|
+
assert_equal(false, val.value)
|
266
|
+
end
|
267
|
+
|
268
|
+
[nil, 0, "", "hello", [], {}].each do |v|
|
269
|
+
assert_raises(RuntimeError) do
|
270
|
+
if?(v) {}
|
271
|
+
end
|
272
|
+
end
|
273
|
+
CustomBoolean.truth_test = CustomBoolean::RUBY_TRUTH
|
274
|
+
end
|
275
|
+
|
276
|
+
def test_c_truth
|
277
|
+
CustomBoolean.truth_test = CustomBoolean::C_TRUTH
|
278
|
+
|
279
|
+
[nil, false, 0].each do |v|
|
280
|
+
val = if?(v) {
|
281
|
+
true
|
282
|
+
}.
|
283
|
+
else? {
|
284
|
+
false
|
285
|
+
}
|
286
|
+
assert_equal(false, val.value)
|
287
|
+
end
|
288
|
+
|
289
|
+
[true, "hello", []].each do |v|
|
290
|
+
val = if?(v) {
|
291
|
+
true
|
292
|
+
}.
|
293
|
+
else? {
|
294
|
+
false
|
295
|
+
}
|
296
|
+
assert_equal(true, val.value)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_ruby_truth
|
301
|
+
[nil, false].each do |v|
|
302
|
+
val = if?(v) {
|
303
|
+
true
|
304
|
+
}.
|
305
|
+
else? {
|
306
|
+
false
|
307
|
+
}
|
308
|
+
assert_equal(false, val.value)
|
309
|
+
end
|
310
|
+
|
311
|
+
[true, "hello", []].each do |v|
|
312
|
+
val = if?(v) {
|
313
|
+
true
|
314
|
+
}.
|
315
|
+
else? {
|
316
|
+
false
|
317
|
+
}
|
318
|
+
assert_equal(true, val.value)
|
319
|
+
end
|
320
|
+
CustomBoolean.truth_test = CustomBoolean::RUBY_TRUTH
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: custom_boolean
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- John Mair (banisterfiend)
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-09-27 00:00:00 +13:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Handrolled if/else expressions with customizable truthiness
|
23
|
+
email: jrmair@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- Rakefile
|
32
|
+
- README.markdown
|
33
|
+
- CHANGELOG
|
34
|
+
- lib/custom_boolean.rb
|
35
|
+
- lib/custom_boolean/version.rb
|
36
|
+
- examples/example.rb
|
37
|
+
- test/test.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://banisterfiend.wordpress.com
|
40
|
+
licenses: []
|
41
|
+
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
hash: 3
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.3.7
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Handrolled if/else expressions with customizable truthiness
|
72
|
+
test_files: []
|
73
|
+
|