bakkdoor-blocktalk 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +165 -0
- data/README.markdown +114 -0
- data/TODO +9 -0
- data/benchmark.bt +18 -0
- data/evaluator.rb +19 -0
- data/examples/chained_method_call.bt +15 -0
- data/examples/classes_modules.bt +68 -0
- data/examples/exceptions.bt +28 -0
- data/examples/fac.bt +23 -0
- data/examples/inline_ruby.bt +20 -0
- data/examples/linecounter.bt +8 -0
- data/examples/multiple_methodcall.bt +1 -0
- data/examples/portscan.bt +39 -0
- data/examples/require.bt +8 -0
- data/examples/ruby_methods.bt +20 -0
- data/examples/string_interpol.bt +10 -0
- data/examples/string_test.bt +13 -0
- data/examples/test.bt +45 -0
- data/examples/test2.bt +125 -0
- data/examples/test3.bt +9 -0
- data/grammar/blocktalk.rb +5030 -0
- data/grammar/blocktalk.tt +463 -0
- data/language-spec/blocktalk-example.bt +38 -0
- data/language-spec/blocktalk-lang-spec.bt +232 -0
- data/lib/blocktalk/array.bt +60 -0
- data/lib/blocktalk/string.bt +9 -0
- data/lib/blocktalk.bt +3 -0
- data/lib/core.rb +12 -0
- data/lib/kernel/array.rb +9 -0
- data/lib/kernel/class.rb +46 -0
- data/lib/kernel/codeblock.rb +57 -0
- data/lib/kernel/console.rb +40 -0
- data/lib/kernel/error.rb +11 -0
- data/lib/kernel/module.rb +18 -0
- data/lib/kernel/object.rb +66 -0
- data/lib/kernel/string.rb +5 -0
- data/lib/kernel/system.rb +5 -0
- data/parser/helpers/method_definitions.rb +31 -0
- data/parser/helpers/methodcalls.rb +56 -0
- data/parser/nodes/block_literal.rb +42 -0
- data/parser/nodes/catch.rb +22 -0
- data/parser/nodes/class_method_definition.rb +15 -0
- data/parser/nodes/comment.rb +7 -0
- data/parser/nodes/ensure.rb +7 -0
- data/parser/nodes/expression.rb +7 -0
- data/parser/nodes/identifier.rb +7 -0
- data/parser/nodes/integer_literal.rb +7 -0
- data/parser/nodes/message_receiver.rb +7 -0
- data/parser/nodes/message_with_params.rb +8 -0
- data/parser/nodes/message_without_params.rb +10 -0
- data/parser/nodes/method_definition.rb +31 -0
- data/parser/nodes/methodcall.rb +37 -0
- data/parser/nodes/multiple_methodcall.rb +28 -0
- data/parser/nodes/operator_message.rb +8 -0
- data/parser/nodes/require.rb +25 -0
- data/parser/nodes/return.rb +7 -0
- data/parser/nodes/root.rb +15 -0
- data/parser/nodes/string.rb +7 -0
- data/parser/nodes/subexpression.rb +7 -0
- data/parser/nodes/super_call.rb +12 -0
- data/parser/nodes/try.rb +7 -0
- data/parser/nodes/yield.rb +18 -0
- data/parser/nodes.rb +29 -0
- metadata +70 -3
@@ -0,0 +1,463 @@
|
|
1
|
+
grammar Blocktalk do
|
2
|
+
# starting point for the parser.
|
3
|
+
# a blocktalk programm consists of expressions & comments.
|
4
|
+
rule blocktalk_programm do
|
5
|
+
ws* exprs:(expression)* ws* <RootNode>
|
6
|
+
end
|
7
|
+
|
8
|
+
# comments start with '#' and end at the end of a line, as in ruby
|
9
|
+
rule comment do
|
10
|
+
'#' (![\n] .)* [\n]? <CommentNode>
|
11
|
+
end
|
12
|
+
|
13
|
+
# expressions start here
|
14
|
+
|
15
|
+
# an expression is one of the following:
|
16
|
+
# assignment, method_call, literal or subexpression
|
17
|
+
rule expression do
|
18
|
+
(subexpr:(method_definition / require_statement / return_statement / yield_statement
|
19
|
+
/
|
20
|
+
try_expression / catch_expression / ensure_expression
|
21
|
+
/
|
22
|
+
super_call / multiple_method_call / method_call / assignment / literal
|
23
|
+
/
|
24
|
+
subexpression / inline_ruby / comment)
|
25
|
+
('$' / (ws* newline?)))
|
26
|
+
<ExpressionNode>
|
27
|
+
end
|
28
|
+
|
29
|
+
rule method_definition do
|
30
|
+
spaces* 'def' spaces+ method_name:(message_name) ws* '=' ws* method_body:(block_literal)
|
31
|
+
<MethodDefinitionNode>
|
32
|
+
/
|
33
|
+
spaces* 'def' spaces+ 'self ' method_name:(message_name) ws* '=' ws* method_body:(block_literal)
|
34
|
+
<ClassMethodDefinitionNode>
|
35
|
+
end
|
36
|
+
|
37
|
+
rule require_statement do
|
38
|
+
'require:' spaces+ parse_file:string_literal <RequireNode>
|
39
|
+
end
|
40
|
+
|
41
|
+
rule return_statement do
|
42
|
+
'return' ':'? ' ' ret_val:(subexpression / identifier / literal) <ReturnNode>
|
43
|
+
end
|
44
|
+
|
45
|
+
rule yield_statement do
|
46
|
+
'yield' ':'? ' ' yieldval:(array_literal) <YieldNode>
|
47
|
+
end
|
48
|
+
|
49
|
+
rule try_expression do
|
50
|
+
'try' ' '? try_block:(block_literal) <TryNode>
|
51
|
+
end
|
52
|
+
|
53
|
+
rule catch_expression do
|
54
|
+
'catch' error_class:(': ' identifier ' ')? ' '? catch_block:(block_literal) <CatchNode>
|
55
|
+
end
|
56
|
+
|
57
|
+
rule ensure_expression do
|
58
|
+
'ensure' ' '? ensure_block:(block_literal) <EnsureNode>
|
59
|
+
end
|
60
|
+
|
61
|
+
# a subexpression is an expression surrounded by parenthesis for grouping.
|
62
|
+
# e.g.: (gets to_i) + 3
|
63
|
+
rule subexpression do
|
64
|
+
'(' ws* subexpr:expression ws* ')' <ExpressionNode>
|
65
|
+
end
|
66
|
+
|
67
|
+
# an assignment typically looks like this:
|
68
|
+
# identifier = value (value is either an (sub)expression, an identifier or a literal
|
69
|
+
rule assignment do
|
70
|
+
target:(identifier) ws* '=' ws* val:(expression / identifier / literal) {
|
71
|
+
def value
|
72
|
+
if val.respond_to?(:subexpr)
|
73
|
+
"#{target.value} = #{val.subexpr.value}"
|
74
|
+
else
|
75
|
+
"#{target.value} = #{val.value}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# call method of superclass (as in ruby)
|
83
|
+
rule super_call do
|
84
|
+
'super' params:(message_params)? <SuperCallNode>
|
85
|
+
end
|
86
|
+
|
87
|
+
# calling multiple methods on the same object in a row, seperated by
|
88
|
+
# semicolons (as in smalltalk)
|
89
|
+
rule multiple_method_call do
|
90
|
+
receiver:(message_receiver) ' '
|
91
|
+
messages:(message:(message_with_params / message_without_params) spaces* ';' ws*)+
|
92
|
+
final_message:(message_with_params / message_without_params) ws*
|
93
|
+
<MultipleMethodcallNode>
|
94
|
+
end
|
95
|
+
|
96
|
+
# a method_call is characterized by a receiver, a message and optional parameters:
|
97
|
+
# e.g.: receiver message
|
98
|
+
# receiver message: param_value
|
99
|
+
# receiver message: param1_value param2: param2_value ...
|
100
|
+
# additionally, a method call can be chained as in:
|
101
|
+
# obj message1 message2 message3: param1 ...
|
102
|
+
# equivalent to this ruby code:
|
103
|
+
# obj.message1().message2().message3(param1) ...
|
104
|
+
rule method_call do
|
105
|
+
receiver:(message_receiver) ' '
|
106
|
+
first_message:(operator_message / message_with_params / message_without_params)
|
107
|
+
first_passed_block_with_ws:(' '? passed_block:(block_literal_do_end / block_literal_curly_braces / '&' block_var_name:identifier))?
|
108
|
+
messages:(' ' message:(message_with_params / message_without_params)
|
109
|
+
passed_block_with_ws:(' '?
|
110
|
+
passed_block:(block_literal_do_end / block_literal_curly_braces / '&' block_var_name:identifier))?)*
|
111
|
+
<MethodcallNode>
|
112
|
+
end
|
113
|
+
|
114
|
+
# a message receiver is one of the following:
|
115
|
+
# - message_without_params, e.g.: "42" to_i to_f # -> 42.0
|
116
|
+
# - literals, e.g. 123, 123.456, [1,2,3], {:a => 1, :b => 2}, "hello world", ?C etc.
|
117
|
+
# subexpressions, e.g. (3 + 4), ("foo" to_sym) etc.
|
118
|
+
rule message_receiver do
|
119
|
+
(literal / identifier) / subexpression
|
120
|
+
end
|
121
|
+
|
122
|
+
# a message with parameters passed to it should look like this:
|
123
|
+
# receiver message: param1_value param2: param2_value param3: param3_value etc.
|
124
|
+
rule message_with_params do
|
125
|
+
message:(message_name) params:(message_params) <MessageWithParamsNode>
|
126
|
+
end
|
127
|
+
|
128
|
+
# a message without parameters passed to it looks like this:
|
129
|
+
# receiver message
|
130
|
+
rule message_without_params do
|
131
|
+
message:(message_name) !message_params <MessageWithoutParamsNode>
|
132
|
+
end
|
133
|
+
|
134
|
+
rule operator_message do
|
135
|
+
operator_name:(operator) ' ' param_value !message_params <OperatorMessageNode>
|
136
|
+
end
|
137
|
+
|
138
|
+
# message parameters look like this:
|
139
|
+
# first_param param2_name: param2_value param3_name: param3_value
|
140
|
+
# but the additional parameters beyond the first one are optional.
|
141
|
+
rule message_params do
|
142
|
+
first_param:(first_param) rest_params:(' ' parameter:param)* {
|
143
|
+
def value
|
144
|
+
[first_param.value] + rest_params.elements.map do |space_and_param|
|
145
|
+
space_and_param.parameter.value
|
146
|
+
end
|
147
|
+
end
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
# the first_param is the one that gets passed to a message in the first position.
|
152
|
+
# it's param_name is the message_name, so to speak.
|
153
|
+
rule first_param do
|
154
|
+
':' ' ' first_param_value:(param_value) {
|
155
|
+
def value
|
156
|
+
{:name => nil, :value => first_param_value.value}
|
157
|
+
end
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
161
|
+
rule param do
|
162
|
+
param_name ' ' param_value:(param_value) {
|
163
|
+
def value
|
164
|
+
#[param_name.value, param_value.value]
|
165
|
+
#param_value
|
166
|
+
{:name => param_name.value, :value => param_value.value}
|
167
|
+
end
|
168
|
+
}
|
169
|
+
end
|
170
|
+
|
171
|
+
rule param_name do
|
172
|
+
identifier ':' {
|
173
|
+
def value
|
174
|
+
identifier.value
|
175
|
+
end
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
rule param_value do
|
180
|
+
literal
|
181
|
+
/
|
182
|
+
identifier
|
183
|
+
/
|
184
|
+
subexpression
|
185
|
+
end
|
186
|
+
|
187
|
+
# literals
|
188
|
+
|
189
|
+
rule literal do
|
190
|
+
string_literal / symbol_literal / float_literal /int_literal / char_literal / array_literal / hash_literal / block_literal / regex_literal
|
191
|
+
end
|
192
|
+
|
193
|
+
rule string_literal do
|
194
|
+
'"' string_val:(string_interpolation / string_char)* '"' <StringLiteralNode>
|
195
|
+
/ "'" string_val:(string_interpolation / string_char_single_quote)* "'" <StringLiteralNode>
|
196
|
+
end
|
197
|
+
|
198
|
+
rule string_char do
|
199
|
+
!'"' char:(.) {
|
200
|
+
def value
|
201
|
+
self.char.text_value
|
202
|
+
end
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
rule string_char_single_quote do
|
207
|
+
!"'" char:(.) {
|
208
|
+
def value
|
209
|
+
self.char.text_value
|
210
|
+
end
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
214
|
+
rule string_interpolation do
|
215
|
+
'#{' spaces* expr:(expression / identifier / literal) spaces* '}' {
|
216
|
+
def value
|
217
|
+
val = "\#\{"
|
218
|
+
val += expr.respond_to?(:value) ? expr.value : expr.subexpr.value
|
219
|
+
val += "\}"
|
220
|
+
end
|
221
|
+
}
|
222
|
+
end
|
223
|
+
|
224
|
+
rule symbol_literal do
|
225
|
+
':' symbol_name:(!':' identifier) {
|
226
|
+
def value
|
227
|
+
(':' + symbol_name.text_value).to_sym
|
228
|
+
end
|
229
|
+
}
|
230
|
+
end
|
231
|
+
|
232
|
+
rule int_literal do
|
233
|
+
sign? non_zero_digit digit* <IntegerLiteralNode> / [0] <IntegerLiteralNode>
|
234
|
+
end
|
235
|
+
|
236
|
+
rule float_literal do
|
237
|
+
sign? digit+ '.' digit+
|
238
|
+
{
|
239
|
+
def value
|
240
|
+
self.text_value.to_f
|
241
|
+
end
|
242
|
+
}
|
243
|
+
end
|
244
|
+
|
245
|
+
rule char_literal do
|
246
|
+
'?' val:[a-zA-Z0-9_] {
|
247
|
+
def value
|
248
|
+
val.each_byte{|b| b}
|
249
|
+
end
|
250
|
+
}
|
251
|
+
end
|
252
|
+
|
253
|
+
rule array_literal do
|
254
|
+
'[' ws* first_item:(literal / identifier)? ws* rest_items:(',' ws* item:(literal / identifier))* ws* ']' {
|
255
|
+
def value
|
256
|
+
if self.text_value =~ /\[\s*\]/
|
257
|
+
"[]"
|
258
|
+
else
|
259
|
+
#[first_item.value] + rest_items.elements.collect{ |ws_and_items| ws_and_items.item.value }
|
260
|
+
array_str = "[#{first_item.value},"
|
261
|
+
rest_items.elements.each do |ws_and_items|
|
262
|
+
array_str += "#{ws_and_items.item.value},"
|
263
|
+
end
|
264
|
+
array_str += "]"
|
265
|
+
return array_str
|
266
|
+
end
|
267
|
+
end
|
268
|
+
}
|
269
|
+
end
|
270
|
+
|
271
|
+
rule hash_literal do
|
272
|
+
# '{' ws* '}' /
|
273
|
+
'{' ws* first_entry:(hash_entry)? ws* rest_pairs:(',' ws* pair:(hash_entry))* ws* '}' {
|
274
|
+
def value
|
275
|
+
if self.text_value =~ /\{\s*\}/
|
276
|
+
return "{}"
|
277
|
+
else
|
278
|
+
hash_str = "{"
|
279
|
+
first_pair = first_entry.value
|
280
|
+
hash_str += "#{first_pair[0]} => #{first_pair[1]},"
|
281
|
+
rest_pairs.elements.each do |ws_and_pair|
|
282
|
+
pair = ws_and_pair.pair
|
283
|
+
hash_str += "#{pair[0]} => #{pair[1]},"
|
284
|
+
end
|
285
|
+
hash_str += "}"
|
286
|
+
|
287
|
+
return hash_str
|
288
|
+
end
|
289
|
+
end
|
290
|
+
}
|
291
|
+
end
|
292
|
+
|
293
|
+
# hash entry: 'key => value'
|
294
|
+
rule hash_entry do
|
295
|
+
key:(literal / identifier) ws* '=>' ws* val:(literal / identifier) {
|
296
|
+
def value
|
297
|
+
[key.value, val.value]
|
298
|
+
end
|
299
|
+
}
|
300
|
+
end
|
301
|
+
|
302
|
+
rule block_literal do
|
303
|
+
(block_literal_do_end / block_literal_curly_braces)
|
304
|
+
end
|
305
|
+
|
306
|
+
rule block_literal_do_end do
|
307
|
+
do_keyword ws* !hash_entry ws* params:(block_params)? ws*
|
308
|
+
body:(block_body) ws*
|
309
|
+
end_keyword
|
310
|
+
<BlockLiteralNode>
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
rule block_literal_curly_braces do
|
315
|
+
'{' ws* !hash_entry ws* params:(block_params)? ws*
|
316
|
+
body:(block_body) ws*
|
317
|
+
'}'
|
318
|
+
<BlockLiteralNode>
|
319
|
+
end
|
320
|
+
|
321
|
+
rule block_body do
|
322
|
+
ws* exprs:(expression)+ ws* {
|
323
|
+
def value
|
324
|
+
body_str = ""
|
325
|
+
body_str += exprs.elements.collect{|e| e.elements[0].value}.join(";")
|
326
|
+
return body_str
|
327
|
+
end
|
328
|
+
}
|
329
|
+
end
|
330
|
+
|
331
|
+
# block parameters (e.g. |a,b,c|)
|
332
|
+
rule block_params do
|
333
|
+
'|' params:(block_param)+ '|' {
|
334
|
+
def value
|
335
|
+
# block_param_str = "|"
|
336
|
+
# block_param_str += params.elements.collect{|param| param.value}.join(",")
|
337
|
+
# block_param_str += "| "
|
338
|
+
# return block_param_str
|
339
|
+
params.elements.collect{|param| param.value}
|
340
|
+
end
|
341
|
+
}
|
342
|
+
end
|
343
|
+
|
344
|
+
rule block_param do
|
345
|
+
(ws* param_name:(identifier ':')? ' '* param_name_val:(identifier) (ws*) / (ws+ param_name_val:(identifier))) {
|
346
|
+
def value
|
347
|
+
# holds param name (if given) with param value (the identifier in the body of the block)
|
348
|
+
name_identifier_pair = {}
|
349
|
+
if param_name.text_value =~ /\S+\:/
|
350
|
+
# return the param-name as a symbol (start with a colon)
|
351
|
+
# without the final colon & space, since it's not part of the name
|
352
|
+
name_identifier_pair[:name] = ":#{param_name.text_value[0..-2]}"
|
353
|
+
end
|
354
|
+
name_identifier_pair[:identifier] = param_name_val.value
|
355
|
+
return name_identifier_pair
|
356
|
+
end
|
357
|
+
}
|
358
|
+
end
|
359
|
+
|
360
|
+
rule regex_literal do
|
361
|
+
'/' (!'/' .)* '/' {
|
362
|
+
def value
|
363
|
+
self.text_value
|
364
|
+
end
|
365
|
+
}
|
366
|
+
end
|
367
|
+
|
368
|
+
# we allow some inline ruby in blocktalk
|
369
|
+
# (mainly as a help for defining some standard library methods etc.)
|
370
|
+
# syntax: %ruby{ ... }%
|
371
|
+
rule inline_ruby do
|
372
|
+
'%ruby' ws* '{' ws* ruby_code:(comment / (!'}%' .))+ '}%' {
|
373
|
+
def value
|
374
|
+
return_val = ""
|
375
|
+
ruby_code.elements.each do |e|
|
376
|
+
unless e.respond_to?(:value) # when NOT a comment
|
377
|
+
return_val += e.text_value.gsub(/[\n\t]/, ";").gsub(/\s+/, " ")
|
378
|
+
else
|
379
|
+
# check if its actually a comment, or just a string
|
380
|
+
# interpolation - I know, it's ugly :(
|
381
|
+
if e.text_value =~ /#\{\S*\}/
|
382
|
+
# if it's just a string interpolation, also return it
|
383
|
+
return_val += e.text_value + ";"
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
return_val
|
388
|
+
end
|
389
|
+
}
|
390
|
+
end
|
391
|
+
|
392
|
+
|
393
|
+
# other rules
|
394
|
+
|
395
|
+
# identifiers are variable & possible methodnames, class & module
|
396
|
+
# names - basically anything, that you can store something in or
|
397
|
+
# assign to.
|
398
|
+
rule identifier do
|
399
|
+
('@' / '@@')? ([a-zA-Z]+ / '$' [0-9]) [a-zA-Z0-9_]* <IdentifierNode>
|
400
|
+
end
|
401
|
+
|
402
|
+
# possible names for messages / methods
|
403
|
+
rule message_name do
|
404
|
+
[a-zA-Z]+ [a-zA-Z0-9_]* ('?' / '!' / '=')? {
|
405
|
+
def value
|
406
|
+
self.text_value
|
407
|
+
end
|
408
|
+
}
|
409
|
+
end
|
410
|
+
|
411
|
+
# operator name combinations
|
412
|
+
rule operator do
|
413
|
+
('=' operator_symbol+) / (operator_symbol '=' operator_symbol*) / operator_symbol+ {
|
414
|
+
def value
|
415
|
+
self.text_value
|
416
|
+
end
|
417
|
+
}
|
418
|
+
end
|
419
|
+
|
420
|
+
rule operator_symbol do
|
421
|
+
('<=' / '>='/ '<' / '>' / '==' / '!=' / '+=' / '-=' / '&' / '.' / '+' / '-' / '/' / '*' / '|' / '=~')
|
422
|
+
end
|
423
|
+
|
424
|
+
# whitespace (with newline)
|
425
|
+
rule ws do
|
426
|
+
[\n\s\t]+
|
427
|
+
end
|
428
|
+
|
429
|
+
# whitespace (without newline)
|
430
|
+
rule spaces do
|
431
|
+
[\s\t]+
|
432
|
+
end
|
433
|
+
|
434
|
+
# newline character
|
435
|
+
rule newline do
|
436
|
+
[\n]+
|
437
|
+
end
|
438
|
+
|
439
|
+
# the 'do' keyword.
|
440
|
+
rule do_keyword do
|
441
|
+
'do' ![a-zA-Z0-9_] &ws
|
442
|
+
end
|
443
|
+
|
444
|
+
# the 'end' keyword
|
445
|
+
rule end_keyword do
|
446
|
+
'end' ![a-zA-Z0-9_]
|
447
|
+
end
|
448
|
+
|
449
|
+
# digits between 1 and 9
|
450
|
+
rule non_zero_digit do
|
451
|
+
[1-9]
|
452
|
+
end
|
453
|
+
|
454
|
+
# digits
|
455
|
+
rule digit do
|
456
|
+
[0-9]
|
457
|
+
end
|
458
|
+
|
459
|
+
# prefix sign for number literals
|
460
|
+
rule sign do
|
461
|
+
('+' / '-')
|
462
|
+
end
|
463
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
System require: "message-lang-spec"
|
2
|
+
|
3
|
+
File open: "test.txt" mode: "w" do |f|
|
4
|
+
# write three lines to 'test.txt' and close afterwards (done in File#open)
|
5
|
+
f puts: "what's up, dog?!"
|
6
|
+
f puts: "crazy shit, yo!"
|
7
|
+
f puts: "hahaha!!"
|
8
|
+
end
|
9
|
+
|
10
|
+
# print:
|
11
|
+
# 10
|
12
|
+
# 9
|
13
|
+
# 8
|
14
|
+
# ..
|
15
|
+
# 0
|
16
|
+
# to Console:
|
17
|
+
10 to: 0 do |i|
|
18
|
+
Console puts: i
|
19
|
+
end
|
20
|
+
|
21
|
+
# same again
|
22
|
+
i = 0
|
23
|
+
(i < 10) while_true: do |i|
|
24
|
+
Console puts: i
|
25
|
+
i incr # increment i
|
26
|
+
# or:
|
27
|
+
#i ++
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
numbers = [1,2,3,4,5] select: {|i| i < 3} # will return [1,2]
|
32
|
+
numbers each: do |i|
|
33
|
+
Console puts: i
|
34
|
+
end
|
35
|
+
|
36
|
+
(1 .. 100) each: {|i| Console puts: i}
|
37
|
+
|
38
|
+
squares = (1 .. 100) collect: {|i| i * i}
|