From Fedora Project Wiki

< FWN‎ | Beats

No edit summary
No edit summary
Line 5: Line 5:
LATAM Fedora is a regular column of Spanish language contributions around open source software.  It is our first expansion into incorporating foreign language content into FWN.   
LATAM Fedora is a regular column of Spanish language contributions around open source software.  It is our first expansion into incorporating foreign language content into FWN.   


This week's contribution is from [[User:gomix|Guillermo Gómez]], a primer on Ruby.  Enjoy!
This week's contribution is from [[User:gomix|Guillermo Gómez]], a primer on Ruby PING.  Enjoy!


=== Ruby Capítulo 1: El primer contacto ===
=== Ruby Ping ===


"Yo quería un lenguaje de programación más poderoso que Perl y más orientado a objetos que Python. Entonces me acordé de mi viejo sueño y decidí diseñar mi propio lenguaje. Al principio estuve jugando con él en el trabajo. Gradualmente creció lo suficiente como para remplazar a Perl. Lo llamé Ruby en honor a esa piedra preciosa roja y lo liberé al público en 1995."
En paralelo con el tutorial de Ruby, que pronto verá su segundo capítulo, vamos en paralelo para publicaciones más frecuentes como FWN a escribir acerca del uso del lenguaje en otras tareas específicas, hoy nos ocupa algunas formas de hacer "ping" con Ruby.


Yukihiro Matsumoto, a.k.a. ``Matz''
==== Ping: librería estandar ====
Japan, October 2000


==== Aprovechando el espacio ====


Para comenzar en Fedora con Ruby vamos instalar lo mínimo necesario y sin perder mucho espacio dando vueltas con teoría y opiniones, directo al grano. Abra una sesión de emulación de terminal preferida y siga las siguientes instrucciones para instalar. En la medida que desarrollemos esta columna dedicada a Ruby, entonces iremos descubriendo el poder y flexibilidad de Ruby.
Ping.pingecho utiliza TCP echo no ICMP echo para determinar si un máquina remota esta "viva". En realidad puede utilizar "otros" puertos, no necesariamente echo tcp/7.


<code>
<code>
$ su -
1 irb(main):013:0> require 'ping'
<contraseña de root>
2 => true
# yum install ruby ruby-rdoc ruby-ri
3 irb(main):012:0> Ping.pingecho('gomix.fedora-ve.org', 10)
4 => true
5 irb(main):016:0> Ping.pingecho('gomix.fedora-ve.org', 10, 'http' )
6 => true
</code>
</code>


Para el editor, hay muchas opciones, mi editor de preferencia es Vim , pero puede usar el de su preferencia, intente usar alguno que pueda resaltar sintaxis Ruby como mínimo. Puede escoger desde entornos tan complejos y completos como Eclipse, hasta editores de escritorio GUI como Gedit, o simples en consola como nano o complejos y sofisticados como Vim y Emacs.
NOTA: si existe un paquete de rechazo ICMP al puerto especificado, se considera que la máquina está viva, es decir, "respondió con ICMP", así que no asuma que el puerto está abierto por el hecho de que Ping.pingecho le devuelva true.


==== Los "Hola mundo" ====
==== net-ping ====
 
La primera forma interactiva simple de ejecutar comandos Ruby es simplemente usar el intérprete, simplemente ejecute el intérprete, ingrese los comandos y termine presionando Ctrl-D para indicarle al intérprete que la entrada de comandos ha finalizado:
 
<code>
$ ruby
puts "Hola Mundo"
<Ctrl-D>
Hola Mundo
</code>
 
La segunda forma interactiva es con irb. irb es el acrónimo para Interactive Ruby. irb es un shell Ruby, es decir, es un espacio donde puede evaluar su código al instante. En próximas ediciones iremos desarrollando más el tema de irb, por ahora simplemente invoque a irb e intente:
 
<code>
$ irb
irb(main):001:0> puts "Hola Mundo"
Hola Mundo
=> nil
irb(main):002:0>exit
$
</code>
 
Si lo que quiere es crear un programa Ruby que nos imprima "Hola Mundo" en la salida del monitor, lance su editor e incluya el siguiente código fuente en un archivo denominado holamundo.rb., guarde y salga de su editor.
 
