[~/rubytesting/postfix]$ irb
1.9.3-p392 :001 > ARGV = ["4 3 +", "2 *"]
(irb):1: warning: already initialized constant ARGV
=> ["4 3 +", "2 *"]
1.9.3-p392 :002 > expr = ARGV.join(" ")
=> "4 3 + 2 *"
1.9.3-p392 :003 > expr
=> "4 3 + 2 *"
>> x = "2 3 4 + *".split(/\s+/) => ["2", "3", "4", "+", "*"] # un array con las diferentes partes de la cadena
La idea es ir retirando terminales del array de terminales. Si es un operando se empuja en la pila. Si es un operador se retiran tantos operandos como aridad tiene el operador y se evalúa el operdor sobre los dos operandos:
[~/rubytesting/postfix]$ pry
[1] pry(main)> z = ['4', '3', '+', '2', '*']
=> ["4", "3", "+", "2", "*"]
[2] pry(main)> stack = []
=> []
[3] pry(main)> d = z.shift
=> "4"
[4] pry(main)> stack.push d
=> ["4"]
[5] pry(main)> z
=> ["3", "+", "2", "*"]
[6] pry(main)> stack
=> ["4"]
[7] pry(main)> d = z.shift
=> "3"
[8] pry(main)> stack.push d
=> ["4", "3"]
[9] pry(main)> d = z.shift
=> "+"
[10] pry(main)> op2 = stack.pop
=> "3"
[11] pry(main)> op1 = stack.pop
=> "4"
[12] pry(main)> stack.push eval "#{op1} #{d} #{op2}"
=> [7]
[13] pry(main)>
En la sesión irb que sigue puede ver como se usa el método
eval:
>> a = 2
=> 2
>> eval "4+#{a}"
=> 6
Puede usar una sentencia case para analizar cada uno de los terminales.
La sintáxis es:
~/rubytesting$ cat -n case.rb
1 #!/usr/bin/env ruby
2 def check(z)
3 case z
4 when 0 .. 2
5 "baby"
6 when *[3,4,5,6] # La estrella '*' expande el array a una lista de argumentos 3,4,5,6
7 "little child"
8 when 7,8,9,10,11,12
9 "child"
10 when /^1\d$/
11 "youth"
12 else
13 "adult"
14 end
15 end
16
17 age = 1
18 puts check(age)
19
20 age = 5
21 puts check(age)
22
23 age = 12
24 puts check(age)
25
26 age = "14" # para que la regexp de la línea 10 funcione, deberá ser una cadena
27 puts check(age)
Este programa produce como salida:
~/rubytesting$ ruby case.rb baby little child child youth
Dentro de un case
las comparaciones se hacen con el operador ===. Así pues:
case expr0
when expr1, expr2
stmt1
when expr3, expr4
stmt2
else
stmt3
end
es equivalente a:
_tmp = expr0
if expr1 === _tmp || expr2 === _tmp
stmt1
elsif expr3 === _tmp || expr4 === _tmp
stmt2
else
stmt3
end
[13] pry(main)> (1..10) === 5 => true [14] pry(main)> (1..10) === 12 => false [15] pry(main)> /^ab*$/ === 'abb' => true [16] pry(main)> /^ab*$/ === 'acb' => false [19] pry(main)> String === "hello" => true [20] pry(main)> String === 4 => false [22] pry(main)> 1 === 1 => true [23] pry(main)> Fixnum === Fixnum => false [28] pry(main)> 4.is_a? Numeric => true [30] pry(main)> 4.is_a? Fixnum => true
El operador prefijo * sobre un array
expande el array en una lista de argumentos:
irb(main)> a = "hello" => "hello" irb(main)> a[1,3] # emepezando en la posicion 1 tomar 3 => "ell" irb(main)> a[*[1,3]] => "ell" irb(main)> def c(x,y) x+y end => nil irb(main)> c(1,2) => 3 irb(main)> c(*[1,2]) => 3
MacBookdeCasiano:programmingRuby casiano$ irb >> Math::PI => 3.14159265358979 >> x = Math.sin(Math::PI/2) => 1.0 >> x = Math.cos(Math::PI) => -1.0Para tener los nombres exportados en nuestro espacio de nombres usaremos include
include:
>> PI
NameError: uninitialized constant PI
from (irb):4
>> include Math
=> Object
>> PI
=> 3.14159265358979
>> x = sin(PI/2)
=> 1.0
Casiano Rodriguez León 2015-01-07