bakkdoor-blocktalk 0.1.1 → 0.1.2
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/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}
|