Aprende a Programar Con Ruby

Post on 15-Jul-2016

38 views 0 download

description

guia para aprender a programar con el lenguaje RUBY

Transcript of Aprende a Programar Con Ruby

1. Introduction2. Lección1

i. ¿QuéesRuby?ii. Instalacióniii. Númerosiv. Stringsv. Variables

3. Lección2i. Métodosii. ReglasNombresiii. Rangosiv. Arraysv. Bloques

4. Lección3i. MásMalabaresconStringsii. ExpresionesRegularesiii. Condicionalesiv. Buclesv. NúmerosAleatorios

5. Lección4i. ClasesyObjetosii. Accesoresiii. Ficheros:lecturayescrituraiv. Usandolibreríasv. Herenciadeclasesvi. Modificandoclasesvii. Congelandoobjetosviii. Serializandoobjetos

6. Lección5i. Controldeaccesoii. Excepcionesiii. Módulosiv. Constantesv. HashesySímbolosvi. LaclaseTime

7. Lección6i. selfii. DuckTypingiii. AzúcarSintácticoiv. Testdeunidades

Tabladecontenido

AprendeaprogramarconRuby

2

EstetutorialdeRubyestábasadoenTheRubyStudyNotes,deSatishTalim,aunqueheañadidoalgodecosechapropia,yorganizadolasleccionesdeotramanera.Además,paraaquellosquesepanprogramaryquieranverlascapacidadesdeRuby,hepreparadoesteRubyen15minutos,queesunresumenmuycondensadodetodoestetutorial.Tambiénlorecomiendoparaaquellosquelohayanterminado,yquieranrepasarloaprendido.

AprendeaprogramarconRuby

3Introduction

Rubyesunlenguajemultiplataforma,interpretadoyorientadoaobjetos.RubyfuediseñadoporYukihiroMatsumoto('Matz')en1993,conelPrincipiodelaMenorSorpresa.

"Queríaminimizarmifrustraciónmientrasprogramo,yesoconllevabaminimizarmiesfuerzo.EsteeselprincipalobjetivodeRuby.Quierodivertirmemientrasprogramo.DespuésdelanzarRubyyprobarlomuchagente,ellosmedijeronquesentíanlomismoqueyo.Ellosfueronlosqueacuñaroneltérminode"PrincipiodeMenorSorpresa".YukihiroMatsumoto

Enelaño2004hubounboomenelinterésporRuby,debidoaRubyonRails:elentornoparadesarrollowebdeDavidHeinemeierHansson.

EnellibrodeDavidBlack"RubyforRails",élmencionaqueunbuenconocimientoenRubypuedeayudarte,comodesarrolladordeRails,encuatroformas:

1. Conocermejorelcódigodetuaplicación(inclusoelcódigoqueRailsescribeautomáticamente).2. SermásproductivoconRails,inclusosidominastodassustécnicas.3. FamiliarizartemejorconelcódigodeRails,loquetepermitiráparticiparendiscusionessobreRailsyquizáspoder

ayudardetectandobugsoaportandopatches.4. Utilizarunapoderosaherramientaparatareasdeadministraciónyorganizaciónconectadascontuaplicación.

Libredeformato:unacosasepuedehacerdedistintasmaneras.Escogelaquemejorseadapteatuformadetrabajo.

Sensiblealasmayúsculas:dospalabras,aunquesediferenciensolamenteenunaletra,porestarenmayúsculaominúscula,sondoscosasdistintas.Porejemplo,'Dir'noeslomismoque'dir'.

Comentarios:cualquierlíneaprecedidapor#esignoradaporelintérprete.Además,cualquiercosaqueescribamosentrelaslíneas=beginy=end(empezandoambasenlaprimeracolumnadesucorrespondientelínea),tambiénseráignorada.

#Comentariodeunasolalínea

=begin

Estoes

uncomentario

devarias

líneas

=end

MUYIMPORTANTE:esteúltimotipodecomentarios,nopuedetenerespaciosasuizquierda,porquedaríaunerror.Porlotanto,sisequiereusar,siemprevanpegadosalmargenizquierdodelapantalla.

=begin

¿QuéesRuby?

¿Cómopuedeayudarte?

Algunascaracterísticas

AprendeaprogramarconRuby

4¿QuéesRuby?

Estecomentariomultilínea

daunerror.

=end

Delimitadoresdeinstrucción:variasinstruccionesenunamismalíneapuedenserseparadasporun;,peronosonnecesariosalfinaldeunalínea:estefinaldelínea(oretornodecarro)setratacomoun;.Siunfinaldelíneaacabaconun\,entonceselretornodecarroesignorado,loquepermitetenerunainstruccióndividaenvariaslíneas.

#Variasinstruccionesenunamismalínea

a=1;b=2;c=3

#esequivalentea:

a=1

b=2

c=3

#Unainstrucciónenvariaslíneas

a='enjutomojamuto'

#esequivalentea:

a="enjuto\

mojamuto"

Palabrasclave:tambiénconocidascomopalabrasreservadas,sonpalabrasenRubyquenopuedenserusadasparaotrospropósitos,porejemplo,comoalmacenarvalores.Además,puedesestaracostumbradoapensarqueunvalor'falso'puedeestarrepresentadopor0(enRubyseevalúaatrue),unacadenavacíaovariasotrascosas.

falseynil:EnRuby,todoestoesválido;dehecho,todoesciertoexceptolaspalabrasreservadasfalseynil.

AprendeaprogramarconRuby

5¿QuéesRuby?

Comolenguajemultiplataforma,Rubyhasidoportadoadistintossistemasoperativosyarquitecturas.EstosignificaquesitudesarrollasunprogramaenunPC(porejemplo),seráposibleejecutarloenotramáquinadistintacomoesunMAC(porponerotroejemplo).

LassiguientesinstruccionessonparainstalarRubyenunPC.Paraotrasplataformas,verelprimercapítulodelaWhy's(poignante)guidetoruby.

LaformamássencilladeinstalarRubyenunPCesmedianteelRubyOne-ClickInstaller.Despuésdedescargarloinstálaloaceptandotodopordefecto.Alinstalarse,lasVariablesdeEntornodelSistemasonactualizadas,detalformaqueseincluyaeldirectoriodelejecutabledeRuby:graciasaesto,podrásejecutarledesdecualquierdrectorioentuPC.

LainstalacióndeRubyincluyelaprimeraedicióndellibro"ProgrammingRuby"yeleditorSciTe.

SupongamosquelainstalacióndeRubyfueenc:/ruby.Estainstalacióncreóunaseriededirectorios:

c:/ruby/binesdondelosejecutablessoninstalados(incluyendorubyeirb).c:/ruby/lib/ruby/1.8aquíestánprogramasescritosenruby.EstosficherossonlibreríasdeRuby:proveenfuncionalidadesquepuedesincorporarentusprogramas.c:/ruby/lib/ruby/1.8/i386-mswin32contieneunaseriedeextensionesespecíficasdelPC.Losficherosenestaterminaciónacabanen.soo.dll(dependiendodelaplataforma).EstosficherosconextensionesprogramadasenlenguajeC;dichodeotraforma:sonfihcerosbinarios,compiladosduranteelprocesodeinstalación,quesepuedenejecutardesdeRuby.c:/ruby/lib/ruby/site_rubyaquíesdondeeladministradordetusistemay/otúpodéisalmacenarlasextensionesylibreríasdeterceraspartes:códigoescritoportimismo,oporotros.c:/ruby/lib/ruby/gemseselsistemaRuby-Gemes,encargadodelainstalacióndenuevasherramientas.c:/ruby/srcesdondesehallaelcódigofuentedeRuby.c:/ruby/samples/RubySrc-1.8.6/sampleaquípodrásencontraralgunosprogramasejemploescritosenRuby.

UsemoseleditorSciTE:Start/Programas/Ruby/SciTe.Seabreeleditor.Paracambiarlosparámetrosdearranque,Options/OpensGlobalyallímodificar:

tabsize=2,indent.size=2(tamañodeltabulador,yelidentado)position.width=-1,position.height=-1(arrancarmaximizado)

Unavezcambiadoslosvalores,pulsarCtrl+SyCtrl+S.Paramodificarestosdosvalores,otraformaes:

Ctrl+Shift+I-abreundiálogodondemodificarlosvaloresanteriores.Tienenqueser=2.F11-paramaximizarminimizarlaventana.

Loúltimoquefaltaantesescribirlosprogramas,esunabrirunaventanadeterminalparaverlosresultadosdelosprogramas.ParaellohayquepulsarF8.UnavezajustadoelSciTE,losiguienteescrearundirectoriodondeirguardandolosprogramasquevayamoscreando.

DescargandoRuby

Directoriosdelainstalación

Elprimerprograma

AprendeaprogramarconRuby

6Instalación

EnlaventanaizquierdadeSciTE(tienequehaber2ventanasdespuésdepulsarF8),escribir:

#p001hola.rb

puts'Hola'

Ahorahayqueguardaryejecutarelprograma.Lasnormasdicenqueelnombredelficheroodirectorio,eselnombreenminúsculasdelaclase/módulo(másadelantesehablarádeclasesymódulos).Porejemplo,laclaseFooestáenelficherofoo.rb.Paraguardarelfichero:File\SaveAs…Sálvalocomop001hola.rb.TodoslosficherosdecódigoRubytienenlaterminación"rb".Ahoraejecutaelprograma:pulsaF5.Enlaventanadeoutputaparecerálapalabra"Hola".

EnRuby,laejecucióndelasinstruccionesdelprograma,vadelaprimeraalaúltima:

#p001hola.rb

Nohacenada.Todaslaslíneasprecedidaspor#soncomentarios.Yloscomentariosseignoranalejecutarseelprograma.

puts'Hello'

putssignifica"ponerstring".Stringesunacadenadetexto.Estainstrucciónsacaporeloutputcualquiercosaquepongamosasuderecha.

Losparéntesissonopcionalescuandousamosunmétodo,enestecasoputs.Lassiguientesinstruccionessoncorrectas:

foobar

foobar()

foobar(a,b,c)

foobara,b,c

EnRuby,tododesdeunnúmeroenteroaunacadenadetexto,esunobjeto.Hablaremosmásdeesto.Ycadaobjetotienesuspropiosmétodos(oinstruccionesofunciones)quepuedenserusadosparahacercosasmuyútiles.Parausarunmétodo,necesitasponerun'.'despuésdelnombredelobjeto,yluegoponerelnombredelmétodo.Algunosmétodoscomoputsygetsnonecesitanestarasociadosaunobjeto,yportantopuedenserusadosdesdecualquierparte.CuandoseejecutaunaaplicaciónenRuby,siempresecreaunobjetollamadomaindelaclaseObject:esteobjetoeselquetienedentrolosmétodosKernel.Detodoestosehablarámásadelante.

Todoestosepuedeverificarporelsiguienteprograma(notepreocupessinoentiendeselprograma,másadelanteseexplicará):

puts'Soyunaclases='+self.class.to_s

puts'Soyunobjeto='+self.to_s

print'Losmétodosdelobjetoson='

putsself.private_methods.sort

'Hola'

Normasdecódigo

AprendeaprogramarconRuby

7Instalación

ProgramadoresdeCyJava-nosenecesitaescribirunmétodomain.Losstringssonsecuenciasdecaracteresentresimpleodoblescomillas.Lascomillassimplessonmáseficientesquelasdobles.Seexplicarámásadelante.Rubyesunlenguajeinterpretado,entoncesnohacefaltarecompilarparaejecutarunprograma.LasnormasdecódigoenRuby,establecenqueelnombredelfichero/directoriotienequeserelnombredelaclase/móduloenminúsculas,añadiendolaextensión.rb

Observaciones

AprendeaprogramarconRuby

8Instalación

EnRuby,losnúmerossinlacomadecimalsonllamadosenteros,ylosenteroscondecimalessonllamadoscoma-flotantes,omássencillamente,flotantes.

puts1+2

puts10-11

puts2*3

#División:cuandodividesdosenteros,obtienesunentero:

puts3/2

#siquieresobtenerelresultadodedecimal,

#almenosunodelosdostienequeserdecimal

puts3.0/2

puts3/2.0

puts1.5/2.6

LosnúmerosenRubysonobjetosdelaclaseFixnumoBignum:estasclasesrepresentannúmerosenterosdedistintostamaños.AmbasclasesdesciendendelaclaseInteger(eninglés,integer=entero).Losnúmeroscoma-flotantessonobjetosdelaclaseFloat(eninglés,float=flotante).

VeamoselejemploquePeterCoopernospropone,sacadodesulibro"BeginningRuby"(noimportaquetodavíanoseascapazdeentendertodoelcódigo):

=begin

Problemadeltablerodeajedrez:

sienlaprimeracasillaponemosungrano,

yduplicamoslacantidaddegranosenlasiguiente,

yasíhastarellenareltablero,

¿cuántosgranostendremos?

=end

granos=1

64.timesdo|escaque|

puts"Enelescaque#{escaque+1}hay#{granos}"

granos*=2

end

Alfinaltenemos2.2.2...2.2=264granosenlaúltimacasilla…¡trillonesdegranos!EstodemuestraqueRubyescapazdemanejarnúmerosextremadamentegrandes,yadiferenciadeotroslenguajesdeprogramación,nohaylímitesenesosnúmeros.Rubyhaceestograciasalasdistintasclasesantesmencionadas:

