Post on 15-Jul-2016
description
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