===== holamundo.rb =====
 
1 puts "Hola Mundo"
 
Para ejecutar simplemente pásale al intérprete Ruby el archivo como argumento.
 
<code>
[gomix@fricky capitulo_1]$ ruby holamundo.rb
Hola Mundo
</code>
 
También puede usar el método "shebang" y convertir el archivo fuente Ruby en ejecutable del sistema, edite su holamundo.rb para que luzca como se muestra en el listado a continuación.
 
===== holamundo.rb =====
 
<code>
1 #!/usr/bin/ruby
2
3 puts "Hola Mundo"
</code>


<code>
<code>
[gomix@fricky capitulo_1]$ chmod +x holamundo.rb
# gem install net-ping
[gomix@fricky capitulo_1]$ ./holamundo.rb
Hola Mundo
</code>
</code>


Existe la forma de pasarle directamente código Ruby al intérprete sin apoyo de archivos o programas adicionales y sin entrar en modo interactivo.
Fase común genérica para los siguientes ejemplos.


<code>
<code>
$ ruby -e 'puts "Hola Mundo"'
1 irb(main):001:0> require 'rubygems'
Hola Mundo
2 => true
3 irb(main):005:0> require 'net/ping'
4 => true
</code>
</code>


==== Ruby es un lenguaje de programación orientado a objetos ====
Ping UDP y TCP.
 
Todo lo que usted manipula en Ruby es un objeto, y los resultados de dichas manipulaciones a su vez, también son objetos. Cuando usted escribe código orientado a objetos normalmente está modelando conceptos del mundo real en su código. Típicamente durante este proceso de modelado usted descubrirá categorías de cosas que necesitan ser representadas en código. En un reproductor de música el concepto de "canción" puede ser una de esas categorías. En Ruby usted define una clase para representar cada una de esas entidades. Una clase es una combinación de estado, por ejemplo el nombre de la canción, y métodos que usan dicho estado, por ejemplo para reproducir la canción.
 
Una vez que tiene dichas clases usted creará instancias de dicha clase. Para el reproductor de música que contiene la clase Cancion usted terminará teniendo instancias separadas independientes para canciones populares como "Todo o nada", "Canción para un amigo", "Amanecer llanero", y por el estilo. La palabra objeto e instancia son intercambiables. En Ruby para crear dichas instancias u objetos, se debe llamar a un método constructor de la clase, el método constructor estandar se llama new.


<code>
<code>
1 cancion1 = Cancion.new("Amanecer llanero")
1 irb(main):011:0> host = "gomix.fedora-ve.org"
2 cancion2 = Cancion.new("Todo o nada")
2 => "gomix.fedora-ve.org"
3 irb(main):012:0> u = Net::Ping::TCP.new(host)
4 => #<Net::Ping::TCP:0x7fb1cf3e16f0 @duration=nil, @timeout=5, @warning=nil, @exception=nil, @host="gomix.fedora-ve.org", @port=7>
5 irb(main):013:0> u.port = 80
6 => 80
7 irb(main):014:0> p u.ping?
8 true
9 => nil
10 >>  u = Net::Ping::UDP.new(host)
11 => #<Net::Ping::UDP:0xb74b6a38 @duration=nil, @warning=nil, @data="ping", @timeout=5, @exception=nil, @bind_port=nil, @host="www.ruby-lang.org", @port=7, @bind_host=nil>
12 >> p u.ping?
13 false
</code>
</code>


Estas instancias son derivadas de la misma clase pero tienen características únicas. Primero, cada objeto tiene un object_id único. Segundo, usted puede definir variables de instancia, variables con valor que son únicos para cada instancia. Estas variables de instancia mantienen el estado del objeto. Igualmente puede definir métodos de instancia para acceder y/o alterar el estado del objeto, es decir, acceder y/o alterar las variables de instancia. Rápidamente definamos nuestra clase Cancion. Ruby se puede leer fácilmente.
NOTA: en este caso el rechazo tanto a nivel TCP como ICMP no es indicativo de que la "máquina" esté viva, es decir, aquí el PING es específico al servicio/puerto que se está probando, no a la máquina. Note en el último caso el ping-tcp al puerto 80 donde si hay respuesta porque hay un servidor web funcionando allí.