Fixnum:manejalosnúmerospequeñosBignum:manejalosnúmerosgrandes(eninglés,big=grande).Rubyescogerácuálusar,ytúúnicamentetendrásquepreocuparteporloquequierashacerconellos.

EchémosleunojoalosoperadoresdeRuby(HalfFulton-TheRubyWay).Estánordenadosdemayoramenorrangodeprecendencia;dichodeotraforma,losdelapartesuperiordelatabla,sonlosprimerosenejecutarse.

operador significado

: Alcance(scope)

[] Índices

Números

Operadoresyprecedencias

AprendeaprogramarconRuby

9Números

** Exponentes

+-!~ Unarios:pos/neg,no,…

*/% Multiplicación,División,…

+- Suma,Resta,…

«» Desplazadoresbinarios,…

& 'y'binario

,^ 'or'y'xor'binarios

>>=<<= Comparadores

=====<=>!==~!~ Igualdad,inegualdad,…

&& 'y'booleano

|| 'o'booleano

..… Operadoresderango

=(+=,-=,...) Asignadores

?: Decisiónternaria

not 'no'booleano

and,or 'y','o'booleano

Destacarque:

Losparéntesisfuncionandelamismaformaqueenlasmatemáticas:cualquiercosadentrodeellosescalculadoenprimerlugar.Odichomástécnicamente:tienenmásprecedencia.Losoperadoresincrementoydecremento(++y—)noestándisponiblesenRuby,niensuforma"pre"niensuforma"post".

Eloperadormódulo,quenosdaelrestodeunadivisión,secomportacomosigue:

puts(5%3)#imprime2

puts(-5%3)#imprime1

puts(5%-3)#imprime-1

puts(-5%-3)#imprime-2

`

Escribirunprogramaquedigacuantosminutoshayenunañode365días.

Eloperadormódulo

Ejercicio

AprendeaprogramarconRuby

10Números

Losstrings(ocadenasdetexto)sonsecuenciasdecaracteresentrecomillassimplesocomillasdobles.''(doscomillassimples)notienennada:podemosllamarlostringvacío.

puts"Holamundo"

#Sepuedeusar"o'paralosstrings,pero'esmáseficiente.

puts'Holamundo'

#Juntandocadenas

puts'Megusta'+'Ruby'

#Secuenciadeescape

puts'Ruby\'sparty'

#Repeticióndestrings

puts'Hola'*3

#Definiendounaconstante

#Másadelantesehablarádeconstantes

PI=3.1416

putsPI

EnRubylascadenassonmutables:sepuedenmodificar.Rubyalmacenalascadenascomosecuenciasdebytes.

Hayunosstringsespecialesquesediferencianporusarcomodelimitadorelacentograve`:

puts`dir`

Elstringentrelosacentos,esenviadoalsistemaoperativocomouncomandoaserejecutado.Elresultadodevueltoporelsistema,esrecogidoporRuby.

Conlainterpolaciónnosreferimosalprocesodeinsertarelresultadodeunaexpresióndentrodeunstring.Laformadehacerloesmediante#{expresión}.Ejemplo:

puts"100*5=#{100*5}"

Lasección#{100*5}seejecutayponeelresultadoenesaposición.Esdecir,500.

Ladiferenciaentreambasformas,eseltiempoquesetomaRubyencadauna:mientrasqueconlassimplescomillas,Rubyhacemuypoco;enlasdoblescomillas,Rubytienequehacermástrabajo:

1. buscaposiblessustituciones:lassecuenciasdeescape(lasqueempiecenporun)sonsustituidasporsuvalorbinario.

2. buscaposiblesinterpolaciones:enlassecuenciascon#{expresión},secalculalaexpresión,ysesustituyeelbloqueenteroporsuresultado.

Strings

