Aprende a Programar Con Ruby
-
Upload
carlos-vladimir-roa-luna -
Category
Documents
-
view
33 -
download
0
description
Transcript of Aprende a Programar Con Ruby
1. Introduction2. Lección1
i. ¿QuéesRuby?ii. Instalacióniii. Númerosiv. Stringsv. Variables
3. Lección2i. Métodosii. ReglasNombresiii. Rangosiv. Arraysv. Bloques
4. Lección3i. MásMalabaresconStringsii. ExpresionesRegularesiii. Condicionalesiv. Buclesv. NúmerosAleatorios
5. Lección4i. ClasesyObjetosii. Accesoresiii. Ficheros:lecturayescrituraiv. Usandolibreríasv. Herenciadeclasesvi. Modificandoclasesvii. Congelandoobjetosviii. Serializandoobjetos
6. Lección5i. Controldeaccesoii. Excepcionesiii. Módulosiv. Constantesv. HashesySímbolosvi. LaclaseTime
7. Lección6i. selfii. DuckTypingiii. AzúcarSintácticoiv. Testdeunidades
Tabladecontenido
AprendeaprogramarconRuby
2
EstetutorialdeRubyestábasadoenTheRubyStudyNotes,deSatishTalim,aunqueheañadidoalgodecosechapropia,yorganizadolasleccionesdeotramanera.Además,paraaquellosquesepanprogramaryquieranverlascapacidadesdeRuby,hepreparadoesteRubyen15minutos,queesunresumenmuycondensadodetodoestetutorial.Tambiénlorecomiendoparaaquellosquelohayanterminado,yquieranrepasarloaprendido.
AprendeaprogramarconRuby
3Introduction
Rubyesunlenguajemultiplataforma,interpretadoyorientadoaobjetos.RubyfuediseñadoporYukihiroMatsumoto('Matz')en1993,conelPrincipiodelaMenorSorpresa.
"Queríaminimizarmifrustraciónmientrasprogramo,yesoconllevabaminimizarmiesfuerzo.EsteeselprincipalobjetivodeRuby.Quierodivertirmemientrasprogramo.DespuésdelanzarRubyyprobarlomuchagente,ellosmedijeronquesentíanlomismoqueyo.Ellosfueronlosqueacuñaroneltérminode"PrincipiodeMenorSorpresa".YukihiroMatsumoto
Enelaño2004hubounboomenelinterésporRuby,debidoaRubyonRails:elentornoparadesarrollowebdeDavidHeinemeierHansson.
EnellibrodeDavidBlack"RubyforRails",élmencionaqueunbuenconocimientoenRubypuedeayudarte,comodesarrolladordeRails,encuatroformas:
1. Conocermejorelcódigodetuaplicación(inclusoelcódigoqueRailsescribeautomáticamente).2. SermásproductivoconRails,inclusosidominastodassustécnicas.3. FamiliarizartemejorconelcódigodeRails,loquetepermitiráparticiparendiscusionessobreRailsyquizáspoder
ayudardetectandobugsoaportandopatches.4. Utilizarunapoderosaherramientaparatareasdeadministraciónyorganizaciónconectadascontuaplicación.
Libredeformato:unacosasepuedehacerdedistintasmaneras.Escogelaquemejorseadapteatuformadetrabajo.
Sensiblealasmayúsculas:dospalabras,aunquesediferenciensolamenteenunaletra,porestarenmayúsculaominúscula,sondoscosasdistintas.Porejemplo,'Dir'noeslomismoque'dir'.
Comentarios:cualquierlíneaprecedidapor#esignoradaporelintérprete.Además,cualquiercosaqueescribamosentrelaslíneas=beginy=end(empezandoambasenlaprimeracolumnadesucorrespondientelínea),tambiénseráignorada.
#Comentariodeunasolalínea
=begin
Estoes
uncomentario
devarias
líneas
=end
MUYIMPORTANTE:esteúltimotipodecomentarios,nopuedetenerespaciosasuizquierda,porquedaríaunerror.Porlotanto,sisequiereusar,siemprevanpegadosalmargenizquierdodelapantalla.
=begin
¿QuéesRuby?
¿Cómopuedeayudarte?
Algunascaracterísticas
AprendeaprogramarconRuby
4¿QuéesRuby?
Estecomentariomultilínea
daunerror.
=end
Delimitadoresdeinstrucción:variasinstruccionesenunamismalíneapuedenserseparadasporun;,peronosonnecesariosalfinaldeunalínea:estefinaldelínea(oretornodecarro)setratacomoun;.Siunfinaldelíneaacabaconun\,entonceselretornodecarroesignorado,loquepermitetenerunainstruccióndividaenvariaslíneas.
#Variasinstruccionesenunamismalínea
a=1;b=2;c=3
#esequivalentea:
a=1
b=2
c=3
#Unainstrucciónenvariaslíneas
a='enjutomojamuto'
#esequivalentea:
a="enjuto\
mojamuto"
Palabrasclave:tambiénconocidascomopalabrasreservadas,sonpalabrasenRubyquenopuedenserusadasparaotrospropósitos,porejemplo,comoalmacenarvalores.Además,puedesestaracostumbradoapensarqueunvalor'falso'puedeestarrepresentadopor0(enRubyseevalúaatrue),unacadenavacíaovariasotrascosas.
falseynil:EnRuby,todoestoesválido;dehecho,todoesciertoexceptolaspalabrasreservadasfalseynil.
AprendeaprogramarconRuby
5¿QuéesRuby?
Comolenguajemultiplataforma,Rubyhasidoportadoadistintossistemasoperativosyarquitecturas.EstosignificaquesitudesarrollasunprogramaenunPC(porejemplo),seráposibleejecutarloenotramáquinadistintacomoesunMAC(porponerotroejemplo).
LassiguientesinstruccionessonparainstalarRubyenunPC.Paraotrasplataformas,verelprimercapítulodelaWhy's(poignante)guidetoruby.
LaformamássencilladeinstalarRubyenunPCesmedianteelRubyOne-ClickInstaller.Despuésdedescargarloinstálaloaceptandotodopordefecto.Alinstalarse,lasVariablesdeEntornodelSistemasonactualizadas,detalformaqueseincluyaeldirectoriodelejecutabledeRuby:graciasaesto,podrásejecutarledesdecualquierdrectorioentuPC.
LainstalacióndeRubyincluyelaprimeraedicióndellibro"ProgrammingRuby"yeleditorSciTe.
SupongamosquelainstalacióndeRubyfueenc:/ruby.Estainstalacióncreóunaseriededirectorios:
c:/ruby/binesdondelosejecutablessoninstalados(incluyendorubyeirb).c:/ruby/lib/ruby/1.8aquíestánprogramasescritosenruby.EstosficherossonlibreríasdeRuby:proveenfuncionalidadesquepuedesincorporarentusprogramas.c:/ruby/lib/ruby/1.8/i386-mswin32contieneunaseriedeextensionesespecíficasdelPC.Losficherosenestaterminaciónacabanen.soo.dll(dependiendodelaplataforma).EstosficherosconextensionesprogramadasenlenguajeC;dichodeotraforma:sonfihcerosbinarios,compiladosduranteelprocesodeinstalación,quesepuedenejecutardesdeRuby.c:/ruby/lib/ruby/site_rubyaquíesdondeeladministradordetusistemay/otúpodéisalmacenarlasextensionesylibreríasdeterceraspartes:códigoescritoportimismo,oporotros.c:/ruby/lib/ruby/gemseselsistemaRuby-Gemes,encargadodelainstalacióndenuevasherramientas.c:/ruby/srcesdondesehallaelcódigofuentedeRuby.c:/ruby/samples/RubySrc-1.8.6/sampleaquípodrásencontraralgunosprogramasejemploescritosenRuby.
UsemoseleditorSciTE:Start/Programas/Ruby/SciTe.Seabreeleditor.Paracambiarlosparámetrosdearranque,Options/OpensGlobalyallímodificar:
tabsize=2,indent.size=2(tamañodeltabulador,yelidentado)position.width=-1,position.height=-1(arrancarmaximizado)
Unavezcambiadoslosvalores,pulsarCtrl+SyCtrl+S.Paramodificarestosdosvalores,otraformaes:
Ctrl+Shift+I-abreundiálogodondemodificarlosvaloresanteriores.Tienenqueser=2.F11-paramaximizarminimizarlaventana.
Loúltimoquefaltaantesescribirlosprogramas,esunabrirunaventanadeterminalparaverlosresultadosdelosprogramas.ParaellohayquepulsarF8.UnavezajustadoelSciTE,losiguienteescrearundirectoriodondeirguardandolosprogramasquevayamoscreando.
DescargandoRuby
Directoriosdelainstalación
Elprimerprograma
AprendeaprogramarconRuby
6Instalación
EnlaventanaizquierdadeSciTE(tienequehaber2ventanasdespuésdepulsarF8),escribir:
#p001hola.rb
puts'Hola'
Ahorahayqueguardaryejecutarelprograma.Lasnormasdicenqueelnombredelficheroodirectorio,eselnombreenminúsculasdelaclase/módulo(másadelantesehablarádeclasesymódulos).Porejemplo,laclaseFooestáenelficherofoo.rb.Paraguardarelfichero:File\SaveAs…Sálvalocomop001hola.rb.TodoslosficherosdecódigoRubytienenlaterminación"rb".Ahoraejecutaelprograma:pulsaF5.Enlaventanadeoutputaparecerálapalabra"Hola".
EnRuby,laejecucióndelasinstruccionesdelprograma,vadelaprimeraalaúltima:
#p001hola.rb
Nohacenada.Todaslaslíneasprecedidaspor#soncomentarios.Yloscomentariosseignoranalejecutarseelprograma.
puts'Hello'
putssignifica"ponerstring".Stringesunacadenadetexto.Estainstrucciónsacaporeloutputcualquiercosaquepongamosasuderecha.
Losparéntesissonopcionalescuandousamosunmétodo,enestecasoputs.Lassiguientesinstruccionessoncorrectas:
foobar
foobar()
foobar(a,b,c)
foobara,b,c
EnRuby,tododesdeunnúmeroenteroaunacadenadetexto,esunobjeto.Hablaremosmásdeesto.Ycadaobjetotienesuspropiosmétodos(oinstruccionesofunciones)quepuedenserusadosparahacercosasmuyútiles.Parausarunmétodo,necesitasponerun'.'despuésdelnombredelobjeto,yluegoponerelnombredelmétodo.Algunosmétodoscomoputsygetsnonecesitanestarasociadosaunobjeto,yportantopuedenserusadosdesdecualquierparte.CuandoseejecutaunaaplicaciónenRuby,siempresecreaunobjetollamadomaindelaclaseObject:esteobjetoeselquetienedentrolosmétodosKernel.Detodoestosehablarámásadelante.
Todoestosepuedeverificarporelsiguienteprograma(notepreocupessinoentiendeselprograma,másadelanteseexplicará):
puts'Soyunaclases='+self.class.to_s
puts'Soyunobjeto='+self.to_s
print'Losmétodosdelobjetoson='
putsself.private_methods.sort
'Hola'
Normasdecódigo
AprendeaprogramarconRuby
7Instalación
ProgramadoresdeCyJava-nosenecesitaescribirunmétodomain.Losstringssonsecuenciasdecaracteresentresimpleodoblescomillas.Lascomillassimplessonmáseficientesquelasdobles.Seexplicarámásadelante.Rubyesunlenguajeinterpretado,entoncesnohacefaltarecompilarparaejecutarunprograma.LasnormasdecódigoenRuby,establecenqueelnombredelfichero/directoriotienequeserelnombredelaclase/móduloenminúsculas,añadiendolaextensión.rb
Observaciones
AprendeaprogramarconRuby
8Instalación
EnRuby,losnúmerossinlacomadecimalsonllamadosenteros,ylosenteroscondecimalessonllamadoscoma-flotantes,omássencillamente,flotantes.
puts1+2
puts10-11
puts2*3
#División:cuandodividesdosenteros,obtienesunentero:
puts3/2
#siquieresobtenerelresultadodedecimal,
#almenosunodelosdostienequeserdecimal
puts3.0/2
puts3/2.0
puts1.5/2.6
LosnúmerosenRubysonobjetosdelaclaseFixnumoBignum:estasclasesrepresentannúmerosenterosdedistintostamaños.AmbasclasesdesciendendelaclaseInteger(eninglés,integer=entero).Losnúmeroscoma-flotantessonobjetosdelaclaseFloat(eninglés,float=flotante).
VeamoselejemploquePeterCoopernospropone,sacadodesulibro"BeginningRuby"(noimportaquetodavíanoseascapazdeentendertodoelcódigo):
=begin
Problemadeltablerodeajedrez:
sienlaprimeracasillaponemosungrano,
yduplicamoslacantidaddegranosenlasiguiente,
yasíhastarellenareltablero,
¿cuántosgranostendremos?
=end
granos=1
64.timesdo|escaque|
puts"Enelescaque#{escaque+1}hay#{granos}"
granos*=2
end
Alfinaltenemos2.2.2...2.2=264granosenlaúltimacasilla…¡trillonesdegranos!EstodemuestraqueRubyescapazdemanejarnúmerosextremadamentegrandes,yadiferenciadeotroslenguajesdeprogramación,nohaylímitesenesosnúmeros.Rubyhaceestograciasalasdistintasclasesantesmencionadas:
Fixnum:manejalosnúmerospequeñosBignum:manejalosnúmerosgrandes(eninglés,big=grande).Rubyescogerácuálusar,ytúúnicamentetendrásquepreocuparteporloquequierashacerconellos.
EchémosleunojoalosoperadoresdeRuby(HalfFulton-TheRubyWay).Estánordenadosdemayoramenorrangodeprecendencia;dichodeotraforma,losdelapartesuperiordelatabla,sonlosprimerosenejecutarse.
operador significado
: Alcance(scope)
[] Índices
Números
Operadoresyprecedencias
AprendeaprogramarconRuby
9Números
** Exponentes
+-!~ Unarios:pos/neg,no,…
*/% Multiplicación,División,…
+- Suma,Resta,…
«» Desplazadoresbinarios,…
& 'y'binario
,^ 'or'y'xor'binarios
>>=<<= Comparadores
=====<=>!==~!~ Igualdad,inegualdad,…
&& 'y'booleano
|| 'o'booleano
..… Operadoresderango
=(+=,-=,...) Asignadores
?: Decisiónternaria
not 'no'booleano
and,or 'y','o'booleano
Destacarque:
Losparéntesisfuncionandelamismaformaqueenlasmatemáticas:cualquiercosadentrodeellosescalculadoenprimerlugar.Odichomástécnicamente:tienenmásprecedencia.Losoperadoresincrementoydecremento(++y—)noestándisponiblesenRuby,niensuforma"pre"niensuforma"post".
Eloperadormódulo,quenosdaelrestodeunadivisión,secomportacomosigue:
puts(5%3)#imprime2
puts(-5%3)#imprime1
puts(5%-3)#imprime-1
puts(-5%-3)#imprime-2
`
Escribirunprogramaquedigacuantosminutoshayenunañode365días.
Eloperadormódulo
Ejercicio
AprendeaprogramarconRuby
10Números
Losstrings(ocadenasdetexto)sonsecuenciasdecaracteresentrecomillassimplesocomillasdobles.''(doscomillassimples)notienennada:podemosllamarlostringvacío.
puts"Holamundo"
#Sepuedeusar"o'paralosstrings,pero'esmáseficiente.
puts'Holamundo'
#Juntandocadenas
puts'Megusta'+'Ruby'
#Secuenciadeescape
puts'Ruby\'sparty'
#Repeticióndestrings
puts'Hola'*3
#Definiendounaconstante
#Másadelantesehablarádeconstantes
PI=3.1416
putsPI
EnRubylascadenassonmutables:sepuedenmodificar.Rubyalmacenalascadenascomosecuenciasdebytes.
Hayunosstringsespecialesquesediferencianporusarcomodelimitadorelacentograve`:
puts`dir`
Elstringentrelosacentos,esenviadoalsistemaoperativocomouncomandoaserejecutado.Elresultadodevueltoporelsistema,esrecogidoporRuby.
Conlainterpolaciónnosreferimosalprocesodeinsertarelresultadodeunaexpresióndentrodeunstring.Laformadehacerloesmediante#{expresión}.Ejemplo:
puts"100*5=#{100*5}"
Lasección#{100*5}seejecutayponeelresultadoenesaposición.Esdecir,500.
Ladiferenciaentreambasformas,eseltiempoquesetomaRubyencadauna:mientrasqueconlassimplescomillas,Rubyhacemuypoco;enlasdoblescomillas,Rubytienequehacermástrabajo:
1. buscaposiblessustituciones:lassecuenciasdeescape(lasqueempiecenporun)sonsustituidasporsuvalorbinario.
2. buscaposiblesinterpolaciones:enlassecuenciascon#{expresión},secalculalaexpresión,ysesustituyeelbloqueenteroporsuresultado.
Strings
Elacentograve`
Interpolación
Comillas(')vscomillasdobles(")
AprendeaprogramarconRuby
11Strings
defdi_adios(nombre)
resultado="Buenasnoches,#{nombre}"
returnresultado
end
putsdi_adios('Pepe')
=begin
Comolosmétodosdevuelvenelvalor
delaúltimalínea,nohacefalta
elreturn.
=end
defdi_adios2(nombre)
resultado='Buenasnoches,'+nombre
end
putsdi_adios2('Pepe')
=begin
Ahora,envezdeusar",usamos',
utilizandolaconcatenacióndestrings
paraobtenerelmismoresultado.
=end
String#lengthdevuelveelnúmerodebytesdeunacadena.
string="Estoesunacadena"
string.length#=>18
string.lengthdevuelve18.Cuentatodaslasletras,incluidoslosespaciosenblanco.
String#length
AprendeaprogramarconRuby
12Strings
Paraalmacenarunnúmeroounstringenlamemoriadelordenador,conelfindeusarlosencálculosposteriores,necesitasdarunnombreaesenúmeroostring.Enprogramaciónesteprocesoesconocidocomoasignación.
#Ejemplosdeasignaciones
s='HelloWorld!'
x=10
Lasvariableslocalesenrubysonpalabrasquedeben:
1. empezarconunletraminúsculaounguiónbajo_.2. estarformadasporletras,númerosy/oguionesbajos.
CuandoRubyencuentraunapalabra,lainterpretacomo:unavariablelocal,unmétodoounapalabraclave.Laspalabrasclavesnopuedenserusadoscomovariables.Porejemplodefesunapalabraclave:sólosepuedeusarparadefinirunmétodo.iftambiénesunapalabraclave:granpartedelcódigoconstadeinstruccionescondicionalesqueempiezanconif,poresoseríamuyconfusosipudieseusarsecomovariable.
Losmétodospuedenserpalabras,comostart_here,putsoprint.CuandoRubyencuentraunapalabradecidequéesdelasiguienteforma:
1. sihayunsignodeigualdad(=)aladerechadelapalabra,esunavariablelocalalaqueseleasignaunvalor.2. silapalabraesunapalabraclave,entoncesesunapalabraclave.Rubytieneunalistainternaparapoder
reconocerlas.3. sinosecumpleningunodelosanteriorescasos,Rubyasumequeesunmétodo.
#Definicióndeunaconstante
PI=3.1416
putsPI
#Definicióndeunavariablelocal
myString='Yoamomiciudad,Vigo'
putsmyString
=begin
Conversiones
to_i-convierteanúmeroentero
to_f-convierteanúmerodecimal
to_s-convierteastring
=end
var1=5
var2='2'#fijarsequeesuntexto
putsvar1+var2.to_i
=begin
<<marcaelcomienzodeunstring
yesseguidode'o''.Aquíañadimos
elstringjuntoconelretornodecarro(\n).
=end
a='molo'
a<<'mucho.
Molomazo...'
putsa
=begin
'o"sonlosdelimitadoresdeunstring.
Enestecaso,podemossustituirlosporEND_STR.
END_STResunaconstantedelimitadordestrings.
Variables
AprendeaprogramarconRuby
13Variables
=end
a=<<END_STR
Thisisthestring
Andasecondline
END_STR
putsa
Enelejemplo,var2.to_ielpuntosignificaqueelmétodoto_iesenviadoalavariablevar2,queestecasoesunstring:transformamoselstringenunnúmeroparapodersumarlos.Cuandohablemosdeobjetos,veremosquesepuededecirquelavar2eselreceptordeto_i.Porlotanto,cuandoaparezcaunpuntoenunaposicióninexplicable,habráqueinterpretarlocomounmétodo(lapartederecha)queesenviadoaunobjeto(laparteizquierda).
Porinterpretacióndinámica,seentiendequenohacefaltaespecificarquétipodevariablesevaamanejar:sipareceunnúmero,problablementeseaunnúmero;sipareceunacadena,probablementelosea.Elmétodoclassdevuelveeltipodeclasedeunobjeto:
s='hello'
s.class#String
Otroejemplo:
#Rubyesdinámico
x=7#númeroentero
x="house"#string
x=7.5#númeroreal
Elalcanceesunapropiedaddelasvariables:serefiereasuvisibilidad(aquellaregióndelprogramaadondelavariablepuedeutilizarse).Losdistintostiposdevariables,tienendistintasreglasdealcance.Hablemosdedostiposdevariables:lasglobalesylaslocales.
Empezarmosconelalcancequemenosseusa,peronoporellomenosimportante:unalcanceglobalsignificaquealcanzaatodoelprograma.Desdecualquierpartedelprograma,puedeusarselavariable.Lasvariablesglobalessonlasquetienenalcanceglobal.
Lasvariablesglobalessedistinguenporqueestánprecedidasdelsignodólar$.Puedenservistasdesdecualquierpartedelprograma,yportantopuedenserusadasencualquierparte:nuncaquedanfueradealcance.Sinembargo,lasvariablesglobalessonusadasmuypocoporlosprogramadoresexperimentados.
ElintérpreteRubytienepordefectoungrannúmerodevariablesglobalesiniciadasdesdeelprincipio.Sonvariablesquealmacenaninformaciónútilquepuedeserusadaencualquiermomentoypartedelprograma.
Interpretacióndinámica
Alcance
Alcanceglobalyvariablesglobales
Variablesglobalespordefecto
AprendeaprogramarconRuby
14Variables
Porejemplo,lavariableglobal$0contieneelnombredelficheroqueRubyestáejecutando.Lavariableglobal$:contienelosdirectoriosenlosqueRubybuscacuandosecargaunficheroquenoexisteeneldirectoriodetrabajo.$$contieneelid(identidad)delprocesoqueRubyestáejecutando.Yhaymuchasmás.
Nota:notepreocupessinoentiendesestoahora.
Sepuedeintuirmirandoelcódigodóndeempiezayacabaelalcancedelasvariableslocales,basándonosen:
Elnivelmásalto(fueradetodoslosbloquesdedefinición)tienensupropioalcance.Cadabloquededefinicióndeunaclaseomódulotienensupropioalcance,inclusolosbloquesanidados.Todadefinicióndeunmétodo(def)tienesupropioalcance.
Alcancelocal
AprendeaprogramarconRuby
15Variables
EnRuby,todoloquesemanipulaesunobjeto,yelresultadodeesasoperacionestambiénsonobjetos.Laúnicaformaquetenemosdemanipularlosobjetos,sonlosmétodos:
5.times{puts"Ratón!\n"}#sehablarámástardedebloques
"Aloselefanteslegustanloscacahuetes".length
Silosobjetos(comolosstrings,números,…)sonlosnombres,entonceslosmétodossonlosverbos.Todométodonecesitaunobjeto.Esfácildecirquéobjetorecibeelmétodo:elqueestáalaizquierdadelpunto.Algunasveces,puedequenoseaobvio.Porejemplo,cuandoseusaputsygets,¿dóndeestánsusobjetos?Nadamásiniciarseelintérprete,estamosdentrodeunobjeto:elobjetomain.Portanto,alusarputsygets,estamosmandandoelmensajealobjetomain.
¿Cómopodemossaberdentrodequéobjetoestamos?Usandolavariableself.
putsself
Unbloquedeinstruccionesquedefineunmétodo,empiezaporlapalabradefyacabaporlaend.Losparámetrossonlalistadevariablesquevanentreparéntesis.AunqueenRuby,dichosparéntesissonopcionales:puts,pygetssonmuyusados,yporelloqueelusodeparéntesisseaopcional.EnRails,sellamaalosmétodossinparéntesis.
Unmétododevuelveelvalordesuúltimalínea.Pornorma,esrecomendabledejarunalíneaenblancoentrelasdefinicionesdemétodos:
#metodos.rb
#Definicióndeunmétodo
defhello
puts'Hola'
end
#usodelmétodo
hello
#Métodoconunargumento
defhello1(nombre)
puts'Hola'+nombre
return'correcto'
end
puts(hello1('Pedro'))
#Métodoconunargumento(sinparéntesis,nofuncionaenversionesnuevas)
defhello2nombre2
puts'Hola'+nombre2
return'correcto'
end
puts(hello2'Juan')
Estoesloqueobtenemos
>rubymetodos.rb
Hola
HolaPedro
Variables
Escribiendométodos
AprendeaprogramarconRuby
16Métodos
correcto
HolaJuan
correcto
metodos.rb:18warning:parenthesizeargument(s)forfutureversion
>Exitcode:0
Losmétodosqueacabanconuna!sonmétodosquemodificanalobjeto.Porlotanto,estosmétodossonconsideradoscomopeligrosos,yexistenmétodosiguales,perosinel!.Porsupeligrosidad,elnombre"bang".Ejemplo:
a="Enunalugardelamancha"
#métodosinbang:elobjetonosemodifica
b=a.upcase
putsb
putsa
#métodoconbang:elobjetosemodifica
c=a.upcase!
putsc
putsa
Normalmente,porcadamétodocon!,existeelmismométodosin!.Aquellossinbang,nosdanelmismoresultado,perosinmodificarelobjeto(enestecasoelstring).Lasversionescon!,comosedijo,hacenlamismaacción,peroenlugardecrearunnuevoobjeto,transformanelobjetooriginal.
Ejemplosdeestoson:upcase/upcase!,chomp/chomp!,…Encadacaso,sihacesusodelaversiónsin!,tienesunnuevoobjeto.Sillamaselmétodocon!,hacesloscambiosenelmismoobjetoalquemandasteelmensaje.
aliasnuevo_nombrenombre_original
aliascreaunnuevonombrequeserefiereaunmétodoexistente.Cuandoaunmétodoseleponeunalias,elnuevonombreserefierealmétodooriginal:sielmétodosecambia,elnuevonombreseguiráinvocandoeloriginal.
defviejo_metodo
"viejometodo"
end
aliasnuevo_metodoviejo_metodo
defviejo_metodo
"viejometodomejorado"
end
putsviejo_metodo
putsnuevo_metodo
Enelresultado,vemoscomonuevo_metodohacereferenciaalviejo_metodosinmodficar:
viejometodomejorado
viejometodo
Losmétodosbang(!)
Alias
Métodosperdidos
AprendeaprogramarconRuby
17Métodos
Cuandomandasunmensajeaunobjeto,elobjetobuscaensulistademétodos,yejecutaelprimermétodoconelmismonombredelmensajequeencuentre.Sinoencuetradichométodo,lanzaunaerrorNoMethodError.
Unaformadesolucionaresto,esmedianteelmétodomethod_missing:sidefinimosdichométododentrodeunaclase,seejecutaestemétodopordefecto:
classDummy
defmethod_missing(m,*args)
puts"Noexisteunmetodollamado#{m}"
end
end
Dummy.new.cualquier_cosaobtenemos:
Noexisteunmetodollamadocualquier_cosa
Porlotanto,method_missingescomounareddeseguridad:tedaunaformademanejaraquellosmétodosquedeotraformadaríanunerrorentuprograma.
Rubydejaespecificarlosvalorespordefectodelosargumentos,quesonusadossinoseespecificaunvalorexplícitamente.Sehaceestomedianteeloperadordeasignación=:
#argumentos.rb
defmtd(arg1="Dibya",arg2="Shashank",arg3="Shashank")
"#{arg1},#{arg2},#{arg3}."
end
putsmtd
putsmtd("ruby")
Hemosusadoeloperadorinterpolación#{}:secalculalaexpresiónentreparéntesis,yelresultadoseañadealstring.Loqueobtenemoses:
>rubyargumentos.rb
Dibya,Shashank,Shashank.
ruby,Shashank,Shashank.
>Exitcode:0
Rubypermiteescribirfuncionesqueaceptenunnúmerovariabledeargumentos.Porejemplo:
deffoo(*mi_string)
mi_string.eachdo|palabras|
putspalabras
Argumentos
Valorespordefecto
Númerodeargumentosvariable
AprendeaprogramarconRuby
18Métodos
end
end
foo('hola','mundo')
foo()
Elasteriscoindicaqueelnúmerodeargumentospuedeserelquesequiera.Enesteejemplo,elasteriscotomalosargumentosylosasignaaunarray(ovectordeelementos)llamadomi_string.Haciendousodeeseasterisco,inclusosepuedenpasarceroargumentos;queesloquepasaconfoo().
Nohaymáximonúmerodeargumentosquepodamospasaraunmétodo.
Sisequierenincluirargumentosopcionales,tienenquevenirdespuésdelosargumentosnoopcionales:
defarg_opc(a,b,*x)#bien
defarg_opc(a,*x,b)#mal
Losargumentosseinterpretandeizquierdaaderecha,poresoesimportantequelosargumentosnoopcionalesvayanenprimerlugar.Silospusiésemosenúltimolugar,nosabríamosdecirdondeacabanlosargumentosopcionalesydondeempiezanlosnoopcionales.
=begin
Ejemplodecomolosargumentosse
interpretandeizquierdaaderecha
=end
defmtd(a=99,b=a+1)
[a,b]
end
putsmtd
Leccionesatrásvimoselmétodoputsquesacadatosporlapantalla.¿Cómopodemosintroducirnuestrospropiosdatos?Paraestogets(get=coger,s=string)ychompsondeayuda.Veamoselsiguienteejemplo:
#getsychomp
puts"¿Enquéciudadtegustaríavivir?"
STDOUT.flush
ciudad=gets.chomp
puts"Laciudades"+ciudad
Elejemplosuperior,alserejecutadoenSciTe,clickeaenlapantalladeoutputyponelnombredetuciudadfavorita.STDOUTesunaconstanteglobalquealmacenalassalidasdelprograma.flushvacíacualquierdatoalmacenado,yporlotanto,limpiarácualquierresultadoanterior.chompesunmétodoparastringsygetsalmacenastringsqueprovienendelteclado.Elproblemaesquegetsalmacenaloescritoyelcaráter\n(retornodecarro);chomploquehaceesborrarelcarácter:\n.
RAILS:losdatosvienendemuchossitios.EnlatípicaaplicacióndeRails,vienendeunabasededatos.ComoundesarrolladordeRails,puedesusarconfrecuenciaalgunosdeestosmétodos,porqueRailsrecogelosdatosquelosusuariosescribenenlosformulariosWeb.
Argumentosopcionales
Introduciendodatos(gets)
AprendeaprogramarconRuby
19Métodos
EscribeunprogramaquepregunteporlatemperaturaengradosFahrenheit.Elprogramausaráestedato,yhallaráelequivalenteengradosCelsius.Elresultadofinallomostraráenpantallacondosdecimales.(Celsius(°C)=[Fahrenheit(°F)-32]/1.8)
Nota:paraformatearunresultadoadosdecimales,haydosopciones:
1. Usarelmétodoformat.Porejemplo:
x=45.5678
putsformat("%.2f",x)
1. Otraformaeslafunciónround:
puts(x*100).round/100.0
Ejercicio
AprendeaprogramarconRuby
20Métodos
Unnombreesunaletramayúscula,unaletraminúsculaounguiónbajo,seguidoporcualquiercombinacióndemayúsculas,minúsculas,númerosoguionesbajos.
LosnombresenRubyseusanparareferirseaconstantes,variables,métodos,clasesymódulos.LaprimeraletradeunnombreayudaaRubyadistinguirlos.Algunosnombres,sonpalabrasreservadasynopuedenusarsecomovariable,método,claseomódulo.Elconjuntodelasminúsculasabarcadelaaalazincluyendoelguiónbajo_.ElconjuntodelasmayúsculasabarcadelaAalaZylosnúmeros(del0al9).
Lasvariablescontienencualquiertipodedato.Elpropionombredelavariable,muestrasualcance(local,global,…):
Unavariablelocalconsisteenunaletraminúsculaoguiónbajoseguidodecualquiermayúsculaominúscula.P.ej.:sunil,_z,rock_and_rollUnavariabledeunobjeto(másadelantesehablarádeclasesyobjetos)empiezacon@,seguidodecualquiermayúsculaominúscula.
@sign
@_
@Counter
Unavariabledeclaseempiezacon@@seguidoporcualquiermayúsculaominúscula.
@@signo
@@_
@@Counter
Unavariableglobalempiezapor$,seguidoporcualquiercarácter(nosólomayúsculasominúsculas).
$counter
$COUNTER
$-x.
Unaconstanteempiezaporunaletramayúscula,seguidoporcualquiermayúsculaominúscula.Losnombresdeclasesydemódulossonconstantes,ysiguenunasnormas.
moduleMyMath
PI=3.1416
classPerro
Losnombresdemétodosdebenempezarporunaminúscula(letraoguiónbajo).La?yla!sonlosúnicoscaracteresajenosalgruposdelasmayúsculasyminúsculas,quesepermitencomosufijosdelosmétodos.Másadelanteseexplicarásuuso.
Pornorma,seusaelguiónbajoparasepararpalabrascompuestasenlosnombresdemétodosydevariables.Paralosnombresdeclases,módulosyconstantes,lanormadicedeusarletrasmayúsculasenvezdeguionesbajos,para
Normasenlosnombres
Variables
Constantes
AprendeaprogramarconRuby
21ReglasNombres
distinguirlas.Ejemplos:
variablesymétodos
real_madrid
futbol_club_barcelona
clases,módulosyconstantes:
RealMadrid
FutbolClubBarcelona
Hayquenotarqueunavariablepuedereferirseadistintosvaloresalolargodeltiempo.UnaconstanteenRubypuedeserunareferenciaaunobjeto.Lasconstantessoncreadasenelmomentodesuprimeraasignación,normalmenteenladefinicióndeunaclaseounmódulo;nodebenestardefinidasenlosmétodos.Sepuedevariarelvalordeunaconstante,peroestogeneraunvalordeaviso.
AprendeaprogramarconRuby
22ReglasNombres
Elprincipalusoyquizáselmásapropiadoparalosrangos,esexpresarunasecuencia:lassecuenciastienenunpuntoinicialyunpuntofinal,yunaformadeproducirlossucesivosvaloresentreambos.EnRuby,esassecuenciassoncreadasusandolosoperandos..y…
..generaunasecuenciadondelospuntoslímitesestánincluidos.
(1..3).to_a
#eslasecuencia1,2,3
…generaunasecuenciaenlaquenoestáincluidaellímitesuperior.
(1...5).to_a
#equivalea1,2,3,4
EnRubylosrangosnosonalmacenadoscomounalista:losrangossealmacenancomounobjetoRange,ycontienereferenciasadosobjetosFixnum(sulímitesuperioreinferior).Sepuedeconvertirunrangoenunarray(array=lista,conjuntoordenadodeelementos),medianteelmétodoto_a.
(1..10).to_a
#obtenemos[1,2,3,4,5,6,7,8,9,10]
Losrangosenrubytienendiversosmétodos:
nums=-1...9
putsnums.include?(5)#true
putsnums.min#-1
putsnums.max#8
putsnums.reject{|i|i<5}#[5,6,7,8]
Unodelosusosútilesdelosrangos,escomprobarsiundeterminadovalorestáenelintervalorepresentadoporelrango.Paraesousamoseloperador===:
(1..10)===5#true
(1..10)===15#false
(1..10)===3.14159#true
('a'..'j')==='c'#true
Rangos
Métodosderangos
AprendeaprogramarconRuby
23Rangos
Unarray(olista)esunconjuntoordenado:cadaposiciónenlalistaesunavariablequepodemosleery/oescribir.
#Arrays(ovectores)
#arrayvacío
vec1=[]
#Losíndicesempiezandesdeelcero(0,1,2,...)
nombres=['Satish','Talim','Ruby','Java']
putsnombres[0]
putsnombres[1]
putsnombres[2]
putsnombres[3]
#sielelementonoexiste,sedevuelvenil
putsnombres[4]
#peropodemosañadiraposteriorimáselementos
nombres[3]='Python'
nombres[4]='Rails'
Unarraypuedeserunconjuntodeelementosdistintos:
=begin
unarraycuyoselementos
apuntanaotrostresobjetos:
undecimal,unstringyunarray
=end
sabor='mango'
vec4=[80.5,sabor,[true,false]]
putsvec4[2]
Algunasveces,creararraysdepalabraspuedesertediosodebidoatantascomillasycomas.Afortunadamente,Rubytieneunaformamáscómodaparahacerlo:
nombres1=['ann','richard','william','susan','pat']
putsnombres1[0]#ann
putsnombres1[3]#susan
#estoesmássencilloymásrápido:
nombres2=%w{annrichardwilliamsusanpat}
putsnombres2[0]#ann
putsnombres2[3]#susan
Elmétodoeachextraecadaelementodelarraydentrodelavariablequeseleespecifique(queiráentradosbarras||),queseusaráenbloquedo…end.
ciudades=%w{PuneMumbaiBangalore}
ciudades.eachdo|ciudad|
puts'¡Megusta'+ciudad+'!'
puts'¿Atino?'
Arrays
Usando%w
Elmétodoeach
AprendeaprogramarconRuby
24Arrays
end
#Elmétododeleteborraunelemento
ciudades.delete('Mumbai')
ciudades.eachdo|ciudad|
puts'¡Megustaba'+ciudad+'!'
puts'¿Atiyano?'
end
Porlotantoelmétodoeachnospermitehacerunacosa(laquesea)concadaobjetodelarray.Enelejemplo,fuimoselementoporelementodelarraysinusarlosíndices.Hayquedestacar:
Losvariableentrelos"postes"serefiereacadaítemdelarrayamedidaqueavanzamosenelloop.Sepuedeusarcualquiernombre,peroesmejordotarlodeciertosignificado.Eldo…endidentificaelbloquedecódigoqueseejecutaráconcadaelementodelarray.LosbloquessonusadosintensivamenteenRuby,ysetrataránenprofundidadmásadelante.Esposiblessustiturlosporlasllavesdeinicioyfin.
vec=[34,12,1,38]
putsvec.sort
putsvec.length
putsvec.first
putsvec.last
Unmétodopuededevolverunarray:
defnum_cuadrado(num)
cuadrado=num*num
returnnum,cuadrado
end
=begin
elmétodonosdevuelve
unarrayconelnúmero
ysucuadrado
=end
x=3
num_cuadrado(x)
=begin
siqueremosalmacenarelresultado
hayquehacerlopor
asignaciónenparalelo
=end
num,cuadrado=num_cuadrado(x)
Escribeunprogramatalque,dadounarraynumérico,calculelasumadesuselementos.Porejemplo,array=[1,2,3,4,5]
Escribeunprogramatalque,dadounarraydenúmeros,digadecadaunosiesparoimpar.Porejemplo,array=
Otrosmétodos
Obteniendoarrays
Ejercicios
AprendeaprogramarconRuby
25Arrays
[12,23,456,123,4579]
AprendeaprogramarconRuby
26Arrays
Unbloqueesunaporcióndecódigoencerradaentreparéntesis{}oentredo…end.Porlotanto,unbloqueesunaformadeagruparinstrucciones,ysolopuedeaparecerdespuésdeusarunmétodo:elbloqueempiezaenlamismalíneaqueusaelmétodo.ElcódigodentrodelbloquenoesejectuadoenelinstantequeelintérpretedeRubyloencuentra:Rubyserecordarádelbloque(variableslocales,…)ydespuésentraenelmétodo,ejecutandoelbloquecuandoespreciso.
Supongamosqueexistendosmétodosllamadosgreet1ygreet2:
#greet1,nonecesitaargumentos
greet1{puts'Hola'}
#greet2,necesitaunargumento
greet2("argumento_cualquiera"){puts'Hola'}
Lousualesusarlas{}parabloquesdeunalíneayeldo…endparamásdeunalínea.
Unmétodopuedeusarelbloquemediantelapalabrayield:
defmetodo
puts'Comienzodelmetodo'
yield
yield
puts'Finaldelmetodo'
end
metodo{puts'Dentrodelbloque'}
Lasalidaes:
'Comienzodelmetodo'
'Dentrodelbloque'#primeryield
'Dentrodelbloque'#segundoyield
'Finaldelmetodo'
Loquesucedeesqueenelmomentoqueelintérpretellegaalyield,seejecutaelcódigodentrodelbloque,yluegoseretornaalmétodo.
Enlosbloquessepuedenusarargumentosespecificándolosdentrodedosbarrasverticales||.Ysiseusan,enelyieldnopodemosolvidardarlesvalor:
defmetodo
yield('hola',99)
end
metodo{|str,num|putsstr+''+num.to_s}#hola99
Bloques
Elmétodoyield
Argumentosenlosbloques
AprendeaprogramarconRuby
27Bloques
Unbloquedecódigodevuelveunvalor:elvalordelaúltimaexpresiónevaluada.Yestevalordevueltoporyield,puedeusarsedentrodelmétodoqueinvocaelbloque.
Losbloquesnosonobjetos,peropuedenconvertirseenellosgraciasalaclaseProc.Estosobjetossonbloquesquesehanunidoaunconjutodevariableslocales.EstosehacegraciasalmétodolambdadelmóduloKernel.
prc=lambda{"hola"}
Unbloquecreadoconlambdaactúacomounmétodo:sinoespecificaselnúmerocorrectodeargumentos,nopuedesllamaralbloque.LaclaseProctieneunmétodoparallamaralbloque:elmétodocall.
prc=lambda{puts'Hola'}
prc.call#llamamosalbloque
#otroejemplo
toast=lambdado
puts'Gracias'
end
toast.call
Lasalidaes:
Hola
Gracias
Parausarargumentosconlambda:
aBlock=lambda{|x|putsx}
aBlock.call'HolaMundo!'
Lasalidaes:
HolaMundo!
Losprocssonmuyútilesporque:
Nopuedespasarmétodosdentrodeotrosmétodos(usarloscomoargumentos);perosipuedesusarprocscomoargumentos.Losmétodosnopuedendevolverotrosmétodos;perosípuedendevolverunprocs.
#usodeprocscomoargumentos
defmetod1proc1
puts'Principiodelmetodo'
proc1.call
puts'Finaldelmetodo'
end
hola=lambdado
puts'Hola'
Losprocs
AprendeaprogramarconRuby
28Bloques
end
metod1hola
Lasalidaes:
Principiodelmetodo
Hola
Finaldelmetodo
AprendeaprogramarconRuby
29Bloques
Lasexpresionesregulares,aunquecrípticas,sonunapoderosaherramientaparatrabajarcontexto.Sonusadasparareconocerpatronesyprocesartexto.Unaexpresiónregularesunaformadeespecificarunpatróndecaracteres,queserábuscadoenunstring.EnRuby,secreanlasexpresionesregularesentre//.SonobjetosdeltipoRegexpypuedensermanipuladascomotales.
//.class#Regexp
Laformamássimpledeencontrarsiunaexpresión(tambiénfuncionaconstrings)estádentrodeunstring,esusarelmétodomatchoeloperador=~:
m1=/Ruby/.match("ElfuturoesRuby")
putsm1#"Ruby",puestoqueencontrólapalabra
putsm1.class#devuelveMatchData;devuelve"nil"sinoseencuentra
#operador=~:
m2="ElfuturoesRuby"=~/Ruby/
putsm2#13->posicióndondeempiezalapalabra"Ruby"
Cualquiercarácterquevayaentrebarras,sebuscaexactamente:
/a/#sebuscalaletraa,ycualquierpalabraquelacontenga
Algunoscaracterestienenunsignificadoespecialenlasexpresionesregulares.Paraevitarqueseprocesen,ypoderbuscarlos,seusalasecuenciadeescape\.
/\?/
La\significa"notrateselsiguientecaráctercomoespecial".Loscaracteresespecialesincluyen: ,$,?,.,/,\,[,],{,},(,),+y*.
Algunasveces,sebuscacualquiercaracterenunaposicióndeterminada.Estoselogragraciasal..Unpunto,buscacualquiercarácter,exceptoelretornodecarro.
/.azado/
Buscamazadoycazado.Tambiénencuentra%azadoy8azado.Poresohayquetenercuidadoalusarelpunto:puededarmásresultadosquelosdeseados.Sinembargo,sepuedenponerrestriccionesalosresultados,especificandolasclasesdecaracteresbuscadas.
ExpresionesRegulares
Construyendoexpresionesregulares
Elcomodín.(punto)
AprendeaprogramarconRuby
30ExpresionesRegulares
Unaclasedecarácteresunalistaexplícitadecaracteres.Paraelloseusanloscorchetes:
/[mc]azado/
Deestaforma,especificamoslabúsquedadeazadoprecedidoporcom:solamentebuscamosmazadoocazado.
Dentrodeloscorchetes,sepuedeespecificarunrangodebúsqueda.
/[a-z]/#encuentracualquierminúscula
/[A-Fa-f0-9]/#encuentracualquiernúmerohexadecimal
Algunasvecessenecesitaencontrarcualquiercaráctermenosaquellosdeunalistaespecífica.Estetipodebúsquedaserealizanegando,usando alprincipiodelaclase.
/[^A-Fa-f0-9]/#encuentracualquiercarácter,menosloshexadecimales
Algunoscaracteressontanválidos,quetienensuabreviación.
Abreviacionesparaclasesdecaracteres
Paraencontrarcualquiercifradecimal,estasdosexpresionessonequivalentes:
/[0-9]/
/\d/
Otrasdosabreviacionesson:
\wencuentracualquierdígito,letra,oguiónbajo_.\sencuentracualquiercarácterespacio-en-blanco(characterwhitespace),comosonunespacio,untabuladoyunretornodecarro.Todaslasabreviacionesprecedentes,tambiéntienenunaformanegada.Paraello,seponelamismaletraenmayúsculas:
/\D/#buscacualquiercarácterquenoseaunnúmero
/\W/#buscacualquiercarácterquenoseaunaletraoguiónbajo
/\S/#buscauncarácterquenoseaunespacioenblanco.
expresión significado
. cualquiercaracter
[] especificaciónporrango.P.ej:[a-z],unaletradelaa,alaz
\w letraonúmero;eslomismoque[0-9A-Za-z]
\W cualquiercarácterquenosealetraonúmero
Clasesdecaracteres
Tablaresumen
AprendeaprogramarconRuby
31ExpresionesRegulares
\s carácterdeespacio;eslomismoque[\t\n\r\f]
\S cualquiercarácterquenoseadeespacio
\d número;lomismoque[0-9]
\D cualquiercarácterquenoseaunnúmero
\b retroceso(0x08),siestádentrodeunrango
\b límitedepalabra,siNOestádentrodeunrango
\B nolímitedepalabra
* ceroomásrepeticionesdeloqueleprecede
+ unaomásrepeticionesdeloqueleprecede
$ findelalínea
{m,n} comomenosm,ycomomuchonrepeticionesdeloqueleprecede
? almenosunarepeticióndeloqueleprecede;lomismoque{0,1}
() agruparexpresiones
|| operadorlógicoO,buscalodeantesolodespués
Sinoseentiendealgunadelasexpresionesanteriores,loquehayquehaceresprobar.Porejemplo,veamoselcasode|.Supongamosquebuscamoslapalabragatoolapalabraperro:
/gato|perro/
El|esun"Ológico":sebuscalapalabradelaizquierdaolapalabradeladerecha.
Cualquierbúsquedasucedeconéxitoofracasa.Empecemosconelcasomássimple:elfallo.Cuandointentasencontrarunstringmedianteunpatrón,yelstringnoseencuentra,elresultadosiempreesnil(nil=nada).
/a/.match("b")#nil
Sinembargo,silabúsquedatieneéxitosedevuelveunobjetoMatchData.Esteobjetotieneunvalor'true'desdeelpuntodevistabooleano,yademásalmacenalainformacióndeloencontrado:dondeempieza(enquécarácterdelstring),quéporcióndelstringocupa,…Parapoderusarestainformación,hacefaltaalmacenarlaprimero.Veamosunejemplodondebuscamosunnúmerodeteléfonodentrodeunstring:
string="Minúmerodeteléfonoes(123)555-1234."
num_expr=/\((\d{3})\)\s+(\d{3})-(\d{4})/#expresiónregular
m=num_expr.match(string)#almacenamosbúsqueda
unlessm
puts"Nohuboconcordancias."
exit
end
print"Elstringdelabúsquedaes:"
putsm.string#stringdondeseefectúalabúsqueda
print"Lapartedelstringqueconcuerdaconlabúsquedaes:"
putsm[0]#partedelstringqueconcuerdaconnuestrabúsqueda
puts"Lastrescapturas:"
3.timesdo|index|
#m.captures[index]-subcadenasencontradas(subcaden=()enlaexpresión)
Unabúsquedaconéxito
AprendeaprogramarconRuby
32ExpresionesRegulares
puts"Captura##{index+1}:#{m.captures[index]}"
end
puts"Otraformaparaponerlaprimeracaptura:"
print"Captura#1:"
putsm[1]#cadanúmerocorrespondeaunacaptura
lasalidaes:
Elstringdelabúsquedaes:Minúmerodeteléfonoes(123)555-1234.
Lapartedelstringqueconcuerdaconlabúsquedaes:(123)555-1234
Lastrescapturas:
Captura#1:123
Captura#2:555
Captura#3:1234
Otraformadeponerlaprimeracaptura
Captura#1:123
Paraanalizarlaexpresiónregular,hayqueprestaratenciónacómoestánagrupadaslasbúsquedasentreparéntesis:
num_expr=/\((\d{3})\)\s+(\d{3})-(\d{4})/
\((\d{3})\)buscaungrupodetresnúmeros(\d{3}),entredosparéntesis\(…\)\s+espacioenblancounaovariasveces(\d{3})tresnúmeros-signomenos(\d{4})cuatronúmeros
AprendeaprogramarconRuby
33ExpresionesRegulares
HaymuchosmétodosenlaclaseString(nohayquememorizarlostodos;paraalgoestáladocumentación)como:
reverse,queinvierteloscaracteresdeunstringlength,quenosdiceelnúmerodecaracteresdeunstring,incluyendolosespaciosenblanco.upcase,queponetodosloscaracteresenmayúsculasdowncase,queponetodosloscaracteresenminúsculasswapcase,poneloscaracteresmayúsculasenminúsculasylosminúsculasenmayúsculascapitalize,poneelprimercaracterdelstringenmayúsculas,ylosdemásenminúsculasslice,daunapartedeunstring
Losmétodosupcase,downcase,swapcaseycapitalizetienensucorrespondientemétodobang,quemodificanelstring(upcase!,downcase!,swapcase!,ycaptalize!).Sinonecesitaselstringoriginal,esbuenousarlo,porqueahorrarásmemoria;sobretodosielstringeslargo.
Cadavezqueseseasignaaunavariableunstring,secreaunnuevoobjetoString.¿Cómoesadministradalamemoriaenlosstrings?¿Hayunaporciónseparadaparaellos?LaclaseStringtienemásde75métodos.LeyendolaGuíadeUsodeRuby(RubyUser'sGuide),dice"notenemosencuentalamemoriaocupadaporunstring.Prescindimosdecualquieradministracióndememoria".ParasabertodoslosmétodosquetieneunString:
String.methods,daunalistadetodolosmétodosquetienelaclaseString.String.methods.sort(sort=ordenar),daunalistaordenadaalfabéticamentedetodoslosmétodos.String.instance_methods.sort,daunalistaordenadadetodolosmétodosdeinstancia(seexplicarámásadelante)quetieneunString.String.instance_methods(false).sort,muestraunalistaordenadadetodoslosmétodosquepertanezcanexclusivamentealosStrings,peronoalasclasesdelasquedesciende.
Losstringstienendistintosmétodosparacompararsuigualdad.Elmáscomúndeelloses==.OtrométodoesString.eql?,quedevuelveelmismoresultadoque==.YporúltimoestáString.equal?,quecompruebasidosstringssonelmismoobjeto.Veamoselsiguienteejemplo:
defcompara_strings(s1,s2,s3)
#comprobamossielcontenidoesigual
ifs1==s2
puts'Ambosstringstienenelmismocontenido'
else
puts'AmbosstringsNOtienenelmismoconenido'
end
ifs1.eql?(s2)
puts'Ambosstringstienenelmismocontenido'
else
puts'AmbosstringsNOtienenelmismoconenido'
end
=begin
ahoracomprobamossiambosobjetossoniguales:
dosobjetosdiferentes
puedentenerelmismocontenido
=end
ifs1.equal?(s2)
puts'Ambosstringssonelmismoobjeto'
Másmalabaresconstrings
Comparandodoscadenas
AprendeaprogramarconRuby
34MásMalabaresconStrings
else
puts'AmbosstringsNOsonelmismoobjeto'
end
ifs1.equal?(s3)
puts'Ambosstringssonelmismoobjeto'
else
puts'AmbosstringsNOsonelmismoobjeto'
end
end
string1='Jonathan'
string2='Jonathan'
string3=string1
compara_strings(string1,string2,string3)
Dadounstring,invertirlopalabraporpalabra(envezdeletraporletra).
SepuedeusarString.splitquenosdaunarrayformadoporlaspalabrasdelstring.LaclaseArraytieneunmétodoreverse;detalformaquepuedesrevertirelarrayantesdejuntarloparahacerunnuevostring:
palabras='TutorialdeRuby-fácil,sencilloyconfundamento'
putspalabras.split("").reverse.join("")
Ejercicio
Solución
AprendeaprogramarconRuby
35MásMalabaresconStrings
EnRuby,nilyfalsesignificanfalso,todolodemás(incluyendotrue,0)significanverdadero.EnRuby,nilesunobjeto:portanto,tienesusmétodos,yloqueesmás,puedesañadirlosmétodosquesequieran.
Veamosunejemplodeif,else:
xyz=5
ifxyz>4
puts'Lavariablexyzesmayorque4'
puts'Puedoponermásinstruccionesdentrodelif'
ifxyz==5
puts'Sepuedeanidarunbloqueif,else,enddentrodeotro'
else
puts"Partedelbloqueanidado"
end
else
puts'Lavariablexyznoesmayorque4'
puts'Tambiénpuedoponermúltiplessentencias'
end
elseseejecutabasilacondiciónenifnosecumplía.Parapodertomarmásdecisiones,enfuncióndelvalordelavariable,seusaelsif:
#usandoif,elseanidados
puts'Hola,cuálestunombre?'
STDOUT.flush
nombre=gets.chomp
puts'Hola,'+nombre+'.'
ifnombre=='Mojamuto'
puts'Pedazodenombre!!!'
else
ifname=='Enjuto'
puts'...estenombrenoesmocodepavo...'
end
end
#usandoelsif
puts'Hola,cuálestunombre?'
STDOUT.flush
nombre=gets.chomp
puts'Hola,'+nombre+'.'
ifnombre=='Mojamuto'
puts'Pedazodenombre!!!'
elsifnombre=='Enjuto'
puts'...estenombrenoesmocodepavo...'
end
#otramodificación,usandoel||("o"lógico)
Condiciones
if,else
elsif
AprendeaprogramarconRuby
36Condicionales
puts'Hola,cuálestunombre?'
STDOUT.flush
nombre=gets.chomp
puts'Hola,'+nombre+'.'
ifnombre='Mojamuto'||nombre='Enjuto'
puts'Pedazodenombre!!!'
end
Ademásdelaigualdad,existenotrosoperadorescondicionales:
operador significado
== igual
!= distinto
>= mayoroigualque
<= menoroigualque
> mayorque
< menorque
Estainstrucciónesmuyparecidaalif:secreanunaseriedecondiciones,yseejecutalaprimeracondiciónquesecumpla.Porejemplo:
xyz=10
ifxyz%2==0
puts'Lavariablexyzespar'
else
puts'Lavariablexyzesimpar'
end
esequivalentea:
xyz=10
par=case
whenxyz%2==0thentrue
whenxyz%2!=0thenfalse
end
putspar
unless
Rubytieneunaformacontrariaalif:lainstrucciónunless.Ydigocontraria,porqueenifseejecutabaelbloquedo…endsisecumplíalacondición;conunlessseejecutaráelbloquemientrasNOsecumpla.
nombre='Pepe'
unlessnombre=='Enjuto'
puts'Esenombrenotienearteninguno'
end
=begin
SielnombrenoesEnjuto,
case
AprendeaprogramarconRuby
37Condicionales
siempreseejecutaráelbloque.
=end
Escribeunmétodoquepregunteporunaño,yseacapazde:
1. Decirsies,onoesbisiesto.2. Ponerlacantidaddeminutosquetieneelaño.
Ejercicios
AprendeaprogramarconRuby
38Condicionales
Sepuedenhacerbucles(bucle=algoqueserepite)conlainstrucciónwhile:
#Loops
var=0
whilevar<10
putsvar
var+=1
end
EsteesunejemplodecómoenRubyestodounobjeto,inclusivelosnúmeros.Elmétodotimesnecesitadoscosas:
1. unnúmeroentero,delcuáleselmétodo2. unbloque
Loquehacetimesesiterarelbloqueese"número"deveces.
10.timesdo|num|
putsnum
end
Fijarse,quelavariablenumvade0a9;porlotanto,elbloqueseitera10veces.
Bucles
while
times
AprendeaprogramarconRuby
39Bucles
Rubytieneconungeneradordenúmerosaleatorios:elmétodorand.Usandorandseobtieneunnúmeroaleatoriox,talque0<=x<1.Siseledaunparámetro,porejemplorand(5),entoncesseobtieneunnúmeroenteroentre0y4(ambosincluidos).
defcarta_aleatoria
palos=%w{corazonestrebolespicasdiamantes}
numero=%w{12345678910JQK}
#Quierounacartaaleatoriaquetiene:
#-unpaloaleatorio
#-unnúmeroaleatorio
#paloaleatorio
num=palos.length
palo_aleat=rand(num)
#numeroaleatorio
num_aleat=rand(numero.length)
putsnumero[num_aleat]+'de'+palos[palo_aleat]
end
#unacartaaleatoria
carta_aleatoria
#10cartasaleatorias
10.timesdo
carta_aleatoria
end
#NOTA:lavariabledelbucle,
#comonoseusaenelbloque
#nosedefine.
Númerosaleatorios
AprendeaprogramarconRuby
40NúmerosAleatorios
Desdehacetiempoelestilodeprogramaciónfuncional(queseusaporejemploenellenguajeC)esusadoparaprogramar.Enestetipodeprogramación,hayquecentrarseenlospasospararealizarlatarea,ynosolvidamosdecomosemanejanlosdatos.Sinembargo,enlaprogramaciónorientadaaobjetos,losobjetossonlosagentes,eluniversodetuprograma:seprestaatenciónalaestructuradelosdatos.Cuandosediseñaunaclase,sepiensaenlosobjetosqueseráncreadosporesaclase:enlascosasquepodráhacereseobjeto,ylascaracterísticasquelodefinen.
Unobjetoesuncontenedordedatos,queasuvezcontrolaelaccesoadichosdatos.Asociadosalosobjetosestáunaseriedevariablesquelodefinen:susatributos.Ytambiénunconjuntodefuncionesquecreanuninterfazparainteractuarconelobjeto:sonlosmétodos.Unobjetoesunacombinacióndeestadoydemétodosquecambianeseestado.
Unaclaseesusadaparaconstruirunobjeto.Unaclaseescomounmoldeparaobjetos.Yunobjeto,unainstanciadelaclase.Porejemplo,sepuedeusarlaclaseButtonparahacerdocenasdebotones,cadabotónconsupropiocolor,tamaño,forma,…
#Nuestraprimeraclase
#definelaclasePerro
classPerro
#métodoinicializarclase
definitialize(raza,nombre)
#atributos
@raza=raza
@nombre=nombre
end
#métodoladrar
defladrar
puts'Guau!Guau!'
end
#métodosaludar
defsaludar
puts"Soyunperrodelaraza#{@raza}yminombrees#{@nombre}"
end
end
#parahacernuevosobjetos,
#seusaelmétodonew
d=Perro.new('Labrador','Benzy')
putsd.methods.sort
puts"Laiddelojbetoes#{d.object_id}."
ifd.respond_to?("correr")
d.correr
else
puts"Losiento,elobjetonoentiendeelmensaje'correr'"
end
d.ladrar
d.saludar
#conestavariable,apuntamosalmismoobjeto
d1=d
d1.saludar
d=nil
d1.saludar
ElmétodonewseusaparacrearunnuevoobjetodelaclasePerro.Losobjetossoncreadosenelmomentoyelespaciodememoriadondeseguardan,seasignaaunavariable,enestecasolavariabled,queseconocecomovariabledereferencia.
ClasesyObjetos
AprendeaprogramarconRuby
41ClasesyObjetos
Unmétodoreciéncreadonoesunespacioenblanco:unobjetoreciéncreado,puederesponderunmontóndemensajes.Paraverlalistadeesosmensajesométodosdeformaordenada(.sort):
putsd.methods.sort
Elresultadoesunalistadetodoslosmensajesométodosqueelobjetoreciéncreadopuederesponder.Detodosesosmétodos,losobject_idyrespond_to?sonimportantes.
CadaobjetoenRubytieneunúniconúmeroasociadoconél.Sepuedeverdichonúmeromedianteelmétodoobject_id.Ennuestroejemplo:
puts"Elnúmeroqueidentificaalobjetodenotadoporlavariabledes#{d.object_id}."
Sepuedeconocerdeantemano,siunobjetoserácapazderesponderaunmensaje;odichodeotraforma,siunobjetoposeeciertométodo.Paraelloseusarespond_to?.Ennuestroejemplo:
ifd.respond_to?("correr")
d.correr
else
puts"Losiento,elobjetonoentiendeelmensaje'correr'"
end
Puedessaberaquéclaseperteneceunobjetomedianteelmétodoclass.Ennuestroejemplosiponemos:
d=Perro.new('Alsatian','Lassie')
putsd.class.to_s#obtenemosPerro
instance_of?nosdevuelvetruesiunobjetoesinstanciadeunaclasedeterminada.Porejemplo:
num=10
puts(num.instance_of?Fixnum)#true
LasclasesenRubysoninstanciasdelaclaseClass.Cuandosedefineunanuevaclase(p.e.classNombreClase…end),secreaunobjetodelaclaseClassyesasignadoaunaconstante(enestecasoNombreClase).CuandoseusaNombreClase.newparaconstruirunnuevoobjeto,seusaelmétododelaclaseClassparacrearnuevasinstancias;ydespuésseusaelmétodoinicializadordelapropiaclaseNombreClase:laconstrucciónylainicializacióndeunobjetosoncosasdistintas,ypuedenmodificarse.
object_id,respond_to?
class,instance_of?
LaclaseClass
Constructoresliterales
AprendeaprogramarconRuby
42ClasesyObjetos
Significaquesepuedeusarunanotaciónespecial,envezdeusarnewparacrearunnuevoobjetodeesaclase.Lasclasesqueunconstructorliteralpuedecrear,estánenlasiguientetabla:cadavezqueusasunodeestosconstructores,creasunnuevoobjeto.
Clase ConstructorLiteral Ejemplo
String 'ó" "nuevostring"o'nuevostring'
Símbolo : :símboloo:"símboloconespacios"
Array [] [1,2,3,4,5]
Hash {} {"NuevaYor"=>"NY","Oregon"=>"OR"}
Rango ..ó… 0…10ó0..9
Expresionesregulares // /([a-z]+)/
Poresto,yaunqueavecesnoloparezca,siempreestamoscreandoobjetos.EnRuby,todoesunobjeto.
Lainstrucción:
d=nil
hacequedapunteanil,loquesignificaquenoserefiereanada.Sidespuésdeeso,añado:
Rubyd1=nilRuby
entonceselobjetoPerrodejarádeestarapuntadoporlasvariablesyseráobjetivodelrecicladodebasura.ElrecicladodebasuradeRubyesdeltipomarcar-y-borrar(mark-and-sweep):
enlafase"mark"elprogramaquereciclalamemoria,verificasielobjetoestáenuso.Siunobjetoesapuntadoporunavariable,podríaserusado,yportantoeseobjetosemarcaparaserconservado.sinohayvariablequeapuntealobjeto,entonceselobjetonoesmarcado.Yenlafase"sweep"seborranlosobjetosendesusoparaliberarmemoriademodoquepuedavolveraserutilizadaporelintérpretederuby.
Rubyusaunmark-and-sweepconservador:nohaygarantíadequeunobjetoseaeliminadoporelcolector,antesdequetermineelprograma.Sialmacenasalgoenunarray,ysemantieneelarray,tododentrodelarrayesmarcado.Sialmacenasalgoenunaconstanteovariableglobal,entoncessemarcaparasiempre.
Laideadelosmétodosdeclaseesmandarelmensajealaclase,envezdeunadesusinstancias.Losmétodosdeclaseseusanporquealgunasoperacionesquepertenecenaunaclase,nopuedenserrealizadasporsusinstancias.newesunbuenejemplo.Latareadecrearnuevosobjetossólolapuedehacerlaclase;losobjetosnopuedencrearseasímismos.
Recicladodebasura
Métodosdeclase
AprendeaprogramarconRuby
43ClasesyObjetos
Losaccesorespermitenelaccesoalosatributosdelobjeto.
#SINaccesores
classCancion
definitialize(titulo,artista)
@titulo=titulo
@artista=artista
end
deftitulo
@titulo
end
defartista
@artista
end
end
cancion=Cancion.new("Brazil","IveteSangalo")
putscancion.titulo
putscancion.artista
#CONaccesores
classCancion
definitialize(titulo,artista)
@titulo=titulo
@artista=artista
end
#accesordelectura
attr_reader:titulo,:artista
#accesordeescritura
#attr_writer:titulo
#accesordeescrituraylectura
#attr_accessor:titulo
end
cancion=Cancion.new("Brazil","IveteSangalo")
putscancion.titulo
putscancion.artista
Accesor(métodosdeacceso)
AprendeaprogramarconRuby
44Accesores
Veamoscomosepuedeleer/escribirunficheroconunejemplo:
#Abreyleeunfichero
#Seusaunbloque:elficherosecierra
#automáticamentealacabarelbloque.
File.open('fichero.txt','r')do|f1|
whilelinea=f1.gets
putslinea
end
end
#Creaunnuevofichero,yescribe
File.open('text.txt','w')do|f2|
#'\n'eselretornodecarro
f2.puts"Porquelavida\npuedesermaravillosa"
end
ElmétodoFile.openpuedeabrirelficherodediferentesformas:
'r'sólo-lectura,comienzaalprincipiodelfichero.'r+'lectura/escritura,comienzaalprincipiodelfichero.'w'sólo-escritura,creaunnuevoficherooeliminaelcontenidodelfichero,paraempezardecero.
Hayqueconsultarladocumentaciónparaverunalistacompletadelosposiblesmodos.File.openabreunnuevoficherosinohayunbloque;perosiusaunbloque,entonceselficheroseráelargumentodelbloque,ysecerraráautomáticamentecuandotermineelbloque.Sinohaybloque,elficheronosecierradeformaautomática,ysiempre,siemprehayquecerrarunfichero:enelcasodeunficheroabiertoparaescritura,sinosecierra,podríanperdersedatos.
ElmétodoreadlinedeFilecopiaelficherolíneaporlíneadentrodeunarray.Ambosmétodos,openyreadlinespertenecenalaclaseIO,delacualdesciendelaclaseFile;yportanto,sonheredados.
ElmóduloFindhaceunabúsquedadescendenteenlosdirectoriosdeunconjuntoderutas/directorios.Sielargumentoesundirectorio,entonceselresultadoseráeldirectorio,ytodoslosficherosysubdirectoriosquelepertenecen.
require'find'
#muestralaruta./
#queeseldirectoriodeRuby
Find.find('./')do|f|
type=case
#silarutaesunfichero->F
whenFile.file?(f)then"F"
#silarutaesundirectorio->D
whenFile.directory?(f)then"D"
#sinosabemosloquees->?
else"?"
end
#formateaelresultado
puts"#{type}:#{f}"
end
Ficheros:lectura/escritura
Manejandodirectorios
Accesoaleatorio
AprendeaprogramarconRuby
45Ficheros:lecturayescritura
Poraccesoaleatorio,seentiende,empezaraleerelficheroencualquierparte.Supongamos'aleatorio.rb':
aleatorio.rb
puts'SurfingUSA'Ahoraqueremosleerelficheroapartirdelapalabra"USA":
f=File.new("aleatorio.rb")
f.seek(12,IO::SEEK_SET)
printf.readline
f.close
ElmétodoseekdelaclaseIO,buscaunaposicióndadaporelprimerparámetro,delaformaindicadaporelsegundoparámetro.Lasposiblesformasson:
SEEK_CUR-busca(seek)desdeelprimerparámetro,unnúmeroentero,hastalaposiciónactual.SEEK_END-buscadesdeelparámetrodado,hastaelfinaldelfichero.SEEK_SET-buscalaposiciónabsolutadadaporelparámetro::eseloperadordealcance
Javatienelahabilidaddeserializarobjetos:tepermitealmacenarlosenunficheroyluegoreconstruirloscuandoesnecesario.Rubyllamaaestetipodeserializaciónmarshalling.
Salvarunobjetoyalgunosotodosdesuscomponentes,sehacemedianteelmétodoMarshall.dum.Después,sepuederecuperarelobjetousandoMarshall.load.Seprofundizarámásadelanteeneltema.
¿PermiteRubylaserializacióndeobjetos?
AprendeaprogramarconRuby
46Ficheros:lecturayescritura
Cuandoescribestusprimerosprogramas,setiendeaguardartodoelcódigoenunmismofichero.Peroamedidaquecrecescomoprogramador,tusprogramastambiénlohacen,yenalgúnmomentotedaráscuentaquetenerunúnicoficherocontiendotodoelcódigo,espocopráctico.Esmuchomásfácildividirelcódigoengruposycolocarcadagrupoenunfichero:unalibrería(enespañolseríabibliotecadeprogramasomódulos,nodelibros)esunficheroquecontienemétodosyclasesparasuusoaposteriori.Parapoderusarestaslibrerías,necesitasdelosmétodosrequireyload.
Elmétodorequireleeunaúnicavezelficheroespecificado:
hola.rb
puts"Holaatodos!"
Alusarvariasvecesrequire:
require'hola'#Holaatodos!
require'hola'#
require'hola'#
Sivolvemosausarlo,omitesulectura:todaslasclasesymétodosdelfichero,yaestánalmacenadosenmemoria.Portantonosahorramoseltiempodeotralectura.Hayquefijarseenundetallealahoradeusarrequire:
require'hola'#bien
requiredaporhechoquelaextensióndelficheroes.rb,buscandoelfichero'hola.rb'.Aunquenofuese.rb,Rubyseguiríabuscandoentrelasdemásextensioneshastaencontrarunficherodelnombre'hola'.
Elmétodoloadleeelficheroindicadotantasvecescomoaparezcalainstrucción.¿Difícil?Notanto,veamosunejemplo:
load'hola.rb'#Holaatodos!
load'hola.rb'#Holaatodos!
load'hola.rb'#Holaatodos!
Cadavezqueselee,todaslosmétodosdelficherosevuelvenaleer,yestándisponiblesparasuuso.Cuandoseusaloadesporqueseesperaquealgohayacambiadoenelfichero.
RAILS:enRailssesueleusarload.Porejemplo:mientrassedesarrolla,loquesignificaestarprobandolaaplicaciónyhaciendocambiosalmismotiempo,loscambiosseactualizanalreleerelfichero.Usarrequirenotendríaelmismoefecto,puestoqueelficherosehaleídounavez.
Otroejemplo
Usandolibrerías
require
load
AprendeaprogramarconRuby
47Usandolibrerías
moto.rb
classMoto
definitialize(marca,color)
#Atributos(variablesdelobjeto)
@marca=marca
@color=color
end
defarrancar
if(@estado_motor)
puts'Motorencendido'
else
@estado_motor=true
puts'Arrancandoelmotor'
end
end
end
SiahoraqueremosusarlaclaseMoto,enotrofichero:
require'moto.rb'
m=Moto.new('Yamaha','rojo')
m.arrancar
AprendeaprogramarconRuby
48Usandolibrerías
Laherenciadeclasesesunarelacciónentredosclases.Laventajadelaherenciaesquelasclasesqueenunajerarquíaestánenunnivelinferior,heredanlascaracterísticasdelasclasesdenivelessuperiores;yademás,puedenañadirsuspropiascaracterísticas.
Porejemplo:todoslosgatossonmamíferos.Sitodoslosmamíferosrespiran,laclasegatopordescenderdelaclasemamíferoheredaestacaracterística:losgatosrespiran.
Estopuedeprogramarseasí:
classMamifero
defrespirar
puts'inspirar,espirar'
end
end
#elsímbolo<indicaque
#GatoesunasubclasedeMamifero
classGato<Mamifero
defmaullar
puts'Miaaaaaaaaaaau'
end
end
cribas=Gato.new
cribas.respirar
cribas.maullar
Aunquenoseespecificóquelosgatospuedanrespirar,todoslosgatosherederánesacaracterísticadelaclaseMamifero,yaqueelgatoesunasubclasedelosmamíferos.Enelargot,Mamiferoeslasuper-claseoclasepadre,yGatoeslasubclase,oclasehija.Estoesunaventajaparaelprogramador:losgatostienenlacapacidadderespirar,sinhaberloimplementado.
EnRuby,comosemostróenesteesquema,laclaseObjecteslamadredetodaslasclasesenRuby;porlotanto,susmétodosestándisponiblesentodoslosobjetos,exceptoaquellosquesehansobrescrito.
Habrásituacionesdondelaspropiedadesdeunasuper-clasenodeberíanserheredadasporunasubclaseenparticular.Porejemplo,lasavesgeneralmentesabenvolar,perolospingüinossonunasubclasedeAve,ynovuelan:
classAve
defasear
puts'Meestoylimpiandomisplumas.'
end
defvolar
puts'Estoyvolando.'
end
end
classPinguino<Ave
defvolar
puts'Losiento,nosoycapazdevolar.'
end
end
Herenciadeclases
Sobrescriturademétodos(methodoverriding)
AprendeaprogramarconRuby
49Herenciadeclases
p=Pinguino.new
p.asear
p.volar
Sehasobrescritoelmétodovolar.Lagranventajaqueaportaelusodelaherenciadeclases,sellamaprogramacióndiferencial:vamosdelomásgeneralalomásparticular,añadiendoymodificandodondeseanecesario.
Losdosejemplosanterioressontraduccionesdelaguíaonline"RubyUser'sGuide".
classBicicleta
attr_reader:marchas,:ruedas,:asientos#sehablarádeattr_reader
definitialize(marchas=1)
@ruedas=2
@asientos=1
@marchas=marchas
end
end
classTandem<Bicicleta
definitialize(marchas)
super
@asientos=2
end
end
t=Tandem.new(2)
putst.marchas
putst.ruedas
putst.asientos
b=Bicicleta.new
putsb.marchas
putsb.ruedas
putsb.asientos
Cuandounousasuperdentrodeunmétodo,Rubymandaunmensajealaclasemadredelobjetoalquepertenceelmétodo,buscandounmétodoconelmismonombre.Si:
seinvocaconunalistavacíadeargumentos(comoestecaso),superósuper(),nosepasanargumentosalmétododelaclasemadre.seinvocaconargumentos,super(a,b,c),semandandlosargumentosa,b,c.
Enestecaso,seusasuperenelmétodoinitializedeTandem,loqueprovocaelusodelinitializedeBicicletaparacrearinstanciasdeTandem.Lasalidaes:
2
2
2
1
2
1
RAILS:laherenciadeclasesesunadelasclaveseneldesarrollodeRAILS
Super
AprendeaprogramarconRuby
50Herenciadeclases
EnRuby,lasclasesnuncaestáncerradas:siempresepuedenañadirmétodosaunaclase.Estoesválidotantoparalasclasesqueescribas,comoparalasqueyaestánincluidasconelintérprete.Todoloquehayquehacer,escontinuarconladefinicióndelaclase:
require'moto'
m=moto.new('Yamaha','rojo')
m.arrancar
classMoto
definforme_moto
puts'Elcolordelamotoes'+@color
puts'Lamarcadelamotoes'+@marca
end
end
m.informe_moto
AhoraañadamosunmétodoalaclaseString:
classString
defnum_caracteres
putsself.size
end
end
texto='Cieloempedrado,suelomojado'
texto.num_caracteres
Siseescribeunnuevométodoqueconceptualmentepertenecealaclaseoriginal,sepuedereabrirelficherodelaclase,yañadirelmétodoaladefinicióndelaclase.Estohayquehacerlocuandoelmétodoesdeusofrecuente,yseestáseguroquenoentraráenconflictoconotrosmétodosdefinidosenotraslibreríasqueseusenmásadelante.
Sielmétodonoseráusadofrecuentemente,onosequieretomarelriesgodemodificarlaclasedespuésdesucreación,crearunasubclase(verHerencia)eslamejoropción.Unaclasepuedesobrescribirlosmétodosdelaclasedelaquedesciende.Yesmásseguro,porquelaclaseoriginalpermaneceintacta.
LasclasesenRubysólopuedentenerunmétodoconunnombredado.Paratenermétodos"distintos"conelmismonombre,sepuedejugarconelnúmerodeargumentos:
#Uncuadradosepuededefinirdedosformas:
#Cuadrado.new([x_sup,y_izq],ancho,alto)
#Cuadrado.new([x_sup,y_izq],[x_inf,y_der])
classCuadrado
definitialize(*args)#*implicanúmerovariabledeargumentos
ifargs.size<2||args.size>3
puts'ERROR:Estemétodotomadosotresargumentos'
else
ifargs.size==2
puts'Dosargumentos'
else
puts'Tresargumentos'
end
end
Modificandoclases
Sobrecargademétodos(methodsoverloading)
AprendeaprogramarconRuby
51Modificandoclases
end
end
Cuadrado.new([10,23],4,10)#Tresargumentos
Cuadrado.new([10,23],[14,13])#Dosargumentos
Cuadrado.new([10,23],[14,13],4,10)#ERROR:Estemétodotomadosotresargumentos
Elprogramaestáincompleto,peroessuficienteparavercómosepuedeconseguirlasobrecargademétodos.
AprendeaprogramarconRuby
52Modificandoclases
Losobjetosinmutablessonaquellosquenopuedencambiardeestadodespuésdesercreados.Laspropiedadesporlasquedestacanson:
serthread-safe.Losthreadsnopuedencorromperloquenopuedencambiar.facilitarelimplementarlaencapsulación:sipartedelestadodeunobjetoesalmacenadodentrounobjetoinmutable,entonceslosmétodosmodificadorespuedenleerelestadodedichoobjeto,sinmiedoaquemodifiquensuestado.seríndicesenloshashesinmutables,yaquenopuedencambiar.
EnRuby,lamutabilidadesunapropiedaddelosobjetos,nodeunaclaseentera.Cualquierobjeto(oinstancia)sepuedevolverinmutableusandofreeze.
Elmétodofreeze(congelar)evitaqueunobjetopuedamodificarse,convirtiéndoloenunaconstante.Despuésde"congelar"elobjeto,cualquierintentodemodificarlodacomoresultadounTypeError.
str='Unsimplestring'
str.freeze#congelamoselstring
#seintentamodificar(begin)
#yencasodeerror(rescue)
#selanzaunmensaje.VerExcepciones.
begin
str<<'Intentodemodificarlo'
rescue=>err
puts"#{err.class}#{err}"
end
Sinembargo,freezefuncionaconlasreferencias,noconlasvariables:estosignificaquesicreamosunobjetonuevo,ysobreescribimoslavariable,estesepodrámodificar:
str='stringoriginal-'
str.freeze
str+='añadidoaposteriori'
putsstr
Elobjetooriginalnocambió.Sinembargo,lavariablestrserefiereaunnuevoobjeto.Elmétodofrozen?nosdicesiunobjetoestácongeladoono.
Congelandoobjetos
freeze
Lasalidaes-TypeErrorcan'tmodifyfrozenstring.
Lasalidaes-'Originalstring-añadidoaposteriori'
AprendeaprogramarconRuby
53Congelandoobjetos
Javaescapazdeserializarobjetos:puedealmacenarlos,paraluegoreutilizarloscuandoseanecesario.Rubytienetambiénestacapacidad,perolallamamarshaling.Veamosunejemploenelqueapartirdeunaclase,creamosunaseriedeobjetosquealmacenamosyluegorecuperamos:
Laclase"personaje.rb":
classPersonaje
definitialize(vida,tipo,armas)
@vida=vida
@tipo=tipo
@armas=armas
end
attr_reader:vida,:tipo,:armas
end
CreamoslosobjetosylosguardamosenunficherousandoMarshal.dump:
require'personaje'
p1=Personaje.new(120,'Mago',['hechizos','invisibilidad'])
putsp1.vida.to_s+''+p1.tipo+''
p1.armas.eachdo|w|
putsw+''
end
File.open('juego','w+')do|f|
Marshal.dump(p1,f)
end
UsamosMarshal.loadpararecuperarlos:
require'personaje'
File.open('juego')do|f|
@p1=Marshal.load(f)
end
[email protected]_s+''[email protected]+''
@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