<code>
Ping ICMP con net-ping.
1 class Cancion
2  def titulo
3    @titulo
4  end
5
6  def titulo=(titulo_de_la_cancion)
7    @titulo = titulo_de_la_cancion.to_s
8  end
9 end
</code>
 
Claramente podemos ver y leer que hemos definido la clase de nombre Cancion con dos métodos de instancia, titulo y titulo=. La variable de instancia se representa en @titulo , con la notación de nombre de variable en minúscula precedida del símbolo @ .
 
Note la indentación que hemos implementado para representar la estructura, dos espacios es cómun entre los Rubyeros (me gusta llamarlos así).
 
Es evidente que la plabra clave class establece el inicio de un bloque que se cierra con end para definir una clase con nombre, en este ejemplo Cancion. Dentro de dicha estructura también podemos identificar claramente la palabra clave def que igualmente define bloques que se cierran también con la palabra clave end. def define dos métodos de instancia en este ejemplo. Hablaremos más de def de forma recurrente en muchas ediciones de esta columna.
 
Podemos probar nuestra clase en irb fácilmente, por ahora tipee con cuidado para no equivocarse, luego le ofreceré más técnicas irb.


<code>
<code>
1 $ irb
1 irb(main):011:0> host = "gomix.fedora-ve.org"
2 >> class Cancion
2 => "gomix.fedora-ve.org"
3 >> def titulo
3 irb(main):015:0> u = Net::Ping::ICMP.new(host)
4 >> @titulo
4 => #<Net::Ping::ICMP:0x7fb1d1358088 @pid=8696, @data="\000\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\e\034\035\036\037 !\"\#$%&'()*+,-./012345678", @duration=nil, @data_size=56, @timeout=5, @bind_port=0, @warning=nil, @exception=nil, @seq=0, @host="gomix.fedora-ve.org", @bind_host=nil, @port=nil>
5 >> end
5 irb(main):016:0> p u.ping?
6 >> def titulo=(titulo_de_la_cancion)
6 true
7 >> @titulo = titulo_de_la_cancion.to_s
8 >> end
9 >> end
10 => nil
11 >> cancion1 = Cancion.new
12 => #<Cancion:0xb76e25c8>
13 >> cancion1.titulo="Alma llanera"
14 => "Alma llanera"  
15 >> cancion1.titulo
16 => "Alma llanera"
</code>
 
==== Pero no necesito clases ====
 
También se puede usar Ruby del modo procedimental, funcional, sin necesidad de crear (explícitamente) clases y objetos.
 
<code>
1 $ irb
2 >> 2 + 2
3 => 4
</code>
 
Pero igual note que estamos trabajando con objetos de alguna clase, en nuestro ejemplo Fixnum.
 
<code>
1 >> 2.class
2 => Fixnum
</code>
 
Puede definir métodos y llamarlos:
 
<code>
1 >> def saludo
2 >> puts "Hola Mundo"
3 >> end
4 => nil
5 >> saludo
6 Hola Mundo
7 => nil
7 => nil
</code>
</code>


==== Clases base ====
Tenga presente que:
 
Ya que "todo" son objetos de alguna clase, más vale que comencemos por aprender las más fundamentales del lenguaje, Fixnum, Bignum, Float, String, Array y Hash.
 
Números... Fixnum, Bignum, Float
 
Enteros, dejemos que nuestro código Ruby hable.


<code>
<code>
1 >> num = 8
1 >> u = Net::Ping:ICMP.new(host)
2 => 8
2 RuntimeError: requires root privileges
3 >> 7.times do
3     from /usr/lib/ruby/gems/1.8/gems/net-ping-1.4.0/lib/net/ping/icmp.rb:25:in `initialize'
4 ?> print num.class, " ", num, "\n"
4    from (irb):5:in `new'
5 >> num *= num
5     from (irb):5
6 >> end
7 Fixnum 8
8 Fixnum 64
9 Fixnum 4096
10 Fixnum 16777216
11 Bignum 281474976710656
12 Bignum 79228162514264337593543950336
13 Bignum 6277101735386680763835789423207666416102355444464034512896
14 => 7
15 >> num = 3.14
16 => 3.14
17 >> 8.times do
18 ?> print num.class, " ", num, "\n"
19 >> num *= num
20 >> end
21 Float 3.14
22 Float 9.8596
23 Float 97.21171216
24 Float 9450.11698107869
25 Float 89304710.9560719
26 Float 7.97533139894754e+15
27 Float 6.36059109230385e+31
28 Float 4.04571190434951e+63
</code>
 