Elacentograve`

Interpolación

Comillas(')vscomillasdobles(")

AprendeaprogramarconRuby

11Strings

defdi_adios(nombre)

resultado="Buenasnoches,#{nombre}"

returnresultado

end

putsdi_adios('Pepe')

=begin

Comolosmétodosdevuelvenelvalor

delaúltimalínea,nohacefalta

elreturn.

=end

defdi_adios2(nombre)

resultado='Buenasnoches,'+nombre

end

putsdi_adios2('Pepe')

=begin

Ahora,envezdeusar",usamos',

utilizandolaconcatenacióndestrings

paraobtenerelmismoresultado.

=end

String#lengthdevuelveelnúmerodebytesdeunacadena.

string="Estoesunacadena"

string.length#=>18

string.lengthdevuelve18.Cuentatodaslasletras,incluidoslosespaciosenblanco.

String#length

AprendeaprogramarconRuby

12Strings

Paraalmacenarunnúmeroounstringenlamemoriadelordenador,conelfindeusarlosencálculosposteriores,necesitasdarunnombreaesenúmeroostring.Enprogramaciónesteprocesoesconocidocomoasignación.

#Ejemplosdeasignaciones

s='HelloWorld!'

x=10

Lasvariableslocalesenrubysonpalabrasquedeben:

1. empezarconunletraminúsculaounguiónbajo_.2. estarformadasporletras,númerosy/oguionesbajos.

CuandoRubyencuentraunapalabra,lainterpretacomo:unavariablelocal,unmétodoounapalabraclave.Laspalabrasclavesnopuedenserusadoscomovariables.Porejemplodefesunapalabraclave:sólosepuedeusarparadefinirunmétodo.iftambiénesunapalabraclave:granpartedelcódigoconstadeinstruccionescondicionalesqueempiezanconif,poresoseríamuyconfusosipudieseusarsecomovariable.

Losmétodospuedenserpalabras,comostart_here,putsoprint.CuandoRubyencuentraunapalabradecidequéesdelasiguienteforma:

1. sihayunsignodeigualdad(=)aladerechadelapalabra,esunavariablelocalalaqueseleasignaunvalor.2. silapalabraesunapalabraclave,entoncesesunapalabraclave.Rubytieneunalistainternaparapoder

reconocerlas.3. sinosecumpleningunodelosanteriorescasos,Rubyasumequeesunmétodo.

#Definicióndeunaconstante

PI=3.1416

putsPI

#Definicióndeunavariablelocal

myString='Yoamomiciudad,Vigo'

putsmyString

=begin

Conversiones

to_i-convierteanúmeroentero

to_f-convierteanúmerodecimal

to_s-convierteastring

=end

var1=5

var2='2'#fijarsequeesuntexto

putsvar1+var2.to_i

=begin

<<marcaelcomienzodeunstring

yesseguidode'o''.Aquíañadimos

elstringjuntoconelretornodecarro(\n).

=end

a='molo'

a<<'mucho.

Molomazo...'

putsa

=begin

'o"sonlosdelimitadoresdeunstring.

Enestecaso,podemossustituirlosporEND_STR.

END_STResunaconstantedelimitadordestrings.

Variables

AprendeaprogramarconRuby

13Variables

=end

a=<<END_STR

Thisisthestring

Andasecondline

END_STR

putsa

Enelejemplo,var2.to_ielpuntosignificaqueelmétodoto_iesenviadoalavariablevar2,queestecasoesunstring:transformamoselstringenunnúmeroparapodersumarlos.Cuandohablemosdeobjetos,veremosquesepuededecirquelavar2eselreceptordeto_i.Porlotanto,cuandoaparezcaunpuntoenunaposicióninexplicable,habráqueinterpretarlocomounmétodo(lapartederecha)queesenviadoaunobjeto(laparteizquierda).

Porinterpretacióndinámica,seentiendequenohacefaltaespecificarquétipodevariablesevaamanejar:sipareceunnúmero,problablementeseaunnúmero;sipareceunacadena,probablementelosea.Elmétodoclassdevuelveeltipodeclasedeunobjeto:

s='hello'

s.class#String

Otroejemplo:

#Rubyesdinámico

x=7#númeroentero

x="house"#string

x=7.5#númeroreal

Elalcanceesunapropiedaddelasvariables:serefiereasuvisibilidad(aquellaregióndelprogramaadondelavariablepuedeutilizarse).Losdistintostiposdevariables,tienendistintasreglasdealcance.Hablemosdedostiposdevariables:lasglobalesylaslocales.

Empezarmosconelalcancequemenosseusa,peronoporellomenosimportante:unalcanceglobalsignificaquealcanzaatodoelprograma.Desdecualquierpartedelprograma,puedeusarselavariable.Lasvariablesglobalessonlasquetienenalcanceglobal.

Lasvariablesglobalessedistinguenporqueestánprecedidasdelsignodólar$.Puedenservistasdesdecualquierpartedelprograma,yportantopuedenserusadasencualquierparte:nuncaquedanfueradealcance.Sinembargo,lasvariablesglobalessonusadasmuypocoporlosprogramadoresexperimentados.

ElintérpreteRubytienepordefectoungrannúmerodevariablesglobalesiniciadasdesdeelprincipio.Sonvariablesquealmacenaninformaciónútilquepuedeserusadaencualquiermomentoypartedelprograma.

Interpretacióndinámica

Alcance

Alcanceglobalyvariablesglobales

Variablesglobalespordefecto

AprendeaprogramarconRuby

14Variables

Porejemplo,lavariableglobal$0contieneelnombredelficheroqueRubyestáejecutando.Lavariableglobal$:contienelosdirectoriosenlosqueRubybuscacuandosecargaunficheroquenoexisteeneldirectoriodetrabajo.$$contieneelid(identidad)delprocesoqueRubyestáejecutando.Yhaymuchasmás.

Nota:notepreocupessinoentiendesestoahora.

Sepuedeintuirmirandoelcódigodóndeempiezayacabaelalcancedelasvariableslocales,basándonosen:

Elnivelmásalto(fueradetodoslosbloquesdedefinición)tienensupropioalcance.Cadabloquededefinicióndeunaclaseomódulotienensupropioalcance,inclusolosbloquesanidados.Todadefinicióndeunmétodo(def)tienesupropioalcance.

Alcancelocal

AprendeaprogramarconRuby

15Variables

EnRuby,todoloquesemanipulaesunobjeto,yelresultadodeesasoperacionestambiénsonobjetos.Laúnicaformaquetenemosdemanipularlosobjetos,sonlosmétodos:

5.times{puts"Ratón!\n"}#sehablarámástardedebloques

"Aloselefanteslegustanloscacahuetes".length

Silosobjetos(comolosstrings,números,…)sonlosnombres,entonceslosmétodossonlosverbos.Todométodonecesitaunobjeto.Esfácildecirquéobjetorecibeelmétodo:elqueestáalaizquierdadelpunto.Algunasveces,puedequenoseaobvio.Porejemplo,cuandoseusaputsygets,¿dóndeestánsusobjetos?Nadamásiniciarseelintérprete,estamosdentrodeunobjeto:elobjetomain.Portanto,alusarputsygets,estamosmandandoelmensajealobjetomain.

¿Cómopodemossaberdentrodequéobjetoestamos?Usandolavariableself.

putsself

Unbloquedeinstruccionesquedefineunmétodo,empiezaporlapalabradefyacabaporlaend.Losparámetrossonlalistadevariablesquevanentreparéntesis.AunqueenRuby,dichosparéntesissonopcionales:puts,pygetssonmuyusados,yporelloqueelusodeparéntesisseaopcional.EnRails,sellamaalosmétodossinparéntesis.

Unmétododevuelveelvalordesuúltimalínea.Pornorma,esrecomendabledejarunalíneaenblancoentrelasdefinicionesdemétodos:

#metodos.rb

#Definicióndeunmétodo

defhello

puts'Hola'

end

#usodelmétodo

hello

#Métodoconunargumento

defhello1(nombre)

puts'Hola'+nombre

return'correcto'

end

puts(hello1('Pedro'))

#Métodoconunargumento(sinparéntesis,nofuncionaenversionesnuevas)

defhello2nombre2

puts'Hola'+nombre2

return'correcto'

end

puts(hello2'Juan')

Estoesloqueobtenemos

>rubymetodos.rb

Hola

HolaPedro

Variables

Escribiendométodos

AprendeaprogramarconRuby

16Métodos

correcto

HolaJuan

correcto

metodos.rb:18warning:parenthesizeargument(s)forfutureversion

>Exitcode:0

Losmétodosqueacabanconuna!sonmétodosquemodificanalobjeto.Porlotanto,estosmétodossonconsideradoscomopeligrosos,yexistenmétodosiguales,perosinel!.Porsupeligrosidad,elnombre"bang".Ejemplo:

a="Enunalugardelamancha"

#métodosinbang:elobjetonosemodifica

b=a.upcase

putsb

putsa

#métodoconbang:elobjetosemodifica

c=a.upcase!

putsc

putsa

Normalmente,porcadamétodocon!,existeelmismométodosin!.Aquellossinbang,nosdanelmismoresultado,perosinmodificarelobjeto(enestecasoelstring).Lasversionescon!,comosedijo,hacenlamismaacción,peroenlugardecrearunnuevoobjeto,transformanelobjetooriginal.

Ejemplosdeestoson:upcase/upcase!,chomp/chomp!,…Encadacaso,sihacesusodelaversiónsin!,tienesunnuevoobjeto.Sillamaselmétodocon!,hacesloscambiosenelmismoobjetoalquemandasteelmensaje.

aliasnuevo_nombrenombre_original

aliascreaunnuevonombrequeserefiereaunmétodoexistente.Cuandoaunmétodoseleponeunalias,elnuevonombreserefierealmétodooriginal:sielmétodosecambia,elnuevonombreseguiráinvocandoeloriginal.

defviejo_metodo

"viejometodo"

end

aliasnuevo_metodoviejo_metodo

defviejo_metodo

"viejometodomejorado"

end

putsviejo_metodo

putsnuevo_metodo

Enelresultado,vemoscomonuevo_metodohacereferenciaalviejo_metodosinmodficar:

viejometodomejorado

viejometodo

Losmétodosbang(!)

Alias

Métodosperdidos

AprendeaprogramarconRuby

17Métodos

Cuandomandasunmensajeaunobjeto,elobjetobuscaensulistademétodos,yejecutaelprimermétodoconelmismonombredelmensajequeencuentre.Sinoencuetradichométodo,lanzaunaerrorNoMethodError.

Unaformadesolucionaresto,esmedianteelmétodomethod_missing:sidefinimosdichométododentrodeunaclase,seejecutaestemétodopordefecto:

classDummy

defmethod_missing(m,*args)

puts"Noexisteunmetodollamado#{m}"

end

end

Dummy.new.cualquier_cosaobtenemos:

Noexisteunmetodollamadocualquier_cosa

Porlotanto,method_missingescomounareddeseguridad:tedaunaformademanejaraquellosmétodosquedeotraformadaríanunerrorentuprograma.

Rubydejaespecificarlosvalorespordefectodelosargumentos,quesonusadossinoseespecificaunvalorexplícitamente.Sehaceestomedianteeloperadordeasignación=:

#argumentos.rb

defmtd(arg1="Dibya",arg2="Shashank",arg3="Shashank")

"#{arg1},#{arg2},#{arg3}."

end

putsmtd

putsmtd("ruby")

Hemosusadoeloperadorinterpolación#{}:secalculalaexpresiónentreparéntesis,yelresultadoseañadealstring.Loqueobtenemoses:

>rubyargumentos.rb

Dibya,Shashank,Shashank.

ruby,Shashank,Shashank.

>Exitcode:0

Rubypermiteescribirfuncionesqueaceptenunnúmerovariabledeargumentos.Porejemplo:

deffoo(*mi_string)

mi_string.eachdo|palabras|

putspalabras

Argumentos

Valorespordefecto

Númerodeargumentosvariable

AprendeaprogramarconRuby

18Métodos

end

end

foo('hola','mundo')

foo()

Elasteriscoindicaqueelnúmerodeargumentospuedeserelquesequiera.Enesteejemplo,elasteriscotomalosargumentosylosasignaaunarray(ovectordeelementos)llamadomi_string.Haciendousodeeseasterisco,inclusosepuedenpasarceroargumentos;queesloquepasaconfoo().

Nohaymáximonúmerodeargumentosquepodamospasaraunmétodo.

Sisequierenincluirargumentosopcionales,tienenquevenirdespuésdelosargumentosnoopcionales:

defarg_opc(a,b,*x)#bien

defarg_opc(a,*x,b)#mal

Losargumentosseinterpretandeizquierdaaderecha,poresoesimportantequelosargumentosnoopcionalesvayanenprimerlugar.Silospusiésemosenúltimolugar,nosabríamosdecirdondeacabanlosargumentosopcionalesydondeempiezanlosnoopcionales.

=begin

Ejemplodecomolosargumentosse

interpretandeizquierdaaderecha

=end

defmtd(a=99,b=a+1)

[a,b]

end

putsmtd

Leccionesatrásvimoselmétodoputsquesacadatosporlapantalla.¿Cómopodemosintroducirnuestrospropiosdatos?Paraestogets(get=coger,s=string)ychompsondeayuda.Veamoselsiguienteejemplo:

#getsychomp

puts"¿Enquéciudadtegustaríavivir?"

STDOUT.flush

ciudad=gets.chomp

puts"Laciudades"+ciudad

Elejemplosuperior,alserejecutadoenSciTe,clickeaenlapantalladeoutputyponelnombredetuciudadfavorita.STDOUTesunaconstanteglobalquealmacenalassalidasdelprograma.flushvacíacualquierdatoalmacenado,yporlotanto,limpiarácualquierresultadoanterior.chompesunmétodoparastringsygetsalmacenastringsqueprovienendelteclado.Elproblemaesquegetsalmacenaloescritoyelcaráter\n(retornodecarro);chomploquehaceesborrarelcarácter:\n.

RAILS:losdatosvienendemuchossitios.EnlatípicaaplicacióndeRails,vienendeunabasededatos.ComoundesarrolladordeRails,puedesusarconfrecuenciaalgunosdeestosmétodos,porqueRailsrecogelosdatosquelosusuariosescribenenlosformulariosWeb.

Argumentosopcionales

Introduciendodatos(gets)

AprendeaprogramarconRuby

19Métodos

EscribeunprogramaquepregunteporlatemperaturaengradosFahrenheit.Elprogramausaráestedato,yhallaráelequivalenteengradosCelsius.Elresultadofinallomostraráenpantallacondosdecimales.(Celsius(°C)=[Fahrenheit(°F)-32]/1.8)

Nota:paraformatearunresultadoadosdecimales,haydosopciones:

1. Usarelmétodoformat.Porejemplo:

x=45.5678

putsformat("%.2f",x)

1. Otraformaeslafunciónround:

puts(x*100).round/100.0

Ejercicio

AprendeaprogramarconRuby

20Métodos

Unnombreesunaletramayúscula,unaletraminúsculaounguiónbajo,seguidoporcualquiercombinacióndemayúsculas,minúsculas,númerosoguionesbajos.

LosnombresenRubyseusanparareferirseaconstantes,variables,métodos,clasesymódulos.LaprimeraletradeunnombreayudaaRubyadistinguirlos.Algunosnombres,sonpalabrasreservadasynopuedenusarsecomovariable,método,claseomódulo.Elconjuntodelasminúsculasabarcadelaaalazincluyendoelguiónbajo_.ElconjuntodelasmayúsculasabarcadelaAalaZylosnúmeros(del0al9).

Lasvariablescontienencualquiertipodedato.Elpropionombredelavariable,muestrasualcance(local,global,…):

Unavariablelocalconsisteenunaletraminúsculaoguiónbajoseguidodecualquiermayúsculaominúscula.P.ej.:sunil,_z,rock_and_rollUnavariabledeunobjeto(másadelantesehablarádeclasesyobjetos)empiezacon@,seguidodecualquiermayúsculaominúscula.

@sign

@_

@Counter

Unavariabledeclaseempiezacon@@seguidoporcualquiermayúsculaominúscula.

@@signo

@@_

@@Counter

Unavariableglobalempiezapor$,seguidoporcualquiercarácter(nosólomayúsculasominúsculas).

$counter

$COUNTER

$-x.

Unaconstanteempiezaporunaletramayúscula,seguidoporcualquiermayúsculaominúscula.Losnombresdeclasesydemódulossonconstantes,ysiguenunasnormas.

moduleMyMath

PI=3.1416

classPerro

Losnombresdemétodosdebenempezarporunaminúscula(letraoguiónbajo).La?yla!sonlosúnicoscaracteresajenosalgruposdelasmayúsculasyminúsculas,quesepermitencomosufijosdelosmétodos.Másadelanteseexplicarásuuso.

Pornorma,seusaelguiónbajoparasepararpalabrascompuestasenlosnombresdemétodosydevariables.Paralosnombresdeclases,módulosyconstantes,lanormadicedeusarletrasmayúsculasenvezdeguionesbajos,para

Normasenlosnombres

Variables

Constantes

AprendeaprogramarconRuby

21ReglasNombres

distinguirlas.Ejemplos:

variablesymétodos

real_madrid

futbol_club_barcelona

clases,módulosyconstantes:

RealMadrid

FutbolClubBarcelona

Hayquenotarqueunavariablepuedereferirseadistintosvaloresalolargodeltiempo.UnaconstanteenRubypuedeserunareferenciaaunobjeto.Lasconstantessoncreadasenelmomentodesuprimeraasignación,normalmenteenladefinicióndeunaclaseounmódulo;nodebenestardefinidasenlosmétodos.Sepuedevariarelvalordeunaconstante,peroestogeneraunvalordeaviso.

AprendeaprogramarconRuby

22ReglasNombres

Elprincipalusoyquizáselmásapropiadoparalosrangos,esexpresarunasecuencia:lassecuenciastienenunpuntoinicialyunpuntofinal,yunaformadeproducirlossucesivosvaloresentreambos.EnRuby,esassecuenciassoncreadasusandolosoperandos..y…

..generaunasecuenciadondelospuntoslímitesestánincluidos.

(1..3).to_a

#eslasecuencia1,2,3

…generaunasecuenciaenlaquenoestáincluidaellímitesuperior.

(1...5).to_a

#equivalea1,2,3,4

EnRubylosrangosnosonalmacenadoscomounalista:losrangossealmacenancomounobjetoRange,ycontienereferenciasadosobjetosFixnum(sulímitesuperioreinferior).Sepuedeconvertirunrangoenunarray(array=lista,conjuntoordenadodeelementos),medianteelmétodoto_a.

(1..10).to_a

#obtenemos[1,2,3,4,5,6,7,8,9,10]

Losrangosenrubytienendiversosmétodos:

nums=-1...9

putsnums.include?(5)#true

putsnums.min#-1

putsnums.max#8

putsnums.reject{|i|i<5}#[5,6,7,8]

Unodelosusosútilesdelosrangos,escomprobarsiundeterminadovalorestáenelintervalorepresentadoporelrango.Paraesousamoseloperador===:

(1..10)===5#true

(1..10)===15#false

(1..10)===3.14159#true

('a'..'j')==='c'#true

Rangos

Métodosderangos

AprendeaprogramarconRuby

23Rangos

Unarray(olista)esunconjuntoordenado:cadaposiciónenlalistaesunavariablequepodemosleery/oescribir.

#Arrays(ovectores)

#arrayvacío

vec1=[]

#Losíndicesempiezandesdeelcero(0,1,2,...)

nombres=['Satish','Talim','Ruby','Java']

putsnombres[0]

putsnombres[1]

putsnombres[2]

putsnombres[3]

#sielelementonoexiste,sedevuelvenil

putsnombres[4]

#peropodemosañadiraposteriorimáselementos

nombres[3]='Python'

nombres[4]='Rails'

Unarraypuedeserunconjuntodeelementosdistintos:

=begin

unarraycuyoselementos

apuntanaotrostresobjetos:

undecimal,unstringyunarray

=end

sabor='mango'

vec4=[80.5,sabor,[true,false]]

putsvec4[2]

Algunasveces,creararraysdepalabraspuedesertediosodebidoatantascomillasycomas.Afortunadamente,Rubytieneunaformamáscómodaparahacerlo:

nombres1=['ann','richard','william','susan','pat']

putsnombres1[0]#ann

putsnombres1[3]#susan

#estoesmássencilloymásrápido:

nombres2=%w{annrichardwilliamsusanpat}

putsnombres2[0]#ann

putsnombres2[3]#susan

Elmétodoeachextraecadaelementodelarraydentrodelavariablequeseleespecifique(queiráentradosbarras||),queseusaráenbloquedo…end.

ciudades=%w{PuneMumbaiBangalore}

ciudades.eachdo|ciudad|

puts'¡Megusta'+ciudad+'!'

puts'¿Atino?'

Arrays

Usando%w

Elmétodoeach

AprendeaprogramarconRuby

24Arrays

end

#Elmétododeleteborraunelemento

ciudades.delete('Mumbai')

ciudades.eachdo|ciudad|

puts'¡Megustaba'+ciudad+'!'

puts'¿Atiyano?'

end

Porlotantoelmétodoeachnospermitehacerunacosa(laquesea)concadaobjetodelarray.Enelejemplo,fuimoselementoporelementodelarraysinusarlosíndices.Hayquedestacar:

Losvariableentrelos"postes"serefiereacadaítemdelarrayamedidaqueavanzamosenelloop.Sepuedeusarcualquiernombre,peroesmejordotarlodeciertosignificado.Eldo…endidentificaelbloquedecódigoqueseejecutaráconcadaelementodelarray.LosbloquessonusadosintensivamenteenRuby,ysetrataránenprofundidadmásadelante.Esposiblessustiturlosporlasllavesdeinicioyfin.

vec=[34,12,1,38]

putsvec.sort

putsvec.length

putsvec.first

putsvec.last

Unmétodopuededevolverunarray:

defnum_cuadrado(num)

cuadrado=num*num

returnnum,cuadrado

end

=begin

elmétodonosdevuelve

unarrayconelnúmero

ysucuadrado

=end

x=3

num_cuadrado(x)

=begin

siqueremosalmacenarelresultado

hayquehacerlopor

asignaciónenparalelo

=end

num,cuadrado=num_cuadrado(x)

Escribeunprogramatalque,dadounarraynumérico,calculelasumadesuselementos.Porejemplo,array=[1,2,3,4,5]

Escribeunprogramatalque,dadounarraydenúmeros,digadecadaunosiesparoimpar.Porejemplo,array=

Otrosmétodos

Obteniendoarrays

Ejercicios

AprendeaprogramarconRuby

25Arrays

[12,23,456,123,4579]

AprendeaprogramarconRuby

26Arrays

Unbloqueesunaporcióndecódigoencerradaentreparéntesis{}oentredo…end.Porlotanto,unbloqueesunaformadeagruparinstrucciones,ysolopuedeaparecerdespuésdeusarunmétodo:elbloqueempiezaenlamismalíneaqueusaelmétodo.ElcódigodentrodelbloquenoesejectuadoenelinstantequeelintérpretedeRubyloencuentra:Rubyserecordarádelbloque(variableslocales,…)ydespuésentraenelmétodo,ejecutandoelbloquecuandoespreciso.

Supongamosqueexistendosmétodosllamadosgreet1ygreet2:

#greet1,nonecesitaargumentos

greet1{puts'Hola'}

#greet2,necesitaunargumento

greet2("argumento_cualquiera"){puts'Hola'}

Lousualesusarlas{}parabloquesdeunalíneayeldo…endparamásdeunalínea.

Unmétodopuedeusarelbloquemediantelapalabrayield:

defmetodo

puts'Comienzodelmetodo'

yield

yield

puts'Finaldelmetodo'

end

metodo{puts'Dentrodelbloque'}

Lasalidaes:

'Comienzodelmetodo'

'Dentrodelbloque'#primeryield

'Dentrodelbloque'#segundoyield

'Finaldelmetodo'

Loquesucedeesqueenelmomentoqueelintérpretellegaalyield,seejecutaelcódigodentrodelbloque,yluegoseretornaalmétodo.

Enlosbloquessepuedenusarargumentosespecificándolosdentrodedosbarrasverticales||.Ysiseusan,enelyieldnopodemosolvidardarlesvalor:

defmetodo

yield('hola',99)

end

metodo{|str,num|putsstr+''+num.to_s}#hola99

Bloques

Elmétodoyield

Argumentosenlosbloques

AprendeaprogramarconRuby

27Bloques

Unbloquedecódigodevuelveunvalor:elvalordelaúltimaexpresiónevaluada.Yestevalordevueltoporyield,puedeusarsedentrodelmétodoqueinvocaelbloque.

Losbloquesnosonobjetos,peropuedenconvertirseenellosgraciasalaclaseProc.Estosobjetossonbloquesquesehanunidoaunconjutodevariableslocales.EstosehacegraciasalmétodolambdadelmóduloKernel.

prc=lambda{"hola"}

Unbloquecreadoconlambdaactúacomounmétodo:sinoespecificaselnúmerocorrectodeargumentos,nopuedesllamaralbloque.LaclaseProctieneunmétodoparallamaralbloque:elmétodocall.

prc=lambda{puts'Hola'}

prc.call#llamamosalbloque

#otroejemplo

toast=lambdado

puts'Gracias'

end

toast.call

Lasalidaes:

Hola

Gracias

Parausarargumentosconlambda:

aBlock=lambda{|x|putsx}

aBlock.call'HolaMundo!'

Lasalidaes:

HolaMundo!

Losprocssonmuyútilesporque:

Nopuedespasarmétodosdentrodeotrosmétodos(usarloscomoargumentos);perosipuedesusarprocscomoargumentos.Losmétodosnopuedendevolverotrosmétodos;perosípuedendevolverunprocs.

#usodeprocscomoargumentos

defmetod1proc1

puts'Principiodelmetodo'

proc1.call

puts'Finaldelmetodo'

end

hola=lambdado

puts'Hola'

Losprocs

AprendeaprogramarconRuby

28Bloques

end

metod1hola

Lasalidaes:

Principiodelmetodo

Hola

Finaldelmetodo

AprendeaprogramarconRuby

29Bloques

Lasexpresionesregulares,aunquecrípticas,sonunapoderosaherramientaparatrabajarcontexto.Sonusadasparareconocerpatronesyprocesartexto.Unaexpresiónregularesunaformadeespecificarunpatróndecaracteres,queserábuscadoenunstring.EnRuby,secreanlasexpresionesregularesentre//.SonobjetosdeltipoRegexpypuedensermanipuladascomotales.

//.class#Regexp

Laformamássimpledeencontrarsiunaexpresión(tambiénfuncionaconstrings)estádentrodeunstring,esusarelmétodomatchoeloperador=~:

m1=/Ruby/.match("ElfuturoesRuby")

putsm1#"Ruby",puestoqueencontrólapalabra

putsm1.class#devuelveMatchData;devuelve"nil"sinoseencuentra

#operador=~:

m2="ElfuturoesRuby"=~/Ruby/

putsm2#13->posicióndondeempiezalapalabra"Ruby"

Cualquiercarácterquevayaentrebarras,sebuscaexactamente:

/a/#sebuscalaletraa,ycualquierpalabraquelacontenga

Algunoscaracterestienenunsignificadoespecialenlasexpresionesregulares.Paraevitarqueseprocesen,ypoderbuscarlos,seusalasecuenciadeescape\.

/\?/

La\significa"notrateselsiguientecaráctercomoespecial".Loscaracteresespecialesincluyen: ,$,?,.,/,\,[,],{,},(,),+y*.

Algunasveces,sebuscacualquiercaracterenunaposicióndeterminada.Estoselogragraciasal..Unpunto,buscacualquiercarácter,exceptoelretornodecarro.

/.azado/

Buscamazadoycazado.Tambiénencuentra%azadoy8azado.Poresohayquetenercuidadoalusarelpunto:puededarmásresultadosquelosdeseados.Sinembargo,sepuedenponerrestriccionesalosresultados,especificandolasclasesdecaracteresbuscadas.

ExpresionesRegulares

Construyendoexpresionesregulares

Elcomodín.(punto)

AprendeaprogramarconRuby

30ExpresionesRegulares

Unaclasedecarácteresunalistaexplícitadecaracteres.Paraelloseusanloscorchetes:

/[mc]azado/

Deestaforma,especificamoslabúsquedadeazadoprecedidoporcom:solamentebuscamosmazadoocazado.

Dentrodeloscorchetes,sepuedeespecificarunrangodebúsqueda.

/[a-z]/#encuentracualquierminúscula

/[A-Fa-f0-9]/#encuentracualquiernúmerohexadecimal

Algunasvecessenecesitaencontrarcualquiercaráctermenosaquellosdeunalistaespecífica.Estetipodebúsquedaserealizanegando,usando alprincipiodelaclase.

/[^A-Fa-f0-9]/#encuentracualquiercarácter,menosloshexadecimales

Algunoscaracteressontanválidos,quetienensuabreviación.

Abreviacionesparaclasesdecaracteres

Paraencontrarcualquiercifradecimal,estasdosexpresionessonequivalentes:

/[0-9]/

/\d/

Otrasdosabreviacionesson:

\wencuentracualquierdígito,letra,oguiónbajo_.\sencuentracualquiercarácterespacio-en-blanco(characterwhitespace),comosonunespacio,untabuladoyunretornodecarro.Todaslasabreviacionesprecedentes,tambiéntienenunaformanegada.Paraello,seponelamismaletraenmayúsculas:

/\D/#buscacualquiercarácterquenoseaunnúmero

/\W/#buscacualquiercarácterquenoseaunaletraoguiónbajo

/\S/#buscauncarácterquenoseaunespacioenblanco.

expresión significado

. cualquiercaracter

[] especificaciónporrango.P.ej:[a-z],unaletradelaa,alaz

\w letraonúmero;eslomismoque[0-9A-Za-z]

\W cualquiercarácterquenosealetraonúmero

Clasesdecaracteres

Tablaresumen

AprendeaprogramarconRuby

31ExpresionesRegulares

\s carácterdeespacio;eslomismoque[\t\n\r\f]

\S cualquiercarácterquenoseadeespacio

\d número;lomismoque[0-9]

\D cualquiercarácterquenoseaunnúmero

\b retroceso(0x08),siestádentrodeunrango

\b límitedepalabra,siNOestádentrodeunrango

\B nolímitedepalabra

* ceroomásrepeticionesdeloqueleprecede

+ unaomásrepeticionesdeloqueleprecede

$ findelalínea

{m,n} comomenosm,ycomomuchonrepeticionesdeloqueleprecede

? almenosunarepeticióndeloqueleprecede;lomismoque{0,1}

() agruparexpresiones

|| operadorlógicoO,buscalodeantesolodespués

Sinoseentiendealgunadelasexpresionesanteriores,loquehayquehaceresprobar.Porejemplo,veamoselcasode|.Supongamosquebuscamoslapalabragatoolapalabraperro:

/gato|perro/

El|esun"Ológico":sebuscalapalabradelaizquierdaolapalabradeladerecha.

Cualquierbúsquedasucedeconéxitoofracasa.Empecemosconelcasomássimple:elfallo.Cuandointentasencontrarunstringmedianteunpatrón,yelstringnoseencuentra,elresultadosiempreesnil(nil=nada).

/a/.match("b")#nil

Sinembargo,silabúsquedatieneéxitosedevuelveunobjetoMatchData.Esteobjetotieneunvalor'true'desdeelpuntodevistabooleano,yademásalmacenalainformacióndeloencontrado:dondeempieza(enquécarácterdelstring),quéporcióndelstringocupa,…Parapoderusarestainformación,hacefaltaalmacenarlaprimero.Veamosunejemplodondebuscamosunnúmerodeteléfonodentrodeunstring:

string="Minúmerodeteléfonoes(123)555-1234."

num_expr=/\((\d{3})\)\s+(\d{3})-(\d{4})/#expresiónregular

m=num_expr.match(string)#almacenamosbúsqueda

unlessm

puts"Nohuboconcordancias."

exit

end

print"Elstringdelabúsquedaes:"

putsm.string#stringdondeseefectúalabúsqueda

print"Lapartedelstringqueconcuerdaconlabúsquedaes:"

putsm[0]#partedelstringqueconcuerdaconnuestrabúsqueda

puts"Lastrescapturas:"

3.timesdo|index|

#m.captures[index]-subcadenasencontradas(subcaden=()enlaexpresión)

Unabúsquedaconéxito

AprendeaprogramarconRuby

32ExpresionesRegulares

puts"Captura##{index+1}:#{m.captures[index]}"

end

puts"Otraformaparaponerlaprimeracaptura:"

print"Captura#1:"

putsm[1]#cadanúmerocorrespondeaunacaptura

lasalidaes:

Elstringdelabúsquedaes:Minúmerodeteléfonoes(123)555-1234.

Lapartedelstringqueconcuerdaconlabúsquedaes:(123)555-1234

Lastrescapturas:

Captura#1:123

Captura#2:555

Captura#3:1234

Otraformadeponerlaprimeracaptura

Captura#1:123

Paraanalizarlaexpresiónregular,hayqueprestaratenciónacómoestánagrupadaslasbúsquedasentreparéntesis:

num_expr=/\((\d{3})\)\s+(\d{3})-(\d{4})/

\((\d{3})\)buscaungrupodetresnúmeros(\d{3}),entredosparéntesis\(…\)\s+espacioenblancounaovariasveces(\d{3})tresnúmeros-signomenos(\d{4})cuatronúmeros

AprendeaprogramarconRuby

33ExpresionesRegulares

HaymuchosmétodosenlaclaseString(nohayquememorizarlostodos;paraalgoestáladocumentación)como:

reverse,queinvierteloscaracteresdeunstringlength,quenosdiceelnúmerodecaracteresdeunstring,incluyendolosespaciosenblanco.upcase,queponetodosloscaracteresenmayúsculasdowncase,queponetodosloscaracteresenminúsculasswapcase,poneloscaracteresmayúsculasenminúsculasylosminúsculasenmayúsculascapitalize,poneelprimercaracterdelstringenmayúsculas,ylosdemásenminúsculasslice,daunapartedeunstring

Losmétodosupcase,downcase,swapcaseycapitalizetienensucorrespondientemétodobang,quemodificanelstring(upcase!,downcase!,swapcase!,ycaptalize!).Sinonecesitaselstringoriginal,esbuenousarlo,porqueahorrarásmemoria;sobretodosielstringeslargo.

Cadavezqueseseasignaaunavariableunstring,secreaunnuevoobjetoString.¿Cómoesadministradalamemoriaenlosstrings?¿Hayunaporciónseparadaparaellos?LaclaseStringtienemásde75métodos.LeyendolaGuíadeUsodeRuby(RubyUser'sGuide),dice"notenemosencuentalamemoriaocupadaporunstring.Prescindimosdecualquieradministracióndememoria".ParasabertodoslosmétodosquetieneunString:

String.methods,daunalistadetodolosmétodosquetienelaclaseString.String.methods.sort(sort=ordenar),daunalistaordenadaalfabéticamentedetodoslosmétodos.String.instance_methods.sort,daunalistaordenadadetodolosmétodosdeinstancia(seexplicarámásadelante)quetieneunString.String.instance_methods(false).sort,muestraunalistaordenadadetodoslosmétodosquepertanezcanexclusivamentealosStrings,peronoalasclasesdelasquedesciende.

Losstringstienendistintosmétodosparacompararsuigualdad.Elmáscomúndeelloses==.OtrométodoesString.eql?,quedevuelveelmismoresultadoque==.YporúltimoestáString.equal?,quecompruebasidosstringssonelmismoobjeto.Veamoselsiguienteejemplo:

defcompara_strings(s1,s2,s3)

#comprobamossielcontenidoesigual

ifs1==s2

puts'Ambosstringstienenelmismocontenido'

else

puts'AmbosstringsNOtienenelmismoconenido'

end

ifs1.eql?(s2)

puts'Ambosstringstienenelmismocontenido'

else

puts'AmbosstringsNOtienenelmismoconenido'

end

=begin

ahoracomprobamossiambosobjetossoniguales:

dosobjetosdiferentes

puedentenerelmismocontenido

=end

ifs1.equal?(s2)

puts'Ambosstringssonelmismoobjeto'

Másmalabaresconstrings

Comparandodoscadenas

AprendeaprogramarconRuby

34MásMalabaresconStrings

else

puts'AmbosstringsNOsonelmismoobjeto'

end

ifs1.equal?(s3)

puts'Ambosstringssonelmismoobjeto'

else

puts'AmbosstringsNOsonelmismoobjeto'

end

end

string1='Jonathan'

string2='Jonathan'

string3=string1

compara_strings(string1,string2,string3)

Dadounstring,invertirlopalabraporpalabra(envezdeletraporletra).

SepuedeusarString.splitquenosdaunarrayformadoporlaspalabrasdelstring.LaclaseArraytieneunmétodoreverse;detalformaquepuedesrevertirelarrayantesdejuntarloparahacerunnuevostring:

palabras='TutorialdeRuby-fácil,sencilloyconfundamento'

putspalabras.split("").reverse.join("")

Ejercicio

Solución

AprendeaprogramarconRuby

35MásMalabaresconStrings

EnRuby,nilyfalsesignificanfalso,todolodemás(incluyendotrue,0)significanverdadero.EnRuby,nilesunobjeto:portanto,tienesusmétodos,yloqueesmás,puedesañadirlosmétodosquesequieran.

Veamosunejemplodeif,else:

xyz=5

ifxyz>4

puts'Lavariablexyzesmayorque4'

puts'Puedoponermásinstruccionesdentrodelif'

ifxyz==5

puts'Sepuedeanidarunbloqueif,else,enddentrodeotro'

else

puts"Partedelbloqueanidado"

end

else

puts'Lavariablexyznoesmayorque4'

puts'Tambiénpuedoponermúltiplessentencias'

end

elseseejecutabasilacondiciónenifnosecumplía.Parapodertomarmásdecisiones,enfuncióndelvalordelavariable,seusaelsif:

#usandoif,elseanidados

puts'Hola,cuálestunombre?'

STDOUT.flush

nombre=gets.chomp

puts'Hola,'+nombre+'.'

ifnombre=='Mojamuto'

puts'Pedazodenombre!!!'

else

ifname=='Enjuto'

puts'...estenombrenoesmocodepavo...'

end

end

#usandoelsif

puts'Hola,cuálestunombre?'

STDOUT.flush

nombre=gets.chomp

puts'Hola,'+nombre+'.'

ifnombre=='Mojamuto'

puts'Pedazodenombre!!!'

elsifnombre=='Enjuto'

puts'...estenombrenoesmocodepavo...'

end

#otramodificación,usandoel||("o"lógico)

Condiciones

if,else

elsif

AprendeaprogramarconRuby

36Condicionales

puts'Hola,cuálestunombre?'

STDOUT.flush

nombre=gets.chomp

puts'Hola,'+nombre+'.'

ifnombre='Mojamuto'||nombre='Enjuto'

puts'Pedazodenombre!!!'

end

Ademásdelaigualdad,existenotrosoperadorescondicionales:

operador significado

== igual

!= distinto

>= mayoroigualque

<= menoroigualque

> mayorque

< menorque

Estainstrucciónesmuyparecidaalif:secreanunaseriedecondiciones,yseejecutalaprimeracondiciónquesecumpla.Porejemplo:

xyz=10

ifxyz%2==0

puts'Lavariablexyzespar'

else

puts'Lavariablexyzesimpar'

end

esequivalentea:

xyz=10

par=case

whenxyz%2==0thentrue

whenxyz%2!=0thenfalse

end

putspar

unless

Rubytieneunaformacontrariaalif:lainstrucciónunless.Ydigocontraria,porqueenifseejecutabaelbloquedo…endsisecumplíalacondición;conunlessseejecutaráelbloquemientrasNOsecumpla.

nombre='Pepe'

unlessnombre=='Enjuto'

puts'Esenombrenotienearteninguno'

end

=begin

SielnombrenoesEnjuto,

case

AprendeaprogramarconRuby

37Condicionales

siempreseejecutaráelbloque.

=end

Escribeunmétodoquepregunteporunaño,yseacapazde:

1. Decirsies,onoesbisiesto.2. Ponerlacantidaddeminutosquetieneelaño.

Ejercicios

AprendeaprogramarconRuby

38Condicionales

Sepuedenhacerbucles(bucle=algoqueserepite)conlainstrucciónwhile:

#Loops

var=0

whilevar<10

putsvar

var+=1

end

EsteesunejemplodecómoenRubyestodounobjeto,inclusivelosnúmeros.Elmétodotimesnecesitadoscosas:

1. unnúmeroentero,delcuáleselmétodo2. unbloque

Loquehacetimesesiterarelbloqueese"número"deveces.

10.timesdo|num|

putsnum

end

Fijarse,quelavariablenumvade0a9;porlotanto,elbloqueseitera10veces.

Bucles

while

times

AprendeaprogramarconRuby

39Bucles

Rubytieneconungeneradordenúmerosaleatorios:elmétodorand.Usandorandseobtieneunnúmeroaleatoriox,talque0<=x<1.Siseledaunparámetro,porejemplorand(5),entoncesseobtieneunnúmeroenteroentre0y4(ambosincluidos).

defcarta_aleatoria

palos=%w{corazonestrebolespicasdiamantes}

numero=%w{12345678910JQK}

#Quierounacartaaleatoriaquetiene:

#-unpaloaleatorio

#-unnúmeroaleatorio

#paloaleatorio

num=palos.length

palo_aleat=rand(num)

#numeroaleatorio

num_aleat=rand(numero.length)

putsnumero[num_aleat]+'de'+palos[palo_aleat]

end

#unacartaaleatoria

carta_aleatoria

#10cartasaleatorias

10.timesdo

carta_aleatoria

end

#NOTA:lavariabledelbucle,

#comonoseusaenelbloque

#nosedefine.

Númerosaleatorios

AprendeaprogramarconRuby

40NúmerosAleatorios

Desdehacetiempoelestilodeprogramaciónfuncional(queseusaporejemploenellenguajeC)esusadoparaprogramar.Enestetipodeprogramación,hayquecentrarseenlospasospararealizarlatarea,ynosolvidamosdecomosemanejanlosdatos.Sinembargo,enlaprogramaciónorientadaaobjetos,losobjetossonlosagentes,eluniversodetuprograma:seprestaatenciónalaestructuradelosdatos.Cuandosediseñaunaclase,sepiensaenlosobjetosqueseráncreadosporesaclase:enlascosasquepodráhacereseobjeto,ylascaracterísticasquelodefinen.

Unobjetoesuncontenedordedatos,queasuvezcontrolaelaccesoadichosdatos.Asociadosalosobjetosestáunaseriedevariablesquelodefinen:susatributos.Ytambiénunconjuntodefuncionesquecreanuninterfazparainteractuarconelobjeto:sonlosmétodos.Unobjetoesunacombinacióndeestadoydemétodosquecambianeseestado.

Unaclaseesusadaparaconstruirunobjeto.Unaclaseescomounmoldeparaobjetos.Yunobjeto,unainstanciadelaclase.Porejemplo,sepuedeusarlaclaseButtonparahacerdocenasdebotones,cadabotónconsupropiocolor,tamaño,forma,…

#Nuestraprimeraclase

#definelaclasePerro

classPerro

#métodoinicializarclase

definitialize(raza,nombre)

#atributos

@raza=raza

@nombre=nombre

end

#métodoladrar

defladrar

puts'Guau!Guau!'

end

#métodosaludar

defsaludar

puts"Soyunperrodelaraza#{@raza}yminombrees#{@nombre}"

end

end

#parahacernuevosobjetos,

#seusaelmétodonew

d=Perro.new('Labrador','Benzy')

putsd.methods.sort

puts"Laiddelojbetoes#{d.object_id}."

ifd.respond_to?("correr")

d.correr

else

puts"Losiento,elobjetonoentiendeelmensaje'correr'"

end

d.ladrar

d.saludar

#conestavariable,apuntamosalmismoobjeto

d1=d

d1.saludar

d=nil

d1.saludar

ElmétodonewseusaparacrearunnuevoobjetodelaclasePerro.Losobjetossoncreadosenelmomentoyelespaciodememoriadondeseguardan,seasignaaunavariable,enestecasolavariabled,queseconocecomovariabledereferencia.

ClasesyObjetos

AprendeaprogramarconRuby

41ClasesyObjetos

Unmétodoreciéncreadonoesunespacioenblanco:unobjetoreciéncreado,puederesponderunmontóndemensajes.Paraverlalistadeesosmensajesométodosdeformaordenada(.sort):

putsd.methods.sort

Elresultadoesunalistadetodoslosmensajesométodosqueelobjetoreciéncreadopuederesponder.Detodosesosmétodos,losobject_idyrespond_to?sonimportantes.

CadaobjetoenRubytieneunúniconúmeroasociadoconél.Sepuedeverdichonúmeromedianteelmétodoobject_id.Ennuestroejemplo:

puts"Elnúmeroqueidentificaalobjetodenotadoporlavariabledes#{d.object_id}."

Sepuedeconocerdeantemano,siunobjetoserácapazderesponderaunmensaje;odichodeotraforma,siunobjetoposeeciertométodo.Paraelloseusarespond_to?.Ennuestroejemplo:

ifd.respond_to?("correr")

d.correr

else

puts"Losiento,elobjetonoentiendeelmensaje'correr'"

end

Puedessaberaquéclaseperteneceunobjetomedianteelmétodoclass.Ennuestroejemplosiponemos:

d=Perro.new('Alsatian','Lassie')

putsd.class.to_s#obtenemosPerro

instance_of?nosdevuelvetruesiunobjetoesinstanciadeunaclasedeterminada.Porejemplo:

num=10

puts(num.instance_of?Fixnum)#true

LasclasesenRubysoninstanciasdelaclaseClass.Cuandosedefineunanuevaclase(p.e.classNombreClase…end),secreaunobjetodelaclaseClassyesasignadoaunaconstante(enestecasoNombreClase).CuandoseusaNombreClase.newparaconstruirunnuevoobjeto,seusaelmétododelaclaseClassparacrearnuevasinstancias;ydespuésseusaelmétodoinicializadordelapropiaclaseNombreClase:laconstrucciónylainicializacióndeunobjetosoncosasdistintas,ypuedenmodificarse.

object_id,respond_to?

class,instance_of?

LaclaseClass

Constructoresliterales

AprendeaprogramarconRuby

42ClasesyObjetos

Significaquesepuedeusarunanotaciónespecial,envezdeusarnewparacrearunnuevoobjetodeesaclase.Lasclasesqueunconstructorliteralpuedecrear,estánenlasiguientetabla:cadavezqueusasunodeestosconstructores,creasunnuevoobjeto.

Clase ConstructorLiteral Ejemplo

String 'ó" "nuevostring"o'nuevostring'

Símbolo : :símboloo:"símboloconespacios"

Array [] [1,2,3,4,5]

Hash {} {"NuevaYor"=>"NY","Oregon"=>"OR"}

Rango ..ó… 0…10ó0..9

Expresionesregulares // /([a-z]+)/

Poresto,yaunqueavecesnoloparezca,siempreestamoscreandoobjetos.EnRuby,todoesunobjeto.

Lainstrucción:

d=nil

hacequedapunteanil,loquesignificaquenoserefiereanada.Sidespuésdeeso,añado:

Rubyd1=nilRuby

entonceselobjetoPerrodejarádeestarapuntadoporlasvariablesyseráobjetivodelrecicladodebasura.ElrecicladodebasuradeRubyesdeltipomarcar-y-borrar(mark-and-sweep):

enlafase"mark"elprogramaquereciclalamemoria,verificasielobjetoestáenuso.Siunobjetoesapuntadoporunavariable,podríaserusado,yportantoeseobjetosemarcaparaserconservado.sinohayvariablequeapuntealobjeto,entonceselobjetonoesmarcado.Yenlafase"sweep"seborranlosobjetosendesusoparaliberarmemoriademodoquepuedavolveraserutilizadaporelintérpretederuby.

Rubyusaunmark-and-sweepconservador:nohaygarantíadequeunobjetoseaeliminadoporelcolector,antesdequetermineelprograma.Sialmacenasalgoenunarray,ysemantieneelarray,tododentrodelarrayesmarcado.Sialmacenasalgoenunaconstanteovariableglobal,entoncessemarcaparasiempre.

Laideadelosmétodosdeclaseesmandarelmensajealaclase,envezdeunadesusinstancias.Losmétodosdeclaseseusanporquealgunasoperacionesquepertenecenaunaclase,nopuedenserrealizadasporsusinstancias.newesunbuenejemplo.Latareadecrearnuevosobjetossólolapuedehacerlaclase;losobjetosnopuedencrearseasímismos.

Recicladodebasura

Métodosdeclase

AprendeaprogramarconRuby

43ClasesyObjetos

Losaccesorespermitenelaccesoalosatributosdelobjeto.

#SINaccesores

classCancion

definitialize(titulo,artista)

@titulo=titulo

@artista=artista

end

deftitulo

@titulo

end

defartista

@artista

end

end

cancion=Cancion.new("Brazil","IveteSangalo")

putscancion.titulo

putscancion.artista

#CONaccesores

classCancion

definitialize(titulo,artista)

@titulo=titulo

@artista=artista

end

#accesordelectura

attr_reader:titulo,:artista

#accesordeescritura

#attr_writer:titulo

#accesordeescrituraylectura

#attr_accessor:titulo

end

cancion=Cancion.new("Brazil","IveteSangalo")

putscancion.titulo

putscancion.artista

Accesor(métodosdeacceso)

AprendeaprogramarconRuby

44Accesores

Veamoscomosepuedeleer/escribirunficheroconunejemplo:

#Abreyleeunfichero

#Seusaunbloque:elficherosecierra

#automáticamentealacabarelbloque.

File.open('fichero.txt','r')do|f1|

whilelinea=f1.gets

putslinea

end

end

#Creaunnuevofichero,yescribe

File.open('text.txt','w')do|f2|

#'\n'eselretornodecarro

f2.puts"Porquelavida\npuedesermaravillosa"

end

ElmétodoFile.openpuedeabrirelficherodediferentesformas:

'r'sólo-lectura,comienzaalprincipiodelfichero.'r+'lectura/escritura,comienzaalprincipiodelfichero.'w'sólo-escritura,creaunnuevoficherooeliminaelcontenidodelfichero,paraempezardecero.

Hayqueconsultarladocumentaciónparaverunalistacompletadelosposiblesmodos.File.openabreunnuevoficherosinohayunbloque;perosiusaunbloque,entonceselficheroseráelargumentodelbloque,ysecerraráautomáticamentecuandotermineelbloque.Sinohaybloque,elficheronosecierradeformaautomática,ysiempre,siemprehayquecerrarunfichero:enelcasodeunficheroabiertoparaescritura,sinosecierra,podríanperdersedatos.

ElmétodoreadlinedeFilecopiaelficherolíneaporlíneadentrodeunarray.Ambosmétodos,openyreadlinespertenecenalaclaseIO,delacualdesciendelaclaseFile;yportanto,sonheredados.

ElmóduloFindhaceunabúsquedadescendenteenlosdirectoriosdeunconjuntoderutas/directorios.Sielargumentoesundirectorio,entonceselresultadoseráeldirectorio,ytodoslosficherosysubdirectoriosquelepertenecen.

require'find'

#muestralaruta./

#queeseldirectoriodeRuby

Find.find('./')do|f|

type=case

#silarutaesunfichero->F

whenFile.file?(f)then"F"

#silarutaesundirectorio->D

whenFile.directory?(f)then"D"

#sinosabemosloquees->?

else"?"

end

#formateaelresultado

puts"#{type}:#{f}"

end

Ficheros:lectura/escritura

Manejandodirectorios

Accesoaleatorio

AprendeaprogramarconRuby

45Ficheros:lecturayescritura

Poraccesoaleatorio,seentiende,empezaraleerelficheroencualquierparte.Supongamos'aleatorio.rb':

aleatorio.rb

puts'SurfingUSA'Ahoraqueremosleerelficheroapartirdelapalabra"USA":

f=File.new("aleatorio.rb")

f.seek(12,IO::SEEK_SET)

printf.readline

f.close

ElmétodoseekdelaclaseIO,buscaunaposicióndadaporelprimerparámetro,delaformaindicadaporelsegundoparámetro.Lasposiblesformasson:

SEEK_CUR-busca(seek)desdeelprimerparámetro,unnúmeroentero,hastalaposiciónactual.SEEK_END-buscadesdeelparámetrodado,hastaelfinaldelfichero.SEEK_SET-buscalaposiciónabsolutadadaporelparámetro::eseloperadordealcance

Javatienelahabilidaddeserializarobjetos:tepermitealmacenarlosenunficheroyluegoreconstruirloscuandoesnecesario.Rubyllamaaestetipodeserializaciónmarshalling.

Salvarunobjetoyalgunosotodosdesuscomponentes,sehacemedianteelmétodoMarshall.dum.Después,sepuederecuperarelobjetousandoMarshall.load.Seprofundizarámásadelanteeneltema.

¿PermiteRubylaserializacióndeobjetos?

AprendeaprogramarconRuby

46Ficheros:lecturayescritura

Cuandoescribestusprimerosprogramas,setiendeaguardartodoelcódigoenunmismofichero.Peroamedidaquecrecescomoprogramador,tusprogramastambiénlohacen,yenalgúnmomentotedaráscuentaquetenerunúnicoficherocontiendotodoelcódigo,espocopráctico.Esmuchomásfácildividirelcódigoengruposycolocarcadagrupoenunfichero:unalibrería(enespañolseríabibliotecadeprogramasomódulos,nodelibros)esunficheroquecontienemétodosyclasesparasuusoaposteriori.Parapoderusarestaslibrerías,necesitasdelosmétodosrequireyload.

Elmétodorequireleeunaúnicavezelficheroespecificado:

hola.rb

puts"Holaatodos!"

Alusarvariasvecesrequire:

require'hola'#Holaatodos!

require'hola'#

require'hola'#

Sivolvemosausarlo,omitesulectura:todaslasclasesymétodosdelfichero,yaestánalmacenadosenmemoria.Portantonosahorramoseltiempodeotralectura.Hayquefijarseenundetallealahoradeusarrequire:

require'hola'#bien

requiredaporhechoquelaextensióndelficheroes.rb,buscandoelfichero'hola.rb'.Aunquenofuese.rb,Rubyseguiríabuscandoentrelasdemásextensioneshastaencontrarunficherodelnombre'hola'.

Elmétodoloadleeelficheroindicadotantasvecescomoaparezcalainstrucción.¿Difícil?Notanto,veamosunejemplo:

load'hola.rb'#Holaatodos!

load'hola.rb'#Holaatodos!

load'hola.rb'#Holaatodos!

Cadavezqueselee,todaslosmétodosdelficherosevuelvenaleer,yestándisponiblesparasuuso.Cuandoseusaloadesporqueseesperaquealgohayacambiadoenelfichero.

RAILS:enRailssesueleusarload.Porejemplo:mientrassedesarrolla,loquesignificaestarprobandolaaplicaciónyhaciendocambiosalmismotiempo,loscambiosseactualizanalreleerelfichero.Usarrequirenotendríaelmismoefecto,puestoqueelficherosehaleídounavez.

Otroejemplo

Usandolibrerías

require

load

AprendeaprogramarconRuby

47Usandolibrerías

moto.rb

classMoto

definitialize(marca,color)

#Atributos(variablesdelobjeto)

@marca=marca

@color=color

end

defarrancar

if(@estado_motor)

puts'Motorencendido'

else

@estado_motor=true

puts'Arrancandoelmotor'

end

end

end

SiahoraqueremosusarlaclaseMoto,enotrofichero:

require'moto.rb'

m=Moto.new('Yamaha','rojo')

m.arrancar

AprendeaprogramarconRuby

48Usandolibrerías

Laherenciadeclasesesunarelacciónentredosclases.Laventajadelaherenciaesquelasclasesqueenunajerarquíaestánenunnivelinferior,heredanlascaracterísticasdelasclasesdenivelessuperiores;yademás,puedenañadirsuspropiascaracterísticas.

Porejemplo:todoslosgatossonmamíferos.Sitodoslosmamíferosrespiran,laclasegatopordescenderdelaclasemamíferoheredaestacaracterística:losgatosrespiran.

Estopuedeprogramarseasí:

classMamifero

defrespirar

puts'inspirar,espirar'

end

end

#elsímbolo<indicaque

#GatoesunasubclasedeMamifero

classGato<Mamifero

defmaullar

puts'Miaaaaaaaaaaau'

end

end

cribas=Gato.new

cribas.respirar

cribas.maullar

Aunquenoseespecificóquelosgatospuedanrespirar,todoslosgatosherederánesacaracterísticadelaclaseMamifero,yaqueelgatoesunasubclasedelosmamíferos.Enelargot,Mamiferoeslasuper-claseoclasepadre,yGatoeslasubclase,oclasehija.Estoesunaventajaparaelprogramador:losgatostienenlacapacidadderespirar,sinhaberloimplementado.

EnRuby,comosemostróenesteesquema,laclaseObjecteslamadredetodaslasclasesenRuby;porlotanto,susmétodosestándisponiblesentodoslosobjetos,exceptoaquellosquesehansobrescrito.

Habrásituacionesdondelaspropiedadesdeunasuper-clasenodeberíanserheredadasporunasubclaseenparticular.Porejemplo,lasavesgeneralmentesabenvolar,perolospingüinossonunasubclasedeAve,ynovuelan:

classAve

defasear

puts'Meestoylimpiandomisplumas.'

end

defvolar

puts'Estoyvolando.'

end

end

classPinguino<Ave

defvolar

puts'Losiento,nosoycapazdevolar.'

end

end

Herenciadeclases

Sobrescriturademétodos(methodoverriding)

AprendeaprogramarconRuby

49Herenciadeclases

p=Pinguino.new

p.asear

p.volar

Sehasobrescritoelmétodovolar.Lagranventajaqueaportaelusodelaherenciadeclases,sellamaprogramacióndiferencial:vamosdelomásgeneralalomásparticular,añadiendoymodificandodondeseanecesario.

Losdosejemplosanterioressontraduccionesdelaguíaonline"RubyUser'sGuide".

classBicicleta

attr_reader:marchas,:ruedas,:asientos#sehablarádeattr_reader

definitialize(marchas=1)

@ruedas=2

@asientos=1

@marchas=marchas

end

end

classTandem<Bicicleta

definitialize(marchas)

super

@asientos=2

end

end

t=Tandem.new(2)

putst.marchas

putst.ruedas

putst.asientos

b=Bicicleta.new

putsb.marchas

putsb.ruedas

putsb.asientos

Cuandounousasuperdentrodeunmétodo,Rubymandaunmensajealaclasemadredelobjetoalquepertenceelmétodo,buscandounmétodoconelmismonombre.Si:

seinvocaconunalistavacíadeargumentos(comoestecaso),superósuper(),nosepasanargumentosalmétododelaclasemadre.seinvocaconargumentos,super(a,b,c),semandandlosargumentosa,b,c.

Enestecaso,seusasuperenelmétodoinitializedeTandem,loqueprovocaelusodelinitializedeBicicletaparacrearinstanciasdeTandem.Lasalidaes:

2

2

2

1

2

1

RAILS:laherenciadeclasesesunadelasclaveseneldesarrollodeRAILS

Super

AprendeaprogramarconRuby

50Herenciadeclases

EnRuby,lasclasesnuncaestáncerradas:siempresepuedenañadirmétodosaunaclase.Estoesválidotantoparalasclasesqueescribas,comoparalasqueyaestánincluidasconelintérprete.Todoloquehayquehacer,escontinuarconladefinicióndelaclase:

require'moto'

m=moto.new('Yamaha','rojo')

m.arrancar

classMoto

definforme_moto

puts'Elcolordelamotoes'+@color

puts'Lamarcadelamotoes'+@marca

end

end

m.informe_moto

AhoraañadamosunmétodoalaclaseString:

classString

defnum_caracteres

putsself.size

end

end

texto='Cieloempedrado,suelomojado'

texto.num_caracteres

Siseescribeunnuevométodoqueconceptualmentepertenecealaclaseoriginal,sepuedereabrirelficherodelaclase,yañadirelmétodoaladefinicióndelaclase.Estohayquehacerlocuandoelmétodoesdeusofrecuente,yseestáseguroquenoentraráenconflictoconotrosmétodosdefinidosenotraslibreríasqueseusenmásadelante.

Sielmétodonoseráusadofrecuentemente,onosequieretomarelriesgodemodificarlaclasedespuésdesucreación,crearunasubclase(verHerencia)eslamejoropción.Unaclasepuedesobrescribirlosmétodosdelaclasedelaquedesciende.Yesmásseguro,porquelaclaseoriginalpermaneceintacta.

LasclasesenRubysólopuedentenerunmétodoconunnombredado.Paratenermétodos"distintos"conelmismonombre,sepuedejugarconelnúmerodeargumentos:

#Uncuadradosepuededefinirdedosformas:

#Cuadrado.new([x_sup,y_izq],ancho,alto)

#Cuadrado.new([x_sup,y_izq],[x_inf,y_der])

classCuadrado

definitialize(*args)#*implicanúmerovariabledeargumentos

ifargs.size<2||args.size>3

puts'ERROR:Estemétodotomadosotresargumentos'

else

ifargs.size==2

puts'Dosargumentos'

else

puts'Tresargumentos'

end

end

Modificandoclases

Sobrecargademétodos(methodsoverloading)

AprendeaprogramarconRuby

51Modificandoclases

end

end

Cuadrado.new([10,23],4,10)#Tresargumentos

Cuadrado.new([10,23],[14,13])#Dosargumentos

Cuadrado.new([10,23],[14,13],4,10)#ERROR:Estemétodotomadosotresargumentos

Elprogramaestáincompleto,peroessuficienteparavercómosepuedeconseguirlasobrecargademétodos.

AprendeaprogramarconRuby

52Modificandoclases

Losobjetosinmutablessonaquellosquenopuedencambiardeestadodespuésdesercreados.Laspropiedadesporlasquedestacanson:

serthread-safe.Losthreadsnopuedencorromperloquenopuedencambiar.facilitarelimplementarlaencapsulación:sipartedelestadodeunobjetoesalmacenadodentrounobjetoinmutable,entonceslosmétodosmodificadorespuedenleerelestadodedichoobjeto,sinmiedoaquemodifiquensuestado.seríndicesenloshashesinmutables,yaquenopuedencambiar.

EnRuby,lamutabilidadesunapropiedaddelosobjetos,nodeunaclaseentera.Cualquierobjeto(oinstancia)sepuedevolverinmutableusandofreeze.

Elmétodofreeze(congelar)evitaqueunobjetopuedamodificarse,convirtiéndoloenunaconstante.Despuésde"congelar"elobjeto,cualquierintentodemodificarlodacomoresultadounTypeError.

str='Unsimplestring'

str.freeze#congelamoselstring

#seintentamodificar(begin)

#yencasodeerror(rescue)

#selanzaunmensaje.VerExcepciones.

begin

str<<'Intentodemodificarlo'

rescue=>err

puts"#{err.class}#{err}"

end

Sinembargo,freezefuncionaconlasreferencias,noconlasvariables:estosignificaquesicreamosunobjetonuevo,ysobreescribimoslavariable,estesepodrámodificar:

str='stringoriginal-'

str.freeze

str+='añadidoaposteriori'

putsstr

Elobjetooriginalnocambió.Sinembargo,lavariablestrserefiereaunnuevoobjeto.Elmétodofrozen?nosdicesiunobjetoestácongeladoono.

Congelandoobjetos

freeze

Lasalidaes-TypeErrorcan'tmodifyfrozenstring.

Lasalidaes-'Originalstring-añadidoaposteriori'

AprendeaprogramarconRuby

53Congelandoobjetos

Javaescapazdeserializarobjetos:puedealmacenarlos,paraluegoreutilizarloscuandoseanecesario.Rubytienetambiénestacapacidad,perolallamamarshaling.Veamosunejemploenelqueapartirdeunaclase,creamosunaseriedeobjetosquealmacenamosyluegorecuperamos:

Laclase"personaje.rb":

classPersonaje

definitialize(vida,tipo,armas)

@vida=vida

@tipo=tipo

@armas=armas

end

attr_reader:vida,:tipo,:armas

end

CreamoslosobjetosylosguardamosenunficherousandoMarshal.dump:

require'personaje'

p1=Personaje.new(120,'Mago',['hechizos','invisibilidad'])

putsp1.vida.to_s+''+p1.tipo+''

p1.armas.eachdo|w|

putsw+''

end

File.open('juego','w+')do|f|

Marshal.dump(p1,f)

end

UsamosMarshal.loadpararecuperarlos:

require'personaje'

File.open('juego')do|f|

@p1=Marshal.load(f)

end

puts@p1.vida.to_s+''+@p1.tipo+''

@p1.armas.eachdo|w|

putsw+''

end

Marshalúnicamenteserializaestructurasdedatos;nopuedeserializarcódigo(comohacenlosobjetosProc),orecursosutilizadosporotrosprocesos(comoconexionesabasesdedatos).Marshaldaunerrorcuandoseintentaserializarunfichero.

SerializandoObjetos

AprendeaprogramarconRuby

54Serializandoobjetos

EnRuby,laúnicaformadecambiarelestadodeunobjeto,esinvocandounodesusmétodos:sicontrolaselaccesoalasométodos,controlaráselaccesoalosobjetos.Unabuenaregla,escerrarelaccesoalosmétodosquepuedandejaralobjetoenunestadonoválido.

public-losmétodospúblicos(public)puedenserusadosporcualquiera;nohayuncontroldeacceso.protected-losmétodosprotegidos(protected)puedenserusadosúnicamenteporobjetosdelamismaclaseysubclases,alasqueperteneceelmétodo;peronuncaporelpropioobjeto.Porasídecirlo,elmétodosólolopuedenusarlosotrosmiembrodelafamilia.private-losmétodosprivados(private)sólopuedenserusadoporelpropioobjeto.Técnicamente,sedicequeelreceptordelmétodosiempreeselmismo:self.Elcontroldeaccesosedeterminadinámicamente,amedidaqueelprogramatranscurre.Seobtieneunaviolacióndeaccesosiemprequeseintentaejecutarunmétodonopúblico.

classControlAcceso

defm1#estemétodoespúblico

end

protected

defm2#estemétodoesprotegido

end

private

defm3#estemétodoesprivado

end

defm4

end

end

ca=ControlAcceso.new

ca.m1

ca.m2

ca.m3

Laprivacidaddelosmétodos,tambiénsepuedenespecificardeestaforma:

classControlAcceso

defm1#estemétodoespúblico

end

defm2#estemétodoesprotegido

end

defm3#estemétodoesprivado

end

defm4#estemétodoesprivado

public:m1

protected:m2

private:m3,:m4

end

ca=ControlAcceso.new

ca.m1

ca.m2

ca.m3

Talvezelniveldeaccesoprotegido(protected)seaunpocoliosodeentender.Esmejorverloconunejemplo:

ControldeAccesoyAccesores

Lostresnivelesdeacceso

protected

AprendeaprogramarconRuby

55Controldeacceso

classPersona

definitialize(edad)

@edad=edad

end

defedad

@edad

end

defcomparar_edad(op)#op=otrapersona

ifop.edad>edad

'Laedaddelaotrapersonaesmayor.'

else

'Laedaddelaotrapersonaeslamismaomenor.'

end

end

protected:edad

end

pedro=Persona.new(15)

almudena=Persona.new(17)

putsPedro.comparar_edad(almudena)#Laedad...esmayor

Elobjetoquehacelacomparación(pedro)necesitapreguntaralotroobjeto(almudena)suedad,loquesignificaqueejecutesumétodoedad.Poresoelniveldeaccesoesprotegidoynoprivado:alestarprotegidopedropuedeusarelmétododealmudena.

Laexcepciónvienecuandopedrosepreguntaasímismolaedad,porserunmétodoprotegido,estonoseráposible.selfnopuedeserelreceptordeunmétodoprotegido.

Porejemplo:

putsPedro.edad#daerror

AprendeaprogramarconRuby

56Controldeacceso

UnaexcepciónesuntipoespecialdeobjetodelaclaseException.Lanzarunaexcepciónsignificapararlaejecucióndeunprogramaparasalirdelmismooparatratarconelproblemaquesehaproducido.Paratratarelproblemahacefaltaraise;denoserasí,elprogramaterminayavisadelerror.Loqueharáraise(lanzar),serálanzaruna"excepción"paramanejarelerror.Rubytieneunaseriedeclases,Exceptionysushijas,queayudanamanejarloserroresquepuedenocurrir.

deflanzar_excepcion

puts'Estoyantesdelraise'

raise'Sehaproducidounerror'#lanzaunaexcepciónconelmensajeentre''

puts'Estoydespuesdelraise'

end

lanzar_excepcion

ElmétodoraiseprocededelmóduloKernel.Pordefecto,raisecreaunaexcepcióndelaclaseRuntimeError.Paralanzarunaexcepcióndeunaclaseespecífica,sepuedeponerelnombredelaclasecomoargumentoderaise.

definverse(x)

raiseArgumentError,'Elargumentonoesnumerico'unlessx.is_a?Numeric

1.0/x

end

putsinverse(2)

putsinverse('patata')#daunerrorqueesmanejadoporraise

Hayquerecordarquelosmétodosqueactúancomopreguntas,selesponeun?alfinal:is_a?preguntaalobjetocuálessutipo.Yunlesscuandoseponealfinaldeunainstrucción,significaqueNOseejecutacuandolaexpresiónacontinuaciónesverdadera.

Paratratarunaexcepción,seponeelmétodoquepuedecausarelerrordentrodeunbloquebegin…end.Dentrodeestebloque,sepuedenponervariosrescueparacadatipodeerrorquepuedasurgir:

defraise_and_rescue

begin

puts'Estoyantesdelraise'

raise'Unerrorhaocurrido'#simulamosunerror

puts'Estoydespuésdelraise'

rescue

puts'Estoyrescatadodelerror.'

end

puts'Estoydespuésdelbloque'

end

raise_and_rescue

Lasalidaes:

Estoyantesdelraise

Estoyrescatadodelerror.

Estoydespuésdelbloque

Excepciones

Manejandounaexcepción

AprendeaprogramarconRuby

57Excepciones

Observarqueelcódigointerrumpidoporlaexcepción,nuncaseejecuta.Unavezquelaexcepciónesmanejada(porelrescue),laejecucióncontinúainmediatamentedespuésdelbloquebeginfuentedelerror.

Alescribirrescuesinparámetros,elparámetroStandardErrorsetomapordefecto.Encadarescuesepuedenponervariasexcepcionesatratar.Enelcasodeponermúltiplesrescues:

begin

#

rescueUnTipoDeExcepcion

#

rescueOtroTipoDeExcepcion

#

else

#Otrasexcepciones

end

Rubycomparalaexcepciónqueproduceelerror,concadarescuehastaqueseadelmismotipo;oseaunasuperclasedelaexcepción.Silaexcepciónnoconcuerdaconningúnrescue,usarelseseencargademanejarla.

Parasaberacercadeltipodeexcepción,hayquemapearelobjetoExceptionaunavariableusandorescue:

begin

raise'Testdeexcepcion'

rescueException=>e

putse.message#Testdeexcepción

putse.backtrace.inspect#["nombredefichero:lineadelaexcepción"]

end

Siademásdemanejarlaexcepción,senecesitaqueseejecuteuncódigo,seusarálainstrucciónensure:loquehayaenesebloque,siempreseejecutarácuandoelbloquebegin…endtermine.

Heaquíalgunasexcepcionesmáscomunes,conlacausaquelasoriginayunejemplo:

RuntimeError-laexcepciónqueselanzapordefecto.Ejemplo:

raise

NoMethodError-elobjetonopuedemanejarelmensaje/métodoqueseleenvía.Ej:

string='patata'

string.multiplicarse

NameError-elintérpreteencuentraunidentificadorquenopuederesolvernicomométodo,nicomovariable.Ej:

a=variable_sin_definir

IOError-lecturadeunstreamcerrado,escribiraunsistemadesólolecturayoperacionesparecidas.Ej:

STDIN.puts("NoescribasaSTDIN!")

Excepcionesmáscomunes

AprendeaprogramarconRuby

58Excepciones

Errno::error-erroresrelaccionadoconelficheroIO.Ej:

File.open(-12)

TypeError-unmétodorecibeunargumentoquenopuedemanejar.Ej:

a=3+"nopuedosumarunstringaunnúmero!"

ArgumentError-causadoporunnúmeroincorrectodeargumentos.Ej:

defm(x)

end

m(1,2,3,4,5)

begin

#Abreelficheroylolee

File.open('origen.txt','r')do|f1|

whileline=f1.gets

putsline

end

end

#Creaunnuevoficheroyescribeenél

File.open('destino.txt','w')do|f2|

f2.puts"CreadoporSatish"

end

rescueException=>msg

#disponeelmensajedeerror

putsmsg

end

Ejemplo

AprendeaprogramarconRuby

59Excepciones

AprendeaprogramarconRuby

60Módulos

ConstantesUnaconstanteesunareferenciainmutableaunobjeto;mientrasquelasvariablessísepodían.Lasconstantessecreancuandosonasignadasporprimeravez.EnlaactualversióndeRuby,reasignarunaconstante(intentarcambiarsuvalor)generaunaadvertencia,peronounerror.

Lasconstantesseponenenmayúsculas:

CONST=10

CONST=20

Lasconstantesdefinidasdentrodeunaclaseomódulopuedenserusadasencualquierlugardentrodelaclaseomódulo.Fueradelaclaseomódulo,sepuedenusarmedianteelopoerador::precedidodeunapalabraqueindiqueelmódulooclaseapropiados.Lasconstantesdefinidasfueradecualquierclaseomódulopuedenserusadasmedianteeloperador::perosinpalabraquelopreceda.Lasconstantesnopuedenserdefinidasdentrodeunmétodo.

CONST_EXTERNA=99

classConst

CONST=CONST_EXTERNA+1

defget_const

CONST

end

end

putsConst.new.get_const#100

putsConst::CONST#constantedentrodelaclaseConst

puts::CONST_EXTERNA#constanteexternaatodaclase

putsConst::NEW_CONST=123

#losnombresdelasvariablesymétodosempiezanporminúsculas

$glob=5#lasvariablesglobalesempiezanpor$

classTestVar#nombredeclase,empiezapormayúsculas

@@cla=6#lasvariablesdeclaseempiezanpor@@

CONST_VAL=7#constante:todomayúsculasy/o_

definitialize(x)#constructor

@inst=x#variablesdeobjetoempiezanpor@

@@cla+=1#cadaobjetocomparte@@cla

end

defself.cla#métododeclase,lectordeatributo

@@cla

end

defself.cla=(y)#métododeclase,modificadordeatributo"0@%0@@cla=y

end

definst#métododeobjeto,lector

@inst

end

definst=(i)#métododeobjeto,modificador

@inst=i

end

end

puts$glob

test=TestVar.new(3)

Alcancedelasconstantes

Repasoalostiposdevariables

AprendeaprogramarconRuby

61Constantes

putstest.inspect#daelIDdelobjetoysusvariables

TestVar.cla=4

test.inst=8

putstest.inst

putsTestVar.cla

otro=TestVar.new(17)

#'cla'semodificacadavez

#quesecreaunobjeto

putsTestVar.cla

putsotro.inspect

AprendeaprogramarconRuby

62Constantes

Unsímbolopareceunavariable,peroestáprecedidodedospuntos.Ejemplos:

:action

:line_tines

Losdospuntossepuedeninterpretarcomo"lacosallamada".Entonces:id,seinterpretacomo"lacosallamadaid".Lossímbolosnocontienenvalorescomolasvariables.Unsímboloesunaetiqueta,unnombre,nadamás.

UnsímboloeselobjetomásbásicoquepuedescrearenRuby:esunnombreyunaIDinterna.Lossímbolossonútilesporquedadounsímbolo,serefierealmismoobjetoentodoelprograma.Porlotanto,sonmáseficientesquelosstrings:dosstringsconelmismonombre,sondosobjetosdistintos.Estoimplicaunahorradetiempoymemoria.

puts"hola".object_id#21066960

puts"hola".object_id#21066730

puts:hola.object_id#132178

puts:hola.object_id#132178

Cadavezquesehausadounstring,sehacreadounobjetonuevo.Portanto,¿cuándousarunstring,ycuándounsímbolo?

Sielcontenidodelobjetoesloimportante,usaunstring.Silaidentidaddelobjetoesimportante,usaunsímbolo.

Rubyusaunatabladesímbolosinternaconlosnombresdelasvariables,objetos,métodos,clases…Porejemplo,sihayunmétodoconelnombredecontrol_movie,automáticamentesecreaelsímbolo:control_movie.ParaverlatabladesímbolosSymbol.all_symbols.

Comoveremosacontinuación,lossímbolossonparticularmenteútilesparaloshashes.

Hashes,tambiénconocidoscomoarraysasociativos,mapasodiccionarios,sonparecidosalosarraysenquesonunacolecciónindexadadereferenciasaobjetos.Sinembargo,mientrasqueenlosarrayslosíndicessonnúmeros,enloshashessepuedeindexarconobjetosdecualquiertipo:strings,expresionesregulares,etc.

Cuandosealmacenaunvalorenunarray,sedandosobjetos:elíndiceyelvalor.Aposteriorisepuedeobtenerdichovalor,graciasalíndice.

h={'perro'=>'canino','gato'=>'felino','burro'=>'asno',12=>'docena'}

putsh.length#4

putsh['perro']#'canino'

putsh

putsh[12]

Comparadosconlosarrays,tenemosunaventajasignificativa:sepuedeusarcualquierobjetocomoíndice.Sinembargo,

HashesySímbolos

SímbolosvsStrings

Hashes

AprendeaprogramarconRuby

63HashesySímbolos

suselementosnoestánordenados,yesfácilusarunhashcomounapilaocola.

Loshashestienenunvalorpordefecto.Estevalorsedevuelvecuandoseusaníndicesquenoexisten:elvalorquesedevuelvepordefectoesnil.

LaclaseHashtienemuchosmétodosquesepuedenveraquí.

Porlasventajasantescitadas,seusanlossímboloscomoíndices:

persona=Hash.new

persona[:nombre]='Pedro'

persona[:apellido]='Picapiedra'

putspersona[:nombre]

queesequivalentea:

persona={:nombre=>'Pedro',:apellido=>'Picapiedra'}

putspersona[:apellido]

Lossímboloscomoíndices

AprendeaprogramarconRuby

64HashesySímbolos

LaclaseTimeenRubytieneunextraordinariométodoparaformatearsuresultado,queesdegranutilidadalahoraderepresentarlahoradedistintasformas.LaclaseTimedeRubycontieneuninterfaceparamanejardirectamentelaslibreríasescritasCsobrelashoras.

ElcerodelostiemposparaRuby,eselprimersegundoGMTdel1deEnerode1970.Estopuedetraerproblemasalahoraderepresentarinstantesanterioresaesecero.LaclaseDateTimeessuperioraTimeparaaplicacionesastronómicasohistóricas;sinembargo,paralasaplicacionesnormales,conusarTimeessuficiente.

t=Time.now

putst.strftime("%d/%m/%Y%H:%M:%S")

#strftime-formateartiempo(stringfytime)

#%d-día(day)

#%m-mes(month)

#%Y-año(year)

#%H-horaenformato24horas(hour)

#%M-minuto

#%S-segundo(second)

putst.strftime("%A")

putst.strftime("%B")

#%A-díadelasemana

#%B-mesdelaño

putst.strftime("sonlas%H:%M%Z")

#%Z-zonahoraria

LaclaseTime

AprendeaprogramarconRuby

65LaclaseTime

Encadainstantedelaejecucióndelprograma,hayunoysólounself:elobjetoqueseestáusandoeneseinstante.

Elcontextodelnivelsuperiorseproducesinosehaentradoenotrocontexto,porejemplo,ladefinicióndeunaclase.Porlatanto,eltérmino"nivelsuperior"serefierealcódigoescritofueradelasclasesomódulos.Siabresunficherodetextoyescribes:

x=1

habráscreadounavariablelocalenelnivelsuperior.Siescribes:

defm

end

habráscreadounmétodoenelnivelsuperior:unmétodoquenoesdefinidocomounmétododeunaclaseomódulo.Sinadamásarrancarelintérprete,tecleas:

putsself

Larespuestaesmain,untérminoqueserefierealobjetoquesecreaaliniciarelintérprete.

Enunaclaseodefinicióndemódulo,selfeslaclaseoelmóduloalqueperteneceelobjeto:

classS

puts'ComenzólaclaseS'

putsself

moduleM

puts'MóduloanidadoS::M'

putsself

end

puts'DeregresoenelnivelmássuperficialdeS'

putsself

end

Lasalidaes:

ComenzólaclaseS

S

MóduloanidadoS::M

S::M

DeregresoenelnivelmássuperficialdeS

S

self

Contextodelnivelsuperior

selfdentrodeclasesymódulos

AprendeaprogramarconRuby

66self

classS

defm

puts'ClaseS,metodom:'

putsself#<S:0x2835908>

end

end

s=S.new

s.m

selfdentrodelosmétodos

AprendeaprogramarconRuby

67self

Aestasalturas,tehabrásdadocuentadequeenRubynosedeclaranlostiposdevariablesométodos:todoesunobjeto.LosobjetosenRubypuedensermodificados:siempresepuedenañadirmétodosaposteriori.Porlotanto,elcomportamientodelobjeto,puedealejarsedeaquelsuministradoporsuclase.

EnRuby,nosfijamosmenoseneltipo(oclase)deunobjetoymásensuscapacidades.DuckTypingserefierealatendenciadeRubyacentrarsemenosenlaclasedeunobjeto,ydarprioridadasucomportamiento:quémétodossepuedenusar,yquéoperacionessepuedenhacerconél.

Sellama"DuckTyping"porqueestábasadoenelTestdelPato(DuckTest):

Sicaminacomounpato,nadacomounpatoyhace"quack",podemostratarlocomounpato.JamesWhitcombRiley

Veamoselsiguienteejemplo:

#Comprobamosquéobjetosrespondenalmétodot_str

puts('Unacadena'.respond_to?:to_str)#=>true

puts(Exception.new.respond_to?:to_str)#=>true

puts(4.respond_to?:to_str)#=>false

Esteejemplo,esunaformasimpledelafilosofía"patotyping":siunobjetohacequackcomounpato(oactúacomounstring),puestrátalocomounpato(ounacadena).Siemprehayquetrataralosobjetosporloquepuedenhacer,mejoerquehacerloporlasclasesdelasqueprocedenolosmódulosqueincluyen.

Lasexcepciones(Exceptions)sonuntipodestringquetieneninformaciónextraasociadaconellas.Sinembargo,aunqueellasnosonunasubclasedeString,puedensertratadascomotales.

classPato

defquack

'Quack!'

end

defnadar

'Paddlepaddlepaddle...'

end

end

classGanso

defhonk

'Honk!'#onomatopiadeunpato

end

defnadar

'Splashsplashsplash...'

end

end

classGrabadoraDePatos

defquack

play

end

defplay

'Quack!'

end

end

DuckTyping

¡Tratémosloscomopatos!

AprendeaprogramarconRuby

68DuckTyping

#Enestemétodo,laGrabadora

#secomportacomounPato

defhaz_quack(pato)

pato.quack

end

putshaz_quack(Pato.new)

putshaz_quack(GrabadoraDePatos.new)

#Paraestemétodo,elGanso

#secomportacomounPato

defhaz_nadar(pato)

pato.nadar

end

putshaz_nadar(Pato.new)

putshaz_nadar(Ganso.new)

AprendeaprogramarconRuby

69DuckTyping

Algunosdelospatronesdeprogramaciónserepitentantoqueloslenguajesdeprogramaciónincluyenformassintácticasquesonabreviacionesparaestospatrones.Elúnicoobjetivodeestasabreviacionesesbrindarunmecanismoparaescribirmenoscódigo.Eselazúcarsintático.

Porejemplo,alahoradecambiarunatributo:

classPerro

definitialize(raza)

@raza=raza

end

attr_reader:raza,:nombre#lector

#métodomodificador

defset_nombre(nm)

@nombre=nm

end

end

pe=Perro.new('Doberman')

pe.set_nombre('Benzy')

putspe.nombre

Rubypermitedefinirmétodosqueterminanen=

defnombre=(nm)

@nombre=nm

end

#usandoelnuevométodo

nombre=('Benzy')

#losparéntesissonopcionales,

#siesunsóloargumento

nombre='Benzy'

siempleamos"esteazúcar"enelejemplo:

classPerro

definitialize(raza)

@raza=raza

end

attr_reader:raza,:nombre#lector

#modificador

defnombre=(nb)

@nombre=nb

end

end

pe=Perro.new('Doberman')

#pe.nombre=('Benzy')

pe.nombre='Benzy'

putspe.nombre

Elsignoigualesunaformafamiliardeasignarunvalor;ademásquenosahorramosponerlosparéntesis.

RAILS:elusodelsignoigual,deformasimilaralavista,escomúnenRails.

AzúcarSintáctico

AprendeaprogramarconRuby

70AzúcarSintáctico

Eltestdeunidadesesunmétodoparatestearelcódigoenpequeñostrozos.

Significaquenuncatendráselproblemadecrearunerrormientrassolucionasotro.Significaquenotendrásqueejecutartuprogramayjugarconél(loqueeslento)paraarreglarloserrores.Eltesteodeunidadesesmuchomásrápidoqueel"testeomanual".Conociendocómousarlasunidadesdetest,abreelmundoalDesarrolloGuiadoporPruebas(TestDrivenDevelopment,TDD).

Cargarlabibliotecatest/unitHacerquelaclaseatestearseaunasubclasedeTest::Unit::TestCaseEscribirlosmétodosconelprefijotest_Afirmar(assert)lascosasquedecidasqueseanciertas.Ejecutarlostestsycorregirloserroreshastaquedesaparezcan.

require'test/unit'

classMiPrimerTest<Test::Unit::TestCase

deftest_de_verdad

asserttrue

end

end

Cadaafirmación,esunmétodoheredadodelaclaseTest::Unit::TestCase:Hayqueecharunojoallistadodelasposiblesafirmaciones(asserts)quepodemoscomprobar.

Supongamosquequeremosescribirunaclasesencilla,Mates,queimplementeoperacionesaritméticasbásicas.Queremoshacerdistintostestsparacomprobarquelasuma,laresta,elproductoyladivisiónfuncionan.

require'mates'

require'test/unit'

classTestDeMates<Test::Unit::TestCcase

deftest_suma

assert_equal4,Mates.run("2+2")

assert_equal4,Mates.run("1+3")

assert_equal5,Mates.run("5+0")

assert_equal0,Mates.run("-5+5")

end

deftest_resta

assert_equal0,Mates.run("2-2")

assert_equal1,Mates.run("2-1")

assert_equal-1,Mates.run("2-3")

end

end

Testdeunidades

¿Porqué?

Requisitos

Ejemplo

AprendeaprogramarconRuby

71Testdeunidades

Siejecutamoselprograma,apareceránsietepuntos…….Cada.esuntestquesehaejecutado,EesunerrorycadaFunfallo.

Started

.......

Finishedin0.015931seconds.

7tests,13assertions,0failures,0errors

Ademásdelostestspositivos,tambiénsepuedenescribirunidadesdetestsnegativasintentandoromperelcódigo.EstopuedeincluireltesteoparaexcepcionesquesurgandeusarentradascomoMates.run("a+2")oMates.run("4/0").

deftest_para_no_numericos

assert_raises(ErrorNoNumerico)do

Mates.run("a+2")

end

end

deftest_division_por_cero

assert_raises(ErrorDivisionPorZero)do

Mates.run("4/0")

end

end

Algunasvecesnecesitamosqueocurrancosasantesydespuésdecadatest.Losmétodossetupyteardownsontuscompañerosenestaaventura.Cualquiercódigoescritoensetupseráejecutadoantesdelcódigo,yelcódigoescritoenteardownseráejecutadoaposteriori.

Siestásescibiendotestsparatodotucódigo(comodeberíaser),elnúmerodeficherosatestearempiezaacrecer.Unacosaquepuedefacilitartelavida,esautomatizarlostests,yrakeeslaherramientaparaestetrabajo.

fichero_rake

require'rake'

require'rake/testtask'

task:default=>[:test_units]

desc"Ejecutandolostests"

Rake::TestTask.new("test_units"){|t|

t.pattern='test/*_test.rb'#buscalosficherosacabadosen'_test.rb'

t.verbose=true

t.warning=true

}

Básicamente,unfichero_rakedefinelastareasquerakepuedehacer.Enelfichero_rake,latareapordefecto(laquesucedecuandoseejecutarakeenundirectorioconunfichero_rakeenél)esconfiguradahacialatareatests_units.Enlatareatests_units,rakeesconfiguradoparabuscarficheroseneldirectorioqueterminenen_test.rbylosejecute.Resumiendo:puedesponertodoslostestsenundirectorioydejarquerakehagaeltrabajo.

Unidadesdetestnegativas

Automatizandotests:setup,teardownyrake

AprendeaprogramarconRuby

72Testdeunidades