Aprende a Programar Con Ruby

72

description

guia para aprender a programar con el lenguaje RUBY

Transcript of Aprende a Programar Con Ruby

Page 1: Aprende a Programar Con Ruby
Page 2: 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

Page 3: Aprende a Programar Con Ruby

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

AprendeaprogramarconRuby

3Introduction

Page 4: Aprende a Programar Con Ruby

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?

Page 5: Aprende a Programar Con Ruby

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?

Page 6: Aprende a Programar Con Ruby

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

Page 7: Aprende a Programar Con Ruby

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

Page 8: Aprende a Programar Con Ruby

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

Page 9: Aprende a Programar Con Ruby

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

Page 10: Aprende a Programar Con Ruby

** 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

Page 11: Aprende a Programar Con Ruby

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

Page 12: Aprende a Programar Con Ruby

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

Page 13: Aprende a Programar Con Ruby

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

Page 14: Aprende a Programar Con Ruby

=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

Page 15: Aprende a Programar Con Ruby

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

Page 16: Aprende a Programar Con Ruby

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

Page 17: Aprende a Programar Con Ruby

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

Page 18: Aprende a Programar Con Ruby

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

Page 19: Aprende a Programar Con Ruby

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

Page 20: Aprende a Programar Con Ruby

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

Page 21: Aprende a Programar Con Ruby

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

Page 22: Aprende a Programar Con Ruby

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

Page 23: Aprende a Programar Con Ruby

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

Page 24: Aprende a Programar Con Ruby

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

Page 25: Aprende a Programar Con Ruby

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

Page 26: Aprende a Programar Con Ruby

[12,23,456,123,4579]

AprendeaprogramarconRuby

26Arrays

Page 27: Aprende a Programar Con Ruby

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

Page 28: Aprende a Programar Con Ruby

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

Page 29: Aprende a Programar Con Ruby

end

metod1hola

Lasalidaes:

Principiodelmetodo

Hola

Finaldelmetodo

AprendeaprogramarconRuby

29Bloques

Page 30: Aprende a Programar Con Ruby

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

Page 31: Aprende a Programar Con Ruby

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

Page 32: Aprende a Programar Con Ruby

\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

Page 33: Aprende a Programar Con Ruby

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

Page 34: Aprende a Programar Con Ruby

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

Page 35: Aprende a Programar Con Ruby

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

Page 36: Aprende a Programar Con Ruby

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

Page 37: Aprende a Programar Con Ruby

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

Page 38: Aprende a Programar Con Ruby

siempreseejecutaráelbloque.

=end

Escribeunmétodoquepregunteporunaño,yseacapazde:

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

Ejercicios

AprendeaprogramarconRuby

38Condicionales

Page 39: Aprende a Programar Con Ruby

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

Page 40: Aprende a Programar Con Ruby

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

Page 41: Aprende a Programar Con Ruby

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

Page 42: Aprende a Programar Con Ruby

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

Page 43: Aprende a Programar Con Ruby

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

Page 44: Aprende a Programar Con Ruby

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

Page 45: Aprende a Programar Con Ruby

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

Page 46: Aprende a Programar Con Ruby

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

Page 47: Aprende a Programar Con Ruby

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

Page 48: Aprende a Programar Con Ruby

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

Page 49: Aprende a Programar Con Ruby

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

Page 50: Aprende a Programar Con Ruby

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

Page 51: Aprende a Programar Con Ruby

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

Page 52: Aprende a Programar Con Ruby

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

Page 53: Aprende a Programar Con Ruby

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

Page 54: Aprende a Programar Con Ruby

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

[email protected]_s+''[email protected]+''

@p1.armas.eachdo|w|

putsw+''

end

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

SerializandoObjetos

AprendeaprogramarconRuby

54Serializandoobjetos

Page 55: Aprende a Programar Con Ruby

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

Page 56: Aprende a Programar Con Ruby

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

Page 57: Aprende a Programar Con Ruby

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

Page 58: Aprende a Programar Con Ruby

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

Page 59: Aprende a Programar Con Ruby

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

Page 60: Aprende a Programar Con Ruby

AprendeaprogramarconRuby

60Módulos

Page 61: Aprende a Programar Con Ruby

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

Page 62: Aprende a Programar Con Ruby

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

Page 63: Aprende a Programar Con Ruby

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

Page 64: Aprende a Programar Con Ruby

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

Page 65: Aprende a Programar Con Ruby

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

Page 66: Aprende a Programar Con Ruby

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

Page 67: Aprende a Programar Con Ruby

classS

defm

puts'ClaseS,metodom:'

putsself#<S:0x2835908>

end

end

s=S.new

s.m

selfdentrodelosmétodos

AprendeaprogramarconRuby

67self

Page 68: Aprende a Programar Con Ruby

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

Page 69: Aprende a Programar Con Ruby

#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

Page 70: Aprende a Programar Con Ruby

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

Page 71: Aprende a Programar Con Ruby

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

Page 72: Aprende a Programar Con Ruby

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