===== Cadenas de caracteres, String =====
 
<code>
1 >> "Hola Mundo".class
2 => String
3 >> "987".class
4 => String
<
</code>
 
===== Arreglos, Array =====
 
<code>
1 >> arreglo = ["a",1,"b",2]
2 => ["a", 1, "b", 2]
3 >> arreglo.class
4 => Array
5 >> arreglo[0]
6 => "a"
7 >> arreglo[1]
8 => 1
<
</code>
 
===== Arreglos indexados arbitrariamente, Hash =====
 
<code>
1 >> hash = { "color" => "rojo", "temperatura" => 75, 1 => "hoy"}
2 => {1=>"hoy", "temperatura"=>75, "color"=>"rojo"}
3 >> hash.class
4 => Hash
5 >> hash["color"]
6 => "rojo"
7 >> hash["temperatura"]
8 => 75
9 >> hash[1]
10 => "hoy"
</code>
 
===== Recapitulación rápida, los objetos y sus métodos, ¿documentación? =====
 
Teniendo cualquier objeto de cualquier clase a la mano, para acceder a su métodos podemos usar la sintaxis objeto.método. En el ejemplo abajo llamamos al popular método to_s que nos ofrece una representación en String del objeto en cuestión.
 
<code>
1 >> hash.to_s
2 => "1hoytemperatura75colorrojo"
3 >> arreglo.to_s
4 => "a1b2"
5 >> 8.to_s
6 => "8"
</code>
 
Ahora bien, ¿dónde consigo la documentación de dichas clases y métodos? Demos la bienvenida a ri para ayuda local en línea de comandos, y por supuesto, en la web a http://www.ruby-doc.org/ . Francamente, en nuestros días la primera fuente de información es la Web, y en segundo lugar, nuestros recursos locales como ri. Entonces, y para efectos de esta serie de artículos, vamos a usar inicialmente Ruby 1.8.7.
 
* http://www.ruby-doc.org/core-1.8.7/
* http://www.ruby-doc.org/stdlib-1.8.7/
 
Ejemplo de salida ri (extracto).
 
<code>
$ ri Fixnum
------------------------------------------------ Class: Fixnum < Integer
    A +Fixnum+ holds +Integer+ values that can be represented in a
    native machine word (minus 1 bit). If any operation on a +Fixnum+
    exceeds this range, the value is automatically converted to a
    +Bignum+.
...
Instance methods:
-----------------
    %, &, *, **, +, -, -@, /, <, <<, <=, <=>, ==, >, >=, >>, [], ^,
    __serialize__, abs, dclone, div, divmod, html_safe?, id2name,
    modulo, power!, quo, rdiv, rpower, size, to_f, to_s, to_sym, xchr,
    zero?, |, ~
</code>
 
==== Ruby es dinámico ¿ 2 + 2 = 4 ? ====
 
Uno de los aspectos notables de Ruby es su dinamismo, una forma de visualizarlo es hacer uso del hecho que todas las clases están "abiertas" y es posible redefinir sus métodos, por ejemplo:
 
===== fixnum_mod.rb =====
 
<code>
#!/usr/bin/ruby
#
class Fixnum
  def +(otro)
     100
  end
end
 
puts (2+2).to_s
 
Y ahora ejecutamos nuestro programa:
 
$ ruby fixnum_mod.rb
100
</code>
 
Horror, hemos echado a perder el método sumar de Fixnum, por ello algunos consideran peligroso los lenguajes dinámicos, sin embargo existe la forma de protegernos de este tipo de modificaciones en el caso de que ello no sea deseable. El ejemplo sin embargo demuestra que toda clase puede redefinir cualquiera de sus métodos en tiempo de ejecución, en cualquier momento, este dinamismo le da gran poder a Ruby, piense en una clase u objeto que evoluciona y gana funcionalidad en el tiempo de existencia del programa, o que la pierde, su funcionalidad puede mutar, cambiar. No puede devolver el cambio, no sin que le enseñe cómo preservar el código sobrescrito, probablemente en la próxima edición de esta columna.
Estructuras de control¶
 
