virtual_keywords 0.1.0 → 0.3.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/lib/parsetree/History.txt +477 -0
- data/lib/parsetree/Manifest.txt +19 -0
- data/lib/parsetree/README.txt +97 -0
- data/lib/parsetree/Rakefile +37 -0
- data/lib/parsetree/bin/parse_tree_abc +89 -0
- data/lib/parsetree/bin/parse_tree_audit +28 -0
- data/lib/parsetree/bin/parse_tree_deps +62 -0
- data/lib/parsetree/bin/parse_tree_show +63 -0
- data/lib/parsetree/demo/printer.rb +20 -0
- data/lib/parsetree/lib/gauntlet_parsetree.rb +121 -0
- data/lib/parsetree/lib/parse_tree.rb +1202 -0
- data/lib/parsetree/lib/parse_tree_extensions.rb +59 -0
- data/lib/parsetree/lib/unified_ruby.rb +421 -0
- data/lib/parsetree/test/something.rb +53 -0
- data/lib/parsetree/test/test_parse_tree.rb +2567 -0
- data/lib/parsetree/test/test_parse_tree_extensions.rb +107 -0
- data/lib/parsetree/test/test_unified_ruby.rb +57 -0
- data/lib/parsetree/validate.sh +31 -0
- data/lib/sexps/{count_to_ten_sexp.txt → count_to_ten_sexp.rb} +0 -0
- data/lib/sexps/{sexps_and.txt → sexps_and.rb} +0 -0
- data/lib/sexps/{sexps_case_when.txt → sexps_case_when.rb} +0 -0
- data/lib/sexps/{sexps_greet.txt → sexps_greet.rb} +0 -0
- data/lib/sexps/sexps_not.rb +24 -0
- data/lib/sexps/{sexps_rewritten_keywords.txt → sexps_rewritten_keywords.rb} +0 -0
- data/lib/sexps/{sexps_symbolic_and.txt → sexps_symbolic_and.rb} +0 -0
- data/lib/sexps/sexps_until.rb +60 -0
- data/lib/sexps/{sexps_while.txt → sexps_while.rb} +0 -0
- data/lib/spec/class_reflection_spec.rb +64 -0
- data/lib/spec/keyword_rewriter_spec.rb +7 -54
- data/lib/spec/not_rewriter_spec.rb +25 -0
- data/lib/spec/parser_strategy_spec.rb +23 -0
- data/lib/spec/sexp_stringifier_spec.rb +19 -0
- data/lib/spec/spec_helper.rb +61 -307
- data/lib/spec/until_rewriter_spec.rb +26 -0
- data/lib/spec/virtualizees/and_user.rb +17 -0
- data/lib/spec/virtualizees/case_when_user.rb +20 -0
- data/lib/spec/virtualizees/fizzbuzzer.rb +15 -0
- data/lib/spec/virtualizees/greeter.rb +127 -0
- data/lib/spec/virtualizees/not_user.rb +9 -0
- data/lib/spec/virtualizees/operator_user.rb +15 -0
- data/lib/spec/virtualizees/or_user.rb +17 -0
- data/lib/spec/virtualizees/parents.rb +8 -0
- data/lib/spec/virtualizees/until_user.rb +16 -0
- data/lib/spec/virtualizees/while_user.rb +16 -0
- data/lib/spec/virtualizer_spec.rb +46 -83
- data/lib/virtual_keywords/class_reflection.rb +88 -0
- data/lib/virtual_keywords/deep_copy_array.rb +12 -0
- data/lib/virtual_keywords/keyword_rewriter.rb +54 -0
- data/lib/virtual_keywords/parser_strategy.rb +40 -0
- data/lib/virtual_keywords/rewritten_keywords.rb +15 -0
- data/lib/virtual_keywords/sexp_stringifier.rb +1 -5
- data/lib/virtual_keywords/version.rb +1 -1
- data/lib/virtual_keywords/virtualizer.rb +30 -115
- data/lib/virtual_keywords.rb +31 -5
- metadata +117 -90
- data/lib/spec/class_mirrorer_spec.rb +0 -18
- data/lib/virtual_keywords/class_mirrorer.rb +0 -39
data/lib/spec/spec_helper.rb
CHANGED
@@ -1,284 +1,29 @@
|
|
1
|
-
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
require '
|
1
|
+
if RUBY_VERSION.start_with? '1.8'
|
2
|
+
require 'virtual_keywords'
|
3
|
+
else
|
4
|
+
require_relative '../virtual_keywords'
|
5
|
+
end
|
6
|
+
|
7
|
+
# Classes containing code that will be rewritten
|
8
|
+
# They act as test data for this gem.
|
9
|
+
require 'virtualizees/parents'
|
10
|
+
require 'virtualizees/fizzbuzzer'
|
11
|
+
require 'virtualizees/greeter'
|
12
|
+
require 'virtualizees/and_user'
|
13
|
+
require 'virtualizees/or_user'
|
14
|
+
require 'virtualizees/not_user'
|
15
|
+
require 'virtualizees/operator_user'
|
16
|
+
require 'virtualizees/while_user'
|
17
|
+
require 'virtualizees/until_user'
|
18
|
+
require 'virtualizees/case_when_user'
|
10
19
|
|
11
20
|
require 'rspec'
|
12
21
|
|
13
|
-
# Classes the specs should use.
|
14
|
-
module ActiveRecord
|
15
|
-
class Base
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class ApplicationController
|
20
|
-
end
|
21
|
-
|
22
|
-
class Fizzbuzzer < ActiveRecord::Base
|
23
|
-
def fizzbuzz(n)
|
24
|
-
(1..n).map { |i|
|
25
|
-
if i % 3 == 0 and i % 5 == 0
|
26
|
-
"fizzbuzz"
|
27
|
-
elsif i % 3 == 0
|
28
|
-
"fizz"
|
29
|
-
elsif i % 5 == 0
|
30
|
-
"buzz"
|
31
|
-
else
|
32
|
-
i.to_s
|
33
|
-
end
|
34
|
-
}
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
class Greeter < ApplicationController
|
39
|
-
def initialize(hello)
|
40
|
-
@hello = hello
|
41
|
-
end
|
42
|
-
|
43
|
-
# The following two methods are before/after examples. The rewriter
|
44
|
-
# should turn greet's body into greet_changed's. Running ParseTree over
|
45
|
-
# them, I got two sexps (in sexps_greet.txt), which I read to
|
46
|
-
# reverse-engineer the format. There may be edge cases (Ruby's grammar
|
47
|
-
# is much more complex than Lisp's!)
|
48
|
-
#
|
49
|
-
# spec/if_processor_spec runs a test over greet
|
50
|
-
|
51
|
-
# An example conditional: if and else
|
52
|
-
def greet_if_else
|
53
|
-
if @hello
|
54
|
-
'Hello World! (if else)'
|
55
|
-
else
|
56
|
-
# Compound expressions should be preserved
|
57
|
-
# (i.e. not evaluated too early or in the wrong context)
|
58
|
-
'Good' + 'bye (if else)'
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# If without else
|
63
|
-
def greet_if_without_else
|
64
|
-
if @hello
|
65
|
-
'Hello World! (if without else)'
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Postfix if
|
70
|
-
def greet_postfix_if
|
71
|
-
'Hello World! (postfix if)' if @hello
|
72
|
-
end
|
73
|
-
|
74
|
-
# If, then, else
|
75
|
-
def greet_if_then_else
|
76
|
-
if @hello then 'Hello World! (if then else)' else 'Goodbye (if then else)' end
|
77
|
-
end
|
78
|
-
|
79
|
-
# If, then, no else
|
80
|
-
def greet_if_then_no_else
|
81
|
-
if @hello then 'Hello World! (if then)' end
|
82
|
-
end
|
83
|
-
|
84
|
-
# Unless
|
85
|
-
def greet_unless
|
86
|
-
unless @hello
|
87
|
-
'Goodbye (unless)'
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# Unless, then else
|
92
|
-
def greet_unless_else
|
93
|
-
unless @hello
|
94
|
-
'Goodbye (unless else)'
|
95
|
-
else
|
96
|
-
'Hello World! (unless else)'
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# Postfix unless
|
101
|
-
def greet_postfix_unless
|
102
|
-
'Goodbye (postfix unless)' unless @hello
|
103
|
-
end
|
104
|
-
|
105
|
-
# What the conditional in greet should look like after processing
|
106
|
-
def greet_changed
|
107
|
-
VirtualKeywords::REWRITTEN_KEYWORDS.call_if(
|
108
|
-
self, lambda { @hello }, lambda { 'Hello World! (if else)' },
|
109
|
-
lambda { 'Good' + 'bye (if else)' })
|
110
|
-
end
|
111
|
-
|
112
|
-
# All together now
|
113
|
-
def greet_all
|
114
|
-
result = ''
|
115
|
-
# 1
|
116
|
-
if @hello
|
117
|
-
result = 'Hello'
|
118
|
-
else
|
119
|
-
result = 'Goodbye'
|
120
|
-
end
|
121
|
-
# 2
|
122
|
-
if 2 + 2 == 4
|
123
|
-
result += '\nMath is right'
|
124
|
-
end
|
125
|
-
# 3
|
126
|
-
result += '\nThis is supposed to look like English' if false
|
127
|
-
# 4
|
128
|
-
unless 2 + 9 == 10
|
129
|
-
result += '\nMath should work in unless too'
|
130
|
-
end
|
131
|
-
# 5
|
132
|
-
result += '\nWorld!' unless true
|
133
|
-
|
134
|
-
result
|
135
|
-
end
|
136
|
-
|
137
|
-
def greet_nested
|
138
|
-
if true
|
139
|
-
# This if should be processed, even though it never happens!
|
140
|
-
if 2 + 2 == 4
|
141
|
-
'Math is right'
|
142
|
-
else
|
143
|
-
'Weird'
|
144
|
-
end
|
145
|
-
else
|
146
|
-
# This if should be expanded, but NOT evaluated!
|
147
|
-
puts 'hi there' if true
|
148
|
-
'The false case'
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def greet_block
|
153
|
-
# Multiple statements in the if/else clauses
|
154
|
-
if @hello
|
155
|
-
value = 5
|
156
|
-
value += 5
|
157
|
-
|
158
|
-
value
|
159
|
-
else
|
160
|
-
thing = 9
|
161
|
-
|
162
|
-
thing
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
def count_to_ten
|
167
|
-
[1..10].each do |index|
|
168
|
-
puts index
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
class AndUser < ActiveRecord::Base
|
174
|
-
def initialize(value)
|
175
|
-
@value = value
|
176
|
-
end
|
177
|
-
|
178
|
-
def method_with_and
|
179
|
-
@value and true
|
180
|
-
end
|
181
|
-
|
182
|
-
def if_with_and
|
183
|
-
if @value and true
|
184
|
-
'Both @value and true were true (the latter is no surprise)'
|
185
|
-
else
|
186
|
-
'@value must have been false, I doubt true was false!'
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
def method_with_and_result
|
191
|
-
my_and(lambda { @value }, lambda { true })
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
class OrUser < ApplicationController
|
196
|
-
def initialize(value)
|
197
|
-
@value = value
|
198
|
-
end
|
199
|
-
|
200
|
-
def method_with_or
|
201
|
-
@value or false
|
202
|
-
end
|
203
|
-
|
204
|
-
def if_with_or
|
205
|
-
if @value or true
|
206
|
-
'Both @value or true were true (the latter is no surprise)'
|
207
|
-
else
|
208
|
-
"This can't happen!"
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
# Ruby also lets you use the && and || operators
|
214
|
-
# I think they have different precedence rules
|
215
|
-
class OperatorUser < ActiveRecord::Base
|
216
|
-
def initialize(value)
|
217
|
-
@value = value
|
218
|
-
end
|
219
|
-
|
220
|
-
def symbolic_and
|
221
|
-
@value && false
|
222
|
-
end
|
223
|
-
|
224
|
-
def symbolic_and_result
|
225
|
-
my_conditional_and(lambda { @value }, lambda { false })
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
class WhileUser < ApplicationController
|
230
|
-
def initialize(value)
|
231
|
-
@value = value
|
232
|
-
@i = 0
|
233
|
-
@counts = []
|
234
|
-
end
|
235
|
-
|
236
|
-
def while_count_to_value
|
237
|
-
while @i < @value
|
238
|
-
@counts << @i
|
239
|
-
@i += 1
|
240
|
-
end
|
241
|
-
|
242
|
-
@counts
|
243
|
-
end
|
244
|
-
|
245
|
-
def while_result
|
246
|
-
my_while(
|
247
|
-
lambda { @i < value },
|
248
|
-
lambda do
|
249
|
-
@counts << @i
|
250
|
-
@i += 1
|
251
|
-
end
|
252
|
-
)
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
class CaseWhenUser < ApplicationController
|
257
|
-
def initialize(value)
|
258
|
-
@value = value
|
259
|
-
end
|
260
|
-
|
261
|
-
def describe_value
|
262
|
-
case @value
|
263
|
-
when 1
|
264
|
-
:one
|
265
|
-
when 3..5
|
266
|
-
:three_to_five
|
267
|
-
when 7, 9
|
268
|
-
:seven_or_nine
|
269
|
-
when value * 10 < 90
|
270
|
-
:passes_multiplication_test
|
271
|
-
else
|
272
|
-
:something_else
|
273
|
-
end
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
22
|
# Helper classes and functions for rewriter specs
|
278
23
|
|
279
24
|
# Given a class and a method name, return a sexpified method.
|
280
25
|
def method_to_sexp(klass, method)
|
281
|
-
|
26
|
+
VirtualKeywords::ParserStrategy.new.translate_instance_method(klass, method)
|
282
27
|
end
|
283
28
|
|
284
29
|
# Sexpify all non-inherited instance methods of a class and return them in
|
@@ -295,68 +40,76 @@ end
|
|
295
40
|
module TrackIfs
|
296
41
|
@my_if_calls = 0 # Don't forget to reset this before each spec!
|
297
42
|
|
298
|
-
def increment_my_if_calls
|
299
|
-
@my_if_calls += 1
|
300
|
-
end
|
301
|
-
|
302
43
|
def my_if
|
303
44
|
# Dummy if that increments @my_if_calls, then runs as normal
|
304
|
-
@my_if ||= lambda
|
305
|
-
|
45
|
+
@my_if ||= lambda do |condition, then_do, else_do|
|
46
|
+
@my_if_calls += 1
|
306
47
|
if condition.call
|
307
48
|
then_do.call
|
308
49
|
else
|
309
50
|
else_do.call
|
310
51
|
end
|
311
|
-
|
52
|
+
end
|
312
53
|
end
|
313
54
|
end
|
314
55
|
|
315
56
|
module TrackAnds
|
316
57
|
@my_and_calls = 0
|
317
58
|
|
318
|
-
def increment_my_and_calls
|
319
|
-
@my_and_calls += 1
|
320
|
-
end
|
321
|
-
|
322
59
|
def my_and
|
323
60
|
# Dummy if that increments @my_if_calls, then runs as normal
|
324
|
-
@my_and ||= lambda
|
325
|
-
|
61
|
+
@my_and ||= lambda do |first, second|
|
62
|
+
@my_and_calls += 1
|
326
63
|
first.call and second.call
|
327
|
-
|
64
|
+
end
|
328
65
|
end
|
329
66
|
end
|
330
67
|
|
331
68
|
module TrackOrs
|
332
69
|
@my_or_calls = 0
|
333
70
|
|
334
|
-
def increment_my_or_calls
|
335
|
-
@my_or_calls += 1
|
336
|
-
end
|
337
|
-
|
338
71
|
def my_or
|
339
|
-
@my_or ||= lambda
|
340
|
-
|
72
|
+
@my_or ||= lambda do |first, second|
|
73
|
+
@my_or_calls += 1
|
341
74
|
first.call or second.call
|
342
|
-
|
75
|
+
end
|
343
76
|
end
|
344
77
|
end
|
345
78
|
|
346
|
-
module
|
347
|
-
@
|
79
|
+
module TrackNots
|
80
|
+
@my_not_calls = 0
|
348
81
|
|
349
|
-
def
|
350
|
-
@
|
82
|
+
def my_not
|
83
|
+
@my_not ||= lambda do |value|
|
84
|
+
@my_not_calls += 1
|
85
|
+
not value.call
|
86
|
+
end
|
351
87
|
end
|
88
|
+
end
|
89
|
+
|
90
|
+
module TrackWhiles
|
91
|
+
@my_while_calls = 0
|
352
92
|
|
353
93
|
def my_while
|
354
|
-
@my_while ||= lambda
|
355
|
-
|
94
|
+
@my_while ||= lambda do |condition, body|
|
95
|
+
@my_while_calls += 1
|
356
96
|
while condition.call
|
357
97
|
body.call
|
358
98
|
end
|
359
|
-
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
module TrackUntils
|
104
|
+
@my_until_calls = 0
|
105
|
+
|
106
|
+
def my_until
|
107
|
+
@my_until ||= lambda do |condition, body|
|
108
|
+
@my_until_calls += 1
|
109
|
+
until condition.call
|
110
|
+
body.call
|
111
|
+
end
|
112
|
+
end
|
360
113
|
end
|
361
114
|
end
|
362
115
|
|
@@ -372,10 +125,10 @@ module DoRewrite
|
|
372
125
|
|
373
126
|
def do_rewrite(method_name, object, verbose = false)
|
374
127
|
sexp = @methods[method_name]
|
375
|
-
|
376
|
-
rewriters.
|
377
|
-
|
378
|
-
|
128
|
+
# Run all rewriters on the sexp
|
129
|
+
result = rewriters.reduce(sexp) { |rewritee, rewriter|
|
130
|
+
rewriter.process rewritee
|
131
|
+
}
|
379
132
|
stringifier = VirtualKeywords::SexpStringifier.new
|
380
133
|
|
381
134
|
# Visually inspecting this result, it appears to be right
|
@@ -388,7 +141,8 @@ module DoRewrite
|
|
388
141
|
# old and new code should produce the same result,
|
389
142
|
# except that @my_*_calls is incremented
|
390
143
|
old_result = object.send method_name
|
391
|
-
VirtualKeywords::ClassReflection.install_method_on_instance(
|
144
|
+
VirtualKeywords::ClassReflection.new.install_method_on_instance(
|
145
|
+
object, code_result)
|
392
146
|
new_result = object.send method_name
|
393
147
|
|
394
148
|
new_result.should eql old_result
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'UntilRewriter' do
|
4
|
+
include TrackUntils, DoRewrite
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
@until_user = UntilUser.new 10
|
8
|
+
@methods = sexpify_instance_methods UntilUser
|
9
|
+
@until_rewriter = VirtualKeywords::UntilRewriter.new
|
10
|
+
|
11
|
+
@my_until_calls = 0
|
12
|
+
|
13
|
+
VirtualKeywords::REWRITTEN_KEYWORDS.register_lambda_for_object(
|
14
|
+
@until_user, :until, my_until)
|
15
|
+
end
|
16
|
+
|
17
|
+
def rewriters
|
18
|
+
[@until_rewriter]
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'rewrites "until" expressions' do
|
22
|
+
do_rewrite(:until_count_to_value, @until_user)
|
23
|
+
@my_until_calls.should eql 1
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class AndUser < ActiveRecord::Base
|
2
|
+
def initialize(value)
|
3
|
+
@value = value
|
4
|
+
end
|
5
|
+
|
6
|
+
def method_with_and
|
7
|
+
@value and true
|
8
|
+
end
|
9
|
+
|
10
|
+
def if_with_and
|
11
|
+
if @value and true
|
12
|
+
'Both @value and true were true (the latter is no surprise)'
|
13
|
+
else
|
14
|
+
'@value must have been false, I doubt true was false!'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class CaseWhenUser < ApplicationController
|
2
|
+
def initialize(value)
|
3
|
+
@value = value
|
4
|
+
end
|
5
|
+
|
6
|
+
def describe_value
|
7
|
+
case @value
|
8
|
+
when 1
|
9
|
+
:one
|
10
|
+
when 3..5
|
11
|
+
:three_to_five
|
12
|
+
when 7, 9
|
13
|
+
:seven_or_nine
|
14
|
+
when value * 10 < 90
|
15
|
+
:passes_multiplication_test
|
16
|
+
else
|
17
|
+
:something_else
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
class Greeter < ApplicationController
|
2
|
+
def initialize(hello)
|
3
|
+
@hello = hello
|
4
|
+
end
|
5
|
+
|
6
|
+
# The following two methods are before/after examples. The rewriter
|
7
|
+
# should turn greet's body into greet_changed's. Running ParseTree over
|
8
|
+
# them, I got two sexps (in sexps_greet.txt), which I read to
|
9
|
+
# reverse-engineer the format. There may be edge cases (Ruby's grammar
|
10
|
+
# is much more complex than Lisp's!)
|
11
|
+
#
|
12
|
+
# spec/if_processor_spec runs a test over greet
|
13
|
+
|
14
|
+
# An example conditional: if and else
|
15
|
+
def greet_if_else
|
16
|
+
if @hello
|
17
|
+
'Hello World! (if else)'
|
18
|
+
else
|
19
|
+
# Compound expressions should be preserved
|
20
|
+
# (i.e. not evaluated too early or in the wrong context)
|
21
|
+
'Good' + 'bye (if else)'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# If without else
|
26
|
+
def greet_if_without_else
|
27
|
+
if @hello
|
28
|
+
'Hello World! (if without else)'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Postfix if
|
33
|
+
def greet_postfix_if
|
34
|
+
'Hello World! (postfix if)' if @hello
|
35
|
+
end
|
36
|
+
|
37
|
+
# If, then, else
|
38
|
+
def greet_if_then_else
|
39
|
+
if @hello then 'Hello World! (if then else)' else 'Goodbye (if then else)' end
|
40
|
+
end
|
41
|
+
|
42
|
+
# If, then, no else
|
43
|
+
def greet_if_then_no_else
|
44
|
+
if @hello then 'Hello World! (if then)' end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Unless
|
48
|
+
def greet_unless
|
49
|
+
unless @hello
|
50
|
+
'Goodbye (unless)'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Unless, then else
|
55
|
+
def greet_unless_else
|
56
|
+
unless @hello
|
57
|
+
'Goodbye (unless else)'
|
58
|
+
else
|
59
|
+
'Hello World! (unless else)'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Postfix unless
|
64
|
+
def greet_postfix_unless
|
65
|
+
'Goodbye (postfix unless)' unless @hello
|
66
|
+
end
|
67
|
+
|
68
|
+
# All together now
|
69
|
+
def greet_all
|
70
|
+
result = ''
|
71
|
+
# 1
|
72
|
+
if @hello
|
73
|
+
result = 'Hello'
|
74
|
+
else
|
75
|
+
result = 'Goodbye'
|
76
|
+
end
|
77
|
+
# 2
|
78
|
+
if 2 + 2 == 4
|
79
|
+
result += '\nMath is right'
|
80
|
+
end
|
81
|
+
# 3
|
82
|
+
result += '\nThis is supposed to look like English' if false
|
83
|
+
# 4
|
84
|
+
unless 2 + 9 == 10
|
85
|
+
result += '\nMath should work in unless too'
|
86
|
+
end
|
87
|
+
# 5
|
88
|
+
result += '\nWorld!' unless true
|
89
|
+
|
90
|
+
result
|
91
|
+
end
|
92
|
+
|
93
|
+
def greet_nested
|
94
|
+
if true
|
95
|
+
# This if should be processed, even though it never happens!
|
96
|
+
if 2 + 2 == 4
|
97
|
+
'Math is right'
|
98
|
+
else
|
99
|
+
'Weird'
|
100
|
+
end
|
101
|
+
else
|
102
|
+
# This if should be expanded, but NOT evaluated!
|
103
|
+
puts 'hi there' if true
|
104
|
+
'The false case'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def greet_block
|
109
|
+
# Multiple statements in the if/else clauses
|
110
|
+
if @hello
|
111
|
+
value = 5
|
112
|
+
value += 5
|
113
|
+
|
114
|
+
value
|
115
|
+
else
|
116
|
+
thing = 9
|
117
|
+
|
118
|
+
thing
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def count_to_ten
|
123
|
+
[1..10].each do |index|
|
124
|
+
puts index
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Ruby also lets you use the && and || operators
|
2
|
+
# I think they have different precedence rules
|
3
|
+
class OperatorUser < ActiveRecord::Base
|
4
|
+
def initialize(value)
|
5
|
+
@value = value
|
6
|
+
end
|
7
|
+
|
8
|
+
def symbolic_and
|
9
|
+
@value && false
|
10
|
+
end
|
11
|
+
|
12
|
+
def symbolic_and_result
|
13
|
+
my_conditional_and(lambda { @value }, lambda { false })
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class OrUser < ApplicationController
|
2
|
+
def initialize(value)
|
3
|
+
@value = value
|
4
|
+
end
|
5
|
+
|
6
|
+
def method_with_or
|
7
|
+
@value or false
|
8
|
+
end
|
9
|
+
|
10
|
+
def if_with_or
|
11
|
+
if @value or true
|
12
|
+
'Both @value or true were true (the latter is no surprise)'
|
13
|
+
else
|
14
|
+
"This can't happen!"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|