[~/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 endes 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