Por supuesto que ningún lenguaje está completo si no tiene la capacidad de ejecución de código condicionada, es decir, evaluar alguna condición o estado, y proceder en consecuencia de distintas maneras. Abajo le resumimos las estructuras más comunes.
 
<code>
1 # Evaluacion máxima 20
2 if evaluacion < 10
3  puts "Usted reprobó la asignatura."
4 elsif evaluacion > 16
5  puts "Usted obtuvo un grado sobresaliente."
6 else
7  puts "Usted aprobó la materia."
8 end
 
1 unless unaCancion.duracion > 180 then
2  costo = .25
3 else
4  costo = .35
5 end
 
1 case forma
2  when Cuadrado, Rectangulo
3    # ...
4  when Circulo
5    # ...
6  when Triangulo
7    # ...
8  else
9    # ...
10 end
</code>
 
==== Lazos e iteradores ====
 
Un iterador en Ruby es simplemente un método que puede invocar un bloque de código. Note como se pasa la referencia del bloque de código y este a su vez ejecutado por medio de la llamada yield.
Ruby Salida
 
<code>
1 def tres_veces
2  yield
3  yield
4  yield
5 end
6  
6  
7 tres_veces { puts "Hola Mundo" }
Hola Mundo
Hola Mundo
Hola Mundo
</code>
Algunos iteradores son muy comunes en muchas clases Ruby para representar colecciones, por ejemplo each en un arreglo simple. Note que each además de iterar por cada uno de los elementos del arreglo, pasa un argumento al bloque de código ha ser ejecutado, en este caso pasa el contenido correspondiente en el arreglo.
<code>
Ruby Salida
1 [1,3,5,7,9].each { |i| puts i }
1
3
5
7
9
</code>
</code>


Lazos con while y until.
Ping "external", esta opción utiliza la utilidad "ping" de su sistema operativo.


<code>
<code>
Ruby Salida
1 >> host="200.44.32.12"
 
2 => "200.44.32.12"
1 peso = 5
3 >> u = Net::Ping::External.new(host)
2 while peso < 100
4 => #<Net::Ping::External:0xb73fbd50 @duration=nil, @warning=nil, @timeout=5, @exception=nil, @host="200.44.32.12", @port=7>
3   peso = peso * 2
5 >> p u.ping?
4   puts peso
6 true
5 end
 
 
10
20
40
80
160
</code>
</code>


<code>
Por cierto, net-ping no está empaquetado en Fedora, ello es una buena oportunidad para que comiences tu primer proyecto de empaquetamiento de rubygems en Fedora, contáctame y suscribe en el grupo de desarrollo latinoamericano RPMDev .
Ruby Salida
 
1 peso = 5
2 until peso > 100
3  peso = peso * 2
4  puts peso
5 end
 
 
10
20
40
80
160
</code>
 
Lazo con for y loop:
 
<code>
Ruby Salida
 
1 for i in 1..8 do
2    puts i
3 end
 
 
1
2
3
4
5
6
7
8
 
Ruby Salida
 
1 num = 0
2 loop do
3  puts "En el lazo por #{num} vez"
4  num += 1
5  break unless num < 5
6 end
 
 
En el lazo por 0 vez
En el lazo por 1 vez
En el lazo por 2 vez
En el lazo por 3 vez
En el lazo por 4 vez
</code>
 
De salida, por supuesto hay mucho más acerca de Ruby y su mundo, usted podrá hacer desde pequeños guiones (scripts) hasta poderosas aplicaciones de escritorio o su último desarrollo web, no se detenga aquí y espero que nos leamos en la próxima entrega de esta publicación, envíeme sus comentarios a <gomix@fedoraproject.org>.
 
Nuestro trabajo es resolver problemas concretos, no alimentar al compilador con cucharilla, nos gustan los lenguajes dinámicos que se adapten a nosotros sin reglas rígidas que seguir.


Gomix_
Gomix_

Revision as of 12:34, 17 March 2011

LATAM Fedora!

LATAM Fedora is a regular column of Spanish language contributions around open source software. It is our first expansion into incorporating foreign language content into FWN.

