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]], | This week's contribution is from [[User:gomix|Guillermo Gómez]], an introduction to bash-completion. Enjoy! | ||
=== | ===bash-completion=== | ||
Si usted es administrador de sistemas o desarrollador, y si no ha montado este paquete, tal vez llore de felicidad después de unos minutos de su uso. No haré más comentarios, sólo ejemplos. | |||
<code> | |||
# yum install bash-completion | |||
</code> | |||
====service==== | |||
<code> | |||
$ service ht<tab> | |||
</code> | |||
====alias==== | |||
<code> | |||
$ unalias <tab><tab> | |||
egrep fgrep grep l. ll ls mc vi which | |||
</code> | |||
====yum==== | |||
<code> | |||
$ yum install bas<tab><tab> | |||
bashdb.noarch basket-libs.i686 bastet.x86_64 | |||
bash-doc.x86_64 basket-libs.x86_64 | |||
BasiliskII.x86_64 basket.x86_64 | |||
</code> | |||
====yumdb==== | |||
<code> | |||
$ yumdb rename<tab><tab> | |||
rename rename-force | |||
</code> | |||
====pkcon (PackageKit)==== | |||
<code> | |||
$ pkcon re<tab><tab> | |||
refresh repo-disable repo-list resolve | |||
remove repo-enable repo-set-data | |||
</code> | |||
====svn==== | |||
<code> | |||
$ svn c<tab><tab> | |||
cat checkout cl co copy | |||
changelist ci cleanup commit cp | |||
</code> | |||
====git==== | |||
<code> | |||
$ git cl<tab><tab> | |||
clean clone | |||
</code> | |||
====modprobe==== | |||
<code> | |||
$ modprobe co<tab><tab> | |||
cobra compal-laptop coretemp | |||
coda configfs | |||
</code> | |||
====man==== | |||
<code> | |||
$ man ls<tab><tab> | |||
ls lscgroup lseek64 lsof lstat | |||
lsame lscpu lset lsort lstat64 | |||
lsattr lsdiff lsetfilecon lspci lsusb | |||
lsblk lsearch lshal lspcmcia | |||
lsb_release lseek lsmod lssubsys | |||
</code> | |||
====ssh==== | |||
<code> | |||
$ ssh 10.10.10.<tab><tab> | |||
10.10.10.223 10.10.10.226 10.10.10.50 | |||
10.10.10.225 10.10.10.233 10.10.10.80 | |||
</code> | |||
Gomix" | |||
* Métodos públicos: pueden ser invocados por cualquiera, no se aplica ningún control de acceso. Los métodos son públicos por omisión excepto initiliaze que siempre es privado. | * Métodos públicos: pueden ser invocados por cualquiera, no se aplica ningún control de acceso. Los métodos son públicos por omisión excepto initiliaze que siempre es privado. |
Revision as of 20:18, 23 June 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, an introduction to bash-completion. Enjoy!
bash-completion
Si usted es administrador de sistemas o desarrollador, y si no ha montado este paquete, tal vez llore de felicidad después de unos minutos de su uso. No haré más comentarios, sólo ejemplos.
- yum install bash-completion
service
$ service ht<tab>
alias
$ unalias <tab><tab>
egrep fgrep grep l. ll ls mc vi which
yum
$ yum install bas<tab><tab>
bashdb.noarch basket-libs.i686 bastet.x86_64
bash-doc.x86_64 basket-libs.x86_64
BasiliskII.x86_64 basket.x86_64
yumdb
$ yumdb rename<tab><tab>
rename rename-force
pkcon (PackageKit)
$ pkcon re<tab><tab>
refresh repo-disable repo-list resolve
remove repo-enable repo-set-data
svn
$ svn c<tab><tab>
cat checkout cl co copy
changelist ci cleanup commit cp
git
$ git cl<tab><tab>
clean clone
modprobe
$ modprobe co<tab><tab>
cobra compal-laptop coretemp
coda configfs
man
$ man ls<tab><tab>
ls lscgroup lseek64 lsof lstat
lsame lscpu lset lsort lstat64
lsattr lsdiff lsetfilecon lspci lsusb
lsblk lsearch lshal lspcmcia
lsb_release lseek lsmod lssubsys
ssh
$ ssh 10.10.10.<tab><tab>
10.10.10.223 10.10.10.226 10.10.10.50
10.10.10.225 10.10.10.233 10.10.10.80
Gomix"
* Métodos públicos: pueden ser invocados por cualquiera, no se aplica ningún control de acceso. Los métodos son públicos por omisión excepto initiliaze que siempre es privado. * Métodos protegidos: sólo pueden ser invocados por objetos de la misma clase o subclases. El acceso se mantiene a la familia. * Métodos privados: no pueden ser invocados con un receptor explícito, el receptor siempre es self. Esto significa que los métodos privados sólo pueden ser llamados en el contexto del objeto actual, no se puede invocar los métodos privados de otro objeto.
Una diferencia importante con otros lenguajes orientados a objeto es que el control de acceso es determinado dinámicamente en la medida que el programa se ejecuta. Obtendrá una violación de acceso sólo cuando intente ejecutar el método restringido.
Especificación del control de acceso
Se especifica el nivel de acceso de los métodos dentro de una clase o módulo utilizando una o más de las tres funciones public, protected y private. Puede usar cada función en dos formas diferentes.
Si se usan sin argumentos, las tres funciones definen el control de acceso de los métodos subsiguientes.
1 class MiClase
2 def metodo1 # 'public' por omisión
3 #
4 end
5
6 protected # los subsiguientes métodos serán 'protected'
7
8 def metodo2
9 #
10 end
11
12 private # los subsiguientes métodos serán 'private'
13
14 def metodo3
15 #
16 end
17
18 public # los subsiguientes métodos serán 'public'
19
20 def metodo4
21 #
22 end
23 end
De forma alternativa puede simplemente listar los métodos en dichas funciones.
1 class MiClase
2 def metodo1
3 #
4 end
5 # ... y el resto de las definiciones de métodos
6
7 public :metodo1, :metodo4
8 protected :metodo2
9 private :metodo3
10 end
Ejemplo private
El ejemplo abajo muestra un esqueleto para proteger un método peligroso de alteración del estado del objeto por medio del uso de otro método intermediario que se supone asegura el acceso, esto ayuda a mantener el código separado pero simple, uno asegura por ejemplo las credenciales, el otro ajusta el estado del objeto.
1 class Banco
2 def initialize
3 @tasa="10%"
4 end
5
6 def tasa
7 @tasa
8 end
9
10 def interfase_segura(nueva_tasa) # Se supone que es "segura", llama al método privado
11 # Código de seguridad
12 self.tasa=nueva_tasa
13 end
14
15 private
16 def tasa=(nueva_tasa)
17 @tasa=nueva_tasa
18 end
19 end
1 >> banco = Banco.new
2 => #<Banco:0xb747e318 @tasa="10%">
3 >> banco.tasa
4 => "10%"
5 >> banco.interfase_segura("20%")
6 => "20%"
7 >> banco.tasa
8 => "20%"
9 >> banco.tasa="30%"
10 NoMethodError: private method `tasa=' called for #<Banco:0xb747e318 @tasa="20%">
11 from (irb):63
12
Ejemplo protected
Por definición este control de acceso limita el acceso a la familia, objetos de la misma clase, y objetos de clases derivadas de la clase que define el método protegido. Abajo un ejemplo simple para comparar manzanas con manzanas, no con peras.
1 class Manzana
2 def initialize(peso)
3 @peso = peso
4 end
5
6 def <=>(otra_manzana)
7 self.peso <=> otra_manzana.peso
8 end
9
10 protected
11
12 def peso
13 @peso
14 end
15 end
16
17 class Pera
18 def initialize(peso)
19 @peso = peso
20 end
21
22 def <=>(otra_pera)
23 self.peso <=> otra_pera.peso
24 end
25
26 protected
27
28 def peso
29 @peso
30 end
31 end
1 >> m1 = Manzana.new(100)
2 => #<Manzana:0xb74838e0 @peso=100>
3 >> m2 = Manzana.new(200)
4 => #<Manzana:0xb747dda0 @peso=200>
5 >> p1 = Pera.new(50)
6 => #<Pera:0xb74783c8 @peso=50>
7 >> m1 <=> m2
8 => -1
9 >> m1 <=> p1
10 NoMethodError: protected method peso' called for #<Pera:0xb74783c8 @peso=50>
11 from ./manzanas.rb:7:in
<=>'
12 from (irb):11
13
Al intentar hacer la comparación entre manzana y pera, se invoca pera.peso en el contexto de las manzanas, y ya que el método está protegido, entonces da el error.
Ahora bien, esta idea de uso para protected en realidad está en franco desuso por muchos ya que va en contra de la flexibilidad y dinamismo natural de Ruby y del concepto de Duck Typing que explicaremos a continuación.
Duck Typing
En Ruby no declaramos tipos de variables o tipos para los métodos, todo es simplemente alguna encarnación, un objeto de una clase, y las clases no son tipos. Si deseamos programar con la filosofía Duck Typing lo único que necesita recordar es que el "tipo" de objeto está determinado por lo que puede hacer, no por su clase.
En la práctica esto significa que hay pocas pruebas de valores de objeto. Por ejemplo digamos que estamos programando un método para agregar información de dos objetos de cierta clase y obtener un resultado String. Los programadores con conocmientos de C# o Java estarían tentados a hacer algo como lo siguiente:
1 def anexar(obj1,obj2)
2 # probar que se nos han dado lo parámetros correctos
3 unless obj1.kind_of?(String)
4 fail TypeError.new("Se espera String")
5 end
6 unless obj2.kind_of?(String)
7 fail TypeError.new("Se espera String")
8 end
9 obj1 << obj2
10 end
1 >> anexar("Hola", " Mundo")
2 => "Hola Mundo"
3 >> anexar("Hola", 1)
4 TypeError: Se espera String
5 from ./dt.rb:7:in anexar'
6
Si abraza la filosofía Duck Typing de Ruby podrá escribir este método de una forma mucho más simple.
1 def anexar(obj1,obj2)
2 obj1 << obj2
3 end
Usted no necesita verificar el tipo de los argumentos en tanto que se soporte el método << en obj1 simplemente todo funcionará bien. Si no es así, se lanzará una excepción de todas maneras, el mismo resultado de que si usted hubiera implementado la verificación. Pero de pronto su método es mucho más flexible, puede pasarle otros objetos no necesariamente String, tal vez un Fixnum.
1 >> anexar("Hola", 1)
2 => "Hola\001"
¿Qué pasa si obj1 no soporta el método << entonces?
1 >> anexar(1.2, " dos ")
2 NoMethodError: undefined method
<<' for 1.2:Float
3 from (irb):6:in `anexar'
4 from (irb):13
5
Obtenemos una excepción NoMethodError para el método << para la clase Float en este ejemplo. Una forma de prevenir posible es usar el método respond_to?:
1 def anexar(obj1,obj2)
2 # probar que se nos han dado lo par ámetros correctos
3 unless obj1.respond_to?(:<<)
4 fail TypeError.new("'obj1' necesita la capacidad <<")
5 end
6
7 obj1 << obj2
8 end
Pero nuevamente esto es más código que mantener y hay que evaluar si realmente quiere tomar ese trabajo ya que igualmente podría manejar las excepciones más arriba.
Si ahora pasa un Array como obj2 obtendrá un error de tipo ya que Array no es un String pero si podemos invocar el método to_s para obtener una representación razonable. En última instancia lo que queremos es que nuestro método si nos devuelva un String.
1 >> arreglo = [0,1,2]
2 => [0, 1, 2]
3 >> anexar("Hola", arreglo.to_s)
4 => "Hola012"
Esto nos lleva a una nueva versión del método anexar, usando to_s para "convertir" los objetos en String, ahora ya tampoco necesitamos la verificación respond_to? ya que String responde a << . Tal vez ahora lo que necesita es validar es que tengan una representación en String, es decir, que respondan a to_s.
1 def anexar(obj1, obj2)
2 # probar que se nos han dado lo parámetros correctos
3 unless obj1.respond_to?(:to_s)
4 fail TypeError.new("Se espera que responda a to_s")
5 end
6 unless obj2.respond_to?(:to_s)
7 fail TypeError.new("Se espera que responda a to_s")
8 end
9
10 obj1.to_s << obj2.to_s
11 end
El código de prueba puede llevarle nuevamente a situaciones indeseables. ¿Soporta obj1 << pero no to_s? Es mejor lidiar con las excepciones que ponerse a probar los tipos y/o los métodos a los que responde. Con esta nueva versión, podemos por ejemplo pasarle dos arreglos, mejor dicho, cualquier par de objetos que tenga una representación String (to_s) y concatenarlos y obtener una salida en String.
1 >> arreglo = [0,1,2]
2 => [0, 1, 2]
3 >> anexar(arreglo, arreglo)
4 => "012012"
Ahora veamos nuestro método en acción con varios objetos involucrados:
1 >> anexar("Hola", " Mundo") ; dos String
2 => "Hola Mundo"
3 >> anexar(1, " Mundo") ; Fixnum + String
4 => "1 Mundo"
5 >> anexar(1, 1) ; dos Fixnum
6 => "11"
7 >> anexar(1, 1.1) ; Fixnum + Float
8 => "11.1"
9 >> anexar(1, [1,2," :) "]) ; Fixnum + Array
10 => "112 :) "
11 >> anexar({1=> "mundo", 2 => "hola"}, [1,2," :) "]) ; Hash + Array
12 => "1mundo2hola12 :) "
De lo único que debe preocuparse en su clase particular es que soporte to_s para tomar ventaja de nuestro método, si no fallará con una excepción. Veamos:
1 >> class Miclase
2 >> end
3 => nil
4 >> miobj = Miclase.new
5 => #<Miclase:0x7fb2a1b2c770>
6 >> anexar("Uh?", miobj)
7 => "Uh?#<Miclase:0x7fb2a1b2c770>" ; to_s ya existe!
8 >> anexar(miobj, "¡Ah!")
9 => "#<Miclase:0x7fb2a1b2c770>\302\241Ah!" ; to_s ya existe...
Por supuesto puede sobrescribir el método to_s heredado de Object.