This week's contribution is from Guillermo Gómez, a primer on Ruby PING. Enjoy!

Ruby Ping

En paralelo con el tutorial de Ruby, que pronto verá su segundo capítulo, vamos en paralelo para publicaciones más frecuentes como FWN a escribir acerca del uso del lenguaje en otras tareas específicas, hoy nos ocupa algunas formas de hacer "ping" con Ruby.

Ping: librería estandar

Ping.pingecho utiliza TCP echo no ICMP echo para determinar si un máquina remota esta "viva". En realidad puede utilizar "otros" puertos, no necesariamente echo tcp/7.

1 irb(main):013:0> require 'ping' 2 => true 3 irb(main):012:0> Ping.pingecho('gomix.fedora-ve.org', 10) 4 => true 5 irb(main):016:0> Ping.pingecho('gomix.fedora-ve.org', 10, 'http' ) 6 => true

NOTA: si existe un paquete de rechazo ICMP al puerto especificado, se considera que la máquina está viva, es decir, "respondió con ICMP", así que no asuma que el puerto está abierto por el hecho de que Ping.pingecho le devuelva true.

net-ping

  1. gem install net-ping

Fase común genérica para los siguientes ejemplos.

1 irb(main):001:0> require 'rubygems' 2 => true 3 irb(main):005:0> require 'net/ping' 4 => true

Ping UDP y TCP.

1 irb(main):011:0> host = "gomix.fedora-ve.org" 
2 => "gomix.fedora-ve.org" 
3 irb(main):012:0> u = Net::Ping::TCP.new(host)
4 => #<Net::Ping::TCP:0x7fb1cf3e16f0 @duration=nil, @timeout=5, @warning=nil, @exception=nil, @host="gomix.fedora-ve.org", @port=7>
5 irb(main):013:0> u.port = 80
6 => 80
7 irb(main):014:0> p u.ping?
8 true
9 => nil

10 >> u = Net::Ping::UDP.new(host) 11 => #<Net::Ping::UDP:0xb74b6a38 @duration=nil, @warning=nil, @data="ping", @timeout=5, @exception=nil, @bind_port=nil, @host="www.ruby-lang.org", @port=7, @bind_host=nil> 12 >> p u.ping? 13 false

NOTA: en este caso el rechazo tanto a nivel TCP como ICMP no es indicativo de que la "máquina" esté viva, es decir, aquí el PING es específico al servicio/puerto que se está probando, no a la máquina. Note en el último caso el ping-tcp al puerto 80 donde si hay respuesta porque hay un servidor web funcionando allí.

Ping ICMP con net-ping.

1 irb(main):011:0> host = "gomix.fedora-ve.org" 2 => "gomix.fedora-ve.org" 3 irb(main):015:0> u = Net::Ping::ICMP.new(host) 4 => #<Net::Ping::ICMP:0x7fb1d1358088 @pid=8696, @data="\000\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\e\034\035\036\037 !\"\#$%&'()*+,-./012345678", @duration=nil, @data_size=56, @timeout=5, @bind_port=0, @warning=nil, @exception=nil, @seq=0, @host="gomix.fedora-ve.org", @bind_host=nil, @port=nil> 5 irb(main):016:0> p u.ping? 6 true 7 => nil

Tenga presente que:

1 >> u = Net::Ping:ICMP.new(host) 2 RuntimeError: requires root privileges 3 from /usr/lib/ruby/gems/1.8/gems/net-ping-1.4.0/lib/net/ping/icmp.rb:25:in initialize' 4 from (irb):5:in new' 5 from (irb):5 6

Ping "external", esta opción utiliza la utilidad "ping" de su sistema operativo.

1 >> host="200.44.32.12" 2 => "200.44.32.12" 3 >> u = Net::Ping::External.new(host) 4 => #<Net::Ping::External:0xb73fbd50 @duration=nil, @warning=nil, @timeout=5, @exception=nil, @host="200.44.32.12", @port=7> 5 >> p u.ping? 6 true

Por cierto, net-ping no está empaquetado en Fedora, ello es una buena oportunidad para que comiences tu primer proyecto de empaquetamiento de rubygems en Fedora, contáctame y suscribe en el grupo de desarrollo latinoamericano RPMDev .

Gomix_