Ruby — An introduction

76
Ruby Ruby An introduction to the Ruby programming language An introduction to the Ruby programming language LPOO — MIEIC — FEUP LPOO — MIEIC — FEUP May 2011 May 2011

description

The slides for a lecture about the Ruby programming language. This language was given at FEUP, on a course called "Laboratories of Object-Oriented Programming".

Transcript of Ruby — An introduction

Page 1: Ruby — An introduction

RubyRuby

An introduction to the Ruby programming languageAn introduction to the Ruby programming language

LPOO — MIEIC — FEUPLPOO — MIEIC — FEUP

May 2011May 2011

Page 2: Ruby — An introduction

@goncalossilva@goncalossilva

Page 3: Ruby — An introduction

RubyRuby

Created by Yukihiru “Matz” Matsumoto, in JapanCreated by Yukihiru “Matz” Matsumoto, in Japan

Perl + SmallTalk + Eiffel + Ada + Lisp = RubyPerl + SmallTalk + Eiffel + Ada + Lisp = Ruby

“I wanted a scripting language that was more powerful than Perl, and more object-oriented than Python.” — matz“I wanted a scripting language that was more powerful than Perl, and more object-oriented than Python.” — matz

Page 4: Ruby — An introduction

RubyRuby

Interpreted language, with many implementations: Interpreted language, with many implementations: YARVYARV , , RubiniusRubinius , , JRubyJRuby , etc, etc

Functional, object-oriented, imperative and reflectiveFunctional, object-oriented, imperative and reflective

Dynamically typed, with automatic garbage collection, exception handling andDynamically typed, with automatic garbage collection, exception handling andbuilt-in unit testingbuilt-in unit testing

Optimized for programmer productivity and happinessOptimized for programmer productivity and happiness

Page 5: Ruby — An introduction

BasicsBasics

Page 6: Ruby — An introduction

MethodsMethods

defdef hello_world hello_world()() returnreturn "Hello world!""Hello world!"endend

hello_worldhello_world()()

Page 7: Ruby — An introduction

MethodsMethods

defdef hello_world hello_world # no need for ()# no need for () "Hello world!""Hello world!" # implicit return# implicit returnendend

hello_world hello_world # no need for ()# no need for ()

Page 8: Ruby — An introduction

ClassesClasses

classclass HelloWorld HelloWorld defdef say say "Hello world done right!""Hello world done right!" endendendend

hello_world_object hello_world_object == HelloWorld HelloWorld..newnewhello_world_objecthello_world_object..saysay

Page 9: Ruby — An introduction

It's object-orientedIt's object-oriented

classclass Lecture Lecture defdef initialize initialize((name name == "TBA""TBA",, duration_in_minutes duration_in_minutes == 6060)) @name@name == name name @duration@duration == duration_in_minutes duration_in_minutes//60.060.0;; endend

defdef description description "Name: #{@name}\nDuration: #{@duration} hours""Name: #{@name}\nDuration: #{@duration} hours" endendendend

lecture lecture == Lecture Lecture..newnew(("Ruby""Ruby",, 4545))lecturelecture..descriptiondescription

Page 10: Ruby — An introduction

It's It's reallyreally object-oriented object-oriented

// Java// Javamaximum maximum == Math Math..maxmax((11,, 33))

# Ruby# Rubymaximum maximum == [[11,, 33].].maxmax

Page 11: Ruby — An introduction

It's It's reallyreally object-oriented object-oriented

# Python# Pythonpositive positive == absabs((numnum))

# Ruby# Rubypositive positive == num num..absabs

Page 12: Ruby — An introduction

It's It's reallyreally object-oriented object-oriented

// C// Clength length == strlenstrlen((namename))

# Ruby# Rubylength length == name name..lengthlength

Page 13: Ruby — An introduction

It's It's reallyreally object-oriented object-oriented

In Ruby, all functions and most operators are methods of an objectIn Ruby, all functions and most operators are methods of an object

In Python, for instance, some functions are proceduralIn Python, for instance, some functions are procedural

Classes themselves are instances of Classes themselves are instances of ClassClass

Page 14: Ruby — An introduction

It's It's reallyreally object-oriented object-oriented

Ruby has a permanent notion of the Ruby has a permanent notion of the current objectcurrent object : : selfself

selfself controls how Ruby accesses instance variables controls how Ruby accesses instance variables

All method calls are made on some object, called the All method calls are made on some object, called the receiverreceiver

If no If no receiverreceiver is specified, is specified, selfself is used — it is implicit! is used — it is implicit!

Page 15: Ruby — An introduction

It's It's reallyreally object-oriented object-oriented

# self is "main", an instance of Object# self is "main", an instance of Objectclassclass MyClass MyClass # self is MyClass# self is MyClass

defdef my_method my_method # self will depend on the receiver for this method# self will depend on the receiver for this method endendendend

# self is "main" again, so my_object exists in the main scope# self is "main" again, so my_object exists in the main scopemy_object my_object == MyClass MyClass..newnew

# explicit receiver, so self will be my_object inside my_method# explicit receiver, so self will be my_object inside my_methodmy_objectmy_object..my_methodmy_method

Page 16: Ruby — An introduction

ArraysArrays

Store indexed collections of objects accessible through an integer keyStore indexed collections of objects accessible through an integer key

Can contain objects with different classes simultaneouslyCan contain objects with different classes simultaneously

# array# arraya a == [[11,, "second""second",, 3.143.14]]aa[[22]]

Page 17: Ruby — An introduction

HashesHashes

Store indexed collections of objects accessible through a key which can be anyStore indexed collections of objects accessible through a key which can be anyobjectobject

Slightly less efficient but much more flexibleSlightly less efficient but much more flexible

# hash# hashh h == {{ "string""string" =>=> [[33,,44,,55],], 22 =>=> "everything can be a value!""everything can be a value!",, [[11,,22]] =>=> "everything can be a key!""everything can be a key!"}}hh[[[[11,,22]]]]

Page 18: Ruby — An introduction

SymbolsSymbols

A significant name, generally a static variableA significant name, generally a static variable

// java// javastaticstatic finalfinal intint NORTH NORTH == 11;;// ... more code// ... more codemovemove((NORTHNORTH););

# ruby# rubymovemove(:(:northnorth))

No need to predeclare these constants, they are uniqueNo need to predeclare these constants, they are unique

returnreturn truetrue ifif direction direction ==== ::northnorth

Page 19: Ruby — An introduction

Control StructuresControl Structures

# if# ififif score score..between?between?((100100,, 199199)) puts puts "You rock!""You rock!"elsifelsif score score < 50< 50 puts puts "You suck!""You suck!"elseelse puts puts "Meh""Meh"endend

# while# whilewhilewhile score score < 100< 100 puts puts "You're almost there! Try again...""You're almost there! Try again..." # ...# ...endend

# more goodness with unless, until, case, for, etc# more goodness with unless, until, case, for, etc

# and awesome shortcuts like statement modifiers# and awesome shortcuts like statement modifiersputs puts "You cheated!""You cheated!" ifif score score >=>= 200200

Page 20: Ruby — An introduction

Blocks and IteratorsBlocks and Iterators

Page 21: Ruby — An introduction

BlocksBlocks

A chuck of code enclosed between A chuck of code enclosed between { }{ } or or dodo//endend keywords keywords

Similar to the concept of anonymous methodsSimilar to the concept of anonymous methods

Can take parametersCan take parameters

Can be passed to methods as arguments (at the end, like an extra parameter)Can be passed to methods as arguments (at the end, like an extra parameter)

sum sum == 00((11....55).).each each dodo ||nn|| # same as [1,2,3,4,5]# same as [1,2,3,4,5] sum sum +=+= n nendendsumsum

# same thing with { }# same thing with { }sum sum == 00((11....55).).each each {{ ||nn|| sum sum +=+= n n }}sumsum

Page 22: Ruby — An introduction

Blocks as ObjectsBlocks as Objects

Can be converted into objectsCan be converted into objects

Can be stored in variables, pass them around, invoke them whenever you wantCan be stored in variables, pass them around, invoke them whenever you want

Great for implementing callbacks, dispatch tables, etcGreat for implementing callbacks, dispatch tables, etc

classclass BlockAsObject BlockAsObject defdef store_block store_block(&(&my_blockmy_block)) @stored_block@stored_block == my_block my_block # converted to Proc# converted to Proc endend

defdef use_block use_block((parameterparameter)) @stored_block@stored_block..callcall((parameterparameter)) endendendend

foo foo == BlockAsObject BlockAsObject..newnewfoofoo..store_block store_block {{ ||paramparam|| "The block was called with ""The block was called with " ++ param param }}foofoo..use_blockuse_block(("delay""delay"))

Page 23: Ruby — An introduction

Blocks as ClosuresBlocks as Closures

They can use local variables from the surrounding scopeThey can use local variables from the surrounding scope

defdef powers_of_2_proc powers_of_2_proc value value == 11 lambda lambda {{ value value +=+= value value }}endend

powers_of_2 powers_of_2 == powers_of_2_proc powers_of_2_proc

powers_of_2powers_of_2..call call # 2# 2powers_of_2powers_of_2..call call # 4# 4powers_of_2powers_of_2..call call # will return 8!# will return 8!

So, So, powers_of_2_procpowers_of_2_proc returns a returns a ProcProc that references that references valuevalue

When the block is called, When the block is called, valuevalue is out of scope is out of scope

The block is still able to access it (and will be for the remaining life of this block)The block is still able to access it (and will be for the remaining life of this block)

Page 24: Ruby — An introduction

IteratorsIterators

In many languages, collections implement methods to generate external iteratorIn many languages, collections implement methods to generate external iteratorobjectsobjects

// C++// C++forfor ((stdstd::::vectorvector<<intint>::>::iteratoriterator ii==listlist..beginbegin();(); i i!=!=listlist..endend();(); i i++)++) {{ // code// code}}

Page 25: Ruby — An introduction

IteratorsIterators

In many languages, collections implement methods to generate external iteratorIn many languages, collections implement methods to generate external iteratorobjectsobjects

// C#// C#IEnumerator<int>IEnumerator<int> i i == list list..GetEnumeratorGetEnumerator();();whilewhile ((ii..MoveNextMoveNext())()) {{ // code// code}}

Page 26: Ruby — An introduction

IteratorsIterators

In many languages, collections implement methods to generate external iteratorIn many languages, collections implement methods to generate external iteratorobjectsobjects

// Java// JavaIteratorIterator i i == list list..iteratoriterator();();whilewhile ((ii..hasNexthasNext())()) {{ // code// code}}

Page 27: Ruby — An introduction

IteratorsIterators

When coming from other languages, many people iterate collections like this:When coming from other languages, many people iterate collections like this:

# familiar?# familiar?forfor i i inin 00....22 number number == array array[[ii][][00]] word word == array array[[ii][][11]]

puts puts "#{word}: #{number}""#{word}: #{number}"endend

Page 28: Ruby — An introduction

IteratorsIterators

However, there's another approach:However, there's another approach:

# the "ruby way", with a lot less coupling# the "ruby way", with a lot less couplingarrayarray..each each dodo ||wordword,, number number|| puts puts "#{word}: #{number}""#{word}: #{number}"endend

The “Ruby way” is different: an iterator is internal to the collection... it's just aThe “Ruby way” is different: an iterator is internal to the collection... it's just amethod that calls method that calls yieldyield every time it generates a new value every time it generates a new value

Page 29: Ruby — An introduction

IteratorsIterators

Ruby provides a lot of useful iterators: Ruby provides a lot of useful iterators: eacheach, , mapmap , , injectinject , etc, etc

But you can build your ownBut you can build your own

defdef fib fib((maxmax)) i1 i1,, i2 i2 == 11,, 11 # parallel assignment# parallel assignment whilewhile i1 i1 <= max<= max yieldyield i1 i1 i1 i1,, i2 i2 == i2 i2,, i1 i1++i2i2 endendendend

result result == """"fibfib((13371337)) {{ ||nn|| result result +=+= "#{n} ""#{n} " }}resultresult

Page 30: Ruby — An introduction

IteratorsIterators

Ruby's internal iterators aren't necessarily the best solutionRuby's internal iterators aren't necessarily the best solution

What if you need the iterator to be an object?What if you need the iterator to be an object?

What if you want to iterate multiple collections simultaneously?What if you want to iterate multiple collections simultaneously?

Page 31: Ruby — An introduction

EnumeratorsEnumerators

When iterators aren't suitable, you can resort to enumeratorsWhen iterators aren't suitable, you can resort to enumerators

To put it simply, an enumerator is an external iteratorTo put it simply, an enumerator is an external iterator

array array == [["my""my",, 13371337,, "array""array"]]enumerator enumerator == array array..to_enum to_enum # same as "enumerator = array.each"# same as "enumerator = array.each"

enumeratorenumerator..nextnext # returns "my" and moves to the next element# returns "my" and moves to the next elementenumeratorenumerator..nextnext

Page 32: Ruby — An introduction

EnumeratorsEnumerators

Most internal iterators are can be used as enumeratorsMost internal iterators are can be used as enumerators

string string == "le fu""le fu"enumerator enumerator == string string..each_chareach_char

enumeratorenumerator..nextnext # returns "l" and moves to the next char# returns "l" and moves to the next charenumeratorenumerator..nextnext # returns "e" and moves to the next char# returns "e" and moves to the next char

Page 33: Ruby — An introduction

Containers, containers, containers!Containers, containers, containers!

Blocks and iterators are core concepts of RubyBlocks and iterators are core concepts of Ruby

With practice, you'll start building classes that iterate over their contents insteadWith practice, you'll start building classes that iterate over their contents insteadof using the conventional looping constructsof using the conventional looping constructs

It might seem complicated at first, but you'll start using these features naturallyIt might seem complicated at first, but you'll start using these features naturally

Easy to read and maintainEasy to read and maintain

Page 34: Ruby — An introduction

SharingSharingFunctionalityFunctionality

Page 35: Ruby — An introduction

InheritanceInheritance

classclass SuperClass SuperClass defdef hello_world hello_world "Hello world!""Hello world!" endendendend

classclass SubClass SubClass < SuperClass< SuperClassendend

superclass superclass == SuperClass SuperClass..newnewsubclass subclass == SubClass SubClass..newnew

"Hello world from the superclass: #{superclass.hello_world}\n""Hello world from the superclass: #{superclass.hello_world}\n" ++"Hello world from the subclass : #{subclass.hello_world}""Hello world from the subclass : #{subclass.hello_world}"

Page 36: Ruby — An introduction

InheritanceInheritance

Single inheritance, unlike C++Single inheritance, unlike C++

Top-level classes are subclasses of Top-level classes are subclasses of ObjectObject , which is a subclass of , which is a subclass of BasicObjectBasicObject

Classes have built-in functionality because they inherited it!Classes have built-in functionality because they inherited it!

Page 37: Ruby — An introduction

ModulesModules

Modules provide a namespace, avoiding name collisionsModules provide a namespace, avoiding name collisions

modulemodule MyModule MyModule # a module has it all# a module has it all MY_CONSTANT MY_CONSTANT == "my constant""my constant" # constants# constants

defdef my_method my_method # methods# methods endend

classclass MyClass MyClass # and classes# and classes endendendend

namespaced namespaced == MyModule MyModule::::MyClassMyClass..newnew

Modules have another wonderful use: Modules have another wonderful use: mixinsmixins

Page 38: Ruby — An introduction

Mixins and InheritanceMixins and Inheritance

Some OO languages support multiple inheritance (C++, Lisp, Python, etc)Some OO languages support multiple inheritance (C++, Lisp, Python, etc)

This is very powerful, but can be troublesome because of inheritance ambiguityThis is very powerful, but can be troublesome because of inheritance ambiguity

Ruby offers a great compromise: the simplicity of single inheritance and theRuby offers a great compromise: the simplicity of single inheritance and thepower of multiple inheritancepower of multiple inheritance

Page 39: Ruby — An introduction

MixinsMixins

includeinclude is used to mix modules into classes or other modules is used to mix modules into classes or other modules

modulemodule ToBeIncluded ToBeIncluded defdef foo foo "bar""bar" endendendend

classclass MyClass MyClass includeinclude ToBeIncluded ToBeIncludedendend

object object == MyClass MyClass..newnewobjectobject..foofoo

Page 40: Ruby — An introduction

MixinsMixins

extendextend is used to add instance methods to a given object is used to add instance methods to a given object

modulemodule ToBeIncluded ToBeIncluded defdef foo foo "bar""bar" endendendend

classclass MyClass MyClassendend

object object == MyClass MyClass..newnewobjectobject..extend ToBeIncludedextend ToBeIncludedobjectobject..foofoo

Page 41: Ruby — An introduction

MixinsMixins

extendextend is also used to mix instance methods into a class is also used to mix instance methods into a class

modulemodule ToBeIncluded ToBeIncluded defdef foo foo "bar""bar" endendendend

classclass MyClass MyClass extend ToBeIncluded extend ToBeIncludedendend

MyClassMyClass..foofoo

Page 42: Ruby — An introduction

modulemodule StringHelpers StringHelpers defdef stringify stringify ifif selfself..value value >> 90009000 "Over 9000!""Over 9000!" elseelse "Meh""Meh" endend endend endend

classclass Number Number attr_reader attr_reader ::valuevalue defdef initialize initialize((valuevalue)) @value@value == value value endend endend

classclass Over9000Number Over9000Number < Number< Number includeinclude StringHelpers StringHelpers defdef initialize initialize((valuevalue)) supersuper((value value ++ 90009000)) endend defdef status status "Current status: ""Current status: "++stringifystringify endend endend

number number == Over9000Number Over9000Number..newnew((4242)) number number..statusstatus # => "Current status: Over 9000!"# => "Current status: Over 9000!"

MixinsMixins

Inherit from one class, include functionality from multiple modules — Inherit from one class, include functionality from multiple modules — mixinsmixins !!

Page 43: Ruby — An introduction

Inheritance, Mixins and DesignInheritance, Mixins and Design

Ruby allows you to right code once and inject it into multiple placesRuby allows you to right code once and inject it into multiple places

When to use each?When to use each?

InheritanceInheritance

You should be able to replace a parent object with a child object, honoringYou should be able to replace a parent object with a child object, honoringits contractits contract

A child object A child object is ais a kind of the parent (an apple is a fruit) kind of the parent (an apple is a fruit)

In the real world, strict hierarchies are restrictive... we need composition!In the real world, strict hierarchies are restrictive... we need composition!

MixinsMixins

For composition: A For composition: A has ahas a B, or A B, or A uses auses a B B

Exclusively using Exclusively using mixinsmixins can be messy — both should be combined can be messy — both should be combined

Page 44: Ruby — An introduction

Inheritance, Mixis and DesignInheritance, Mixis and Design

Each of them serves its purpose, our job is to use the appropriatelyEach of them serves its purpose, our job is to use the appropriately

None of these make any sense:None of these make any sense:

classclass Person Person < DataWrapper< DataWrapperendend

classclass Banana Banana includeinclude FruitProperties FruitPropertiesendend

Think before you typeThink before you type

Page 45: Ruby — An introduction

ReflectionReflection

Page 46: Ruby — An introduction

ReflectionReflection

Ruby is very powerful when it comes to examining the aspects of a programRuby is very powerful when it comes to examining the aspects of a programwithin itselfwithin itself

It can discover information about:It can discover information about:

What objects existWhat objects exist

All class hierarchiesAll class hierarchies

Attributes and methods of all objectsAttributes and methods of all objects

Information about methodsInformation about methods

“When you introspect, you think about your thoughts and feelings. This is interesting because you're using thought to“When you introspect, you think about your thoughts and feelings. This is interesting because you're using thought toanalyze thought.” — Dave Thomasanalyze thought.” — Dave Thomas

Page 47: Ruby — An introduction

Reflection and ObjectsReflection and Objects

You can transverse all living objects:You can transverse all living objects:

ObjectSpaceObjectSpace..each_objecteach_object((FloatFloat)) {{ ||xx|| puts x puts x }}

Page 48: Ruby — An introduction

Reflection and ObjectsReflection and Objects

You can look inside objects:You can look inside objects:

[[11,,22,,33].].methodsmethods[[00....44]]

[[11,,22,,33].].respond_respond_to?to?(:(:to_sto_s))

[[11,,22,,33].].kind_kind_of?of?((HashHash))

Page 49: Ruby — An introduction

Reflection and ObjectsReflection and Objects

You can invoke any method by name using You can invoke any method by name using sendsend ::

a a == [[11,,22,,33]]aa..sendsend((aa..private_methodsprivate_methods..firstfirst..to_symto_sym)) # "initialize"# "initialize"a a # now it's empty!# now it's empty!

Page 50: Ruby — An introduction

Reflection and ObjectsReflection and Objects

Another way is to use the Another way is to use the MethodMethod class: class:

a a == [[11,,22,,33]]constructor constructor == a a..methodmethod(:(:initializeinitialize))constructorconstructor..callcallaa

You get a You get a MethodMethod object which you can store, pass around and call anytime! object which you can store, pass around and call anytime!

Page 51: Ruby — An introduction

Reflection and ClassesReflection and Classes

It's also possible to look inside classes:It's also possible to look inside classes:

StringString..ancestors ancestors # all superclasses and mixed-in modules# all superclasses and mixed-in modules

Page 52: Ruby — An introduction

Reflection and ClassesReflection and Classes

It's also possible to look inside classes:It's also possible to look inside classes:

klass klass == String Stringresult result == klass klass..to_sto_sbeginbegin klass klass == klass klass..superclasssuperclass result result +=+= " < "" < " ++ klass klass..to_sto_sendend whilewhile klass klass..superclasssuperclassresultresult

Page 53: Ruby — An introduction

Reflection and ClassesReflection and Classes

It's also possible to look inside classes:It's also possible to look inside classes:

FixnumFixnum..constantsconstants

FixnumFixnum..class_variablesclass_variables

FixnumFixnum..singleton_methodssingleton_methods((falsefalse))

FixnumFixnum..instance_methodsinstance_methods((falsefalse)) # private/protected/public prefix# private/protected/public prefix

Page 54: Ruby — An introduction

Reflection and the Program'sReflection and the Program'sExecutionExecution

Ruby let's you look at the interpreter while it executes your codeRuby let's you look at the interpreter while it executes your code

set_trace_func lambda set_trace_func lambda {{ ||eventevent,, file file,, line line,, id id,, binding binding,, classname classname|| printf printf "%8s %s:%s-2d %-15s\n""%8s %s:%s-2d %-15s\n",, event event,, file file,, line line,, classname classname,, id id}}

# all code is traced from now on# all code is traced from now on

And you can also get the current call stack by using calling And you can also get the current call stack by using calling callercaller on your on yourmethodsmethods

Page 55: Ruby — An introduction

Reflection and the Program'sReflection and the Program'sExecutionExecution

You can even get the current source file being executed with the You can even get the current source file being executed with the __FILE____FILE__ special specialvariable, leading to an interesting variable, leading to an interesting QuineQuine ::

print Fileprint File..readread((__FILE____FILE__))

A program that outputs itself!A program that outputs itself!

Page 56: Ruby — An introduction

MetaprogrammingMetaprogramming

Page 57: Ruby — An introduction

MetaprogrammingMetaprogramming

Ruby code can modify aspects of its own structure at runtime and it makes it allRuby code can modify aspects of its own structure at runtime and it makes it alleasyeasy

You've seen it before on this presentation: remember You've seen it before on this presentation: remember includeinclude and and extendextend? Ruby is? Ruby iseffectively injecting their code into their receivereffectively injecting their code into their receiver

Page 58: Ruby — An introduction

Singleton MethodsSingleton Methods

Ruby lets you define methods specific to a particular objectRuby lets you define methods specific to a particular object

person person == "person""person" # String object# String objectdefdef person person..say_hisay_hi "Hi!""Hi!"endendpersonperson..say_hisay_hi

Magic? No. Ruby created an anonymous class (often called singleton class) basedMagic? No. Ruby created an anonymous class (often called singleton class) basedon on StringString and added the method and added the method say_hisay_hi to it to it

Page 59: Ruby — An introduction

Singleton ClassSingleton Class

There are other ways of creating methods in an object's singleton classThere are other ways of creating methods in an object's singleton class

person person == "person""person"classclass << person<< person defdef say_hi say_hi "Hi there!""Hi there!" endendendendpersonperson..say_hisay_hi

Page 60: Ruby — An introduction

Inherited VisibilityInherited Visibility

The visibility of an inherited method can be changedThe visibility of an inherited method can be changed

classclass SuperClass SuperClass private private defdef my_private_method my_private_method "U can't touch this""U can't touch this" endendendend

classclass SubClass SubClass < SuperClass< SuperClass public public ::my_private_methodmy_private_methodendend

object object == SubClass SubClass..newnewobjectobject..my_private_method my_private_method # not so private anymore# not so private anymore

Page 61: Ruby — An introduction

Inherited VisibilityInherited Visibility

What's really happening is that Ruby is inserting a hidden proxy method in theWhat's really happening is that Ruby is inserting a hidden proxy method in thesubclass that invokes the original method with subclass that invokes the original method with supersuper

classclass SubClass SubClass < SuperClass< SuperClass defdef my_private_method my_private_method supersuper endend

public public ::my_private_methodmy_private_methodendend

supersuper calls can access the parent's method regardless of its visibility calls can access the parent's method regardless of its visibility

Page 62: Ruby — An introduction

Defining MethodsDefining Methods

Ruby allows you to define methods at runtime using Ruby allows you to define methods at runtime using define_methoddefine_method

classclass BabyInfo BabyInfo [["cry""cry",, "eat""eat",, "poop""poop"].].each each dodo ||baby_actionbaby_action|| define_method define_method((baby_actionbaby_action)) dodo "Of course, babies #{baby_action}""Of course, babies #{baby_action}" endend endendendend

baby_info baby_info == BabyInfo BabyInfo..newnewbaby_infobaby_info..crycry

Methods can also be blocked/removed by calling Methods can also be blocked/removed by calling undef_methodundef_method and and remove_methodremove_method,,respectivelyrespectively

Page 63: Ruby — An introduction

Class-level MacrosClass-level Macros

Ruby has a few class-level macros that generate code behind the scenesRuby has a few class-level macros that generate code behind the scenes

classclass Laptop Laptop attr_accessor attr_accessor ::memory memory # injects a getter/setter for "memory"# injects a getter/setter for "memory"endend

If you've used Ruby on Rails, you've probably dealt with associationsIf you've used Ruby on Rails, you've probably dealt with associations

classclass Post Post < ActiveRecord::Base< ActiveRecord::Base has_many has_many ::commentscommentsendend

Page 64: Ruby — An introduction

EvalEval

Similarly to other languages, Similarly to other languages, evaleval evaluates the passed Ruby expression(s) evaluates the passed Ruby expression(s)

course course == "LPOO""LPOO"eval eval "'Hello ' + course + '!'""'Hello ' + course + '!'"

Page 65: Ruby — An introduction

Instance evalInstance eval

instance_evalinstance_eval allows you to evaluate Ruby expression(s) in the context of an allows you to evaluate Ruby expression(s) in the context of aninstanceinstance

string string == "cool man cool""cool man cool"stringstring..instance_eval instance_eval "def shout; self.upcase; end""def shout; self.upcase; end"stringstring..shoutshout

Remember: classes are instances of Remember: classes are instances of ClassClass, so you can also use , so you can also use instance_evalinstance_eval with withthem:them:

FixnumFixnum..instance_eval instance_eval "def ten; 10; end""def ten; 10; end"FixnumFixnum..tenten

Page 66: Ruby — An introduction

Class evalClass eval

As the name implies, As the name implies, class_evalclass_eval can only be used with classes can only be used with classes

It evaluates the code as if you were in the context of the class definitionIt evaluates the code as if you were in the context of the class definition

StringString..class_eval class_eval dodo defdef shout shout selfself..upcaseupcase endendendendstring string == "cool man cool""cool man cool"stringstring..shoutshout

Note: Note: evaleval, , instance_evalinstance_eval and and class_evalclass_eval can take blocks as arguments as shown can take blocks as arguments as shownaboveabove

Page 67: Ruby — An introduction

Eval evilnessEval evilness

evaleval is slow is slow

evaleval is dangerous is dangerous

evaleval doesn't generally make sense, given all other metaprogramming facilities doesn't generally make sense, given all other metaprogramming facilities

Page 68: Ruby — An introduction

CallbacksCallbacks

Ruby provides Ruby provides hook methodshook methods , called by the interpreter when a specific event, called by the interpreter when a specific eventoccursoccurs

Among all available Among all available hook methodshook methods —also known as —also known as callbackscallbacks—are:—are:

Method-related hooks: Method-related hooks: method_addedmethod_added, , method_missingmethod_missing, , method_removedmethod_removed, etc, etc

Class/Module-related hooks: Class/Module-related hooks: const_missingconst_missing, , extendedextended, , includedincluded, , inheritedinherited, etc, etc

Object marshaling and coercion hooksObject marshaling and coercion hooks

Page 69: Ruby — An introduction

Callbacks: Callbacks: method_missingmethod_missing

Ruby allows you to act upon calls to undefined methods by using Ruby allows you to act upon calls to undefined methods by using method missingmethod missing

classclass BabyInfo BabyInfo [["cry""cry",, "eat""eat",, "poop""poop"].].each each dodo ||baby_actionbaby_action|| define_method define_method((baby_actionbaby_action)) dodo "Of course, babies #{baby_action}""Of course, babies #{baby_action}" endend endend

defdef method_missing method_missing((namename,, **argsargs,, &&blockblock)) "Nope, babies don't #{name}""Nope, babies don't #{name}" endendendend

baby_info baby_info == BabyInfo BabyInfo..newnewbaby_infobaby_info..surfsurf

Page 70: Ruby — An introduction

Callbacks: Callbacks: inheritedinherited

Ruby allows your classes to act when they're subclassedRuby allows your classes to act when they're subclassed

classclass SuperClass SuperClass @children@children == [][] # class variable# class variable

defdef selfself..inheritedinherited((childchild)) @children@children << child<< child endend

defdef selfself..childrenchildren @children@children endendendend

Page 71: Ruby — An introduction

Callback: method callsCallback: method calls

Ruby allows you to intercept calls to specific methods:Ruby allows you to intercept calls to specific methods:

classclass Object Object alias_method alias_method ::old_to_sold_to_s,, ::to_sto_s defdef to_s to_s result result == selfself..old_to_sold_to_s "Your modified to_s returned this (should be '""Your modified to_s returned this (should be '"++resultresult++"')""')" endendendend

object object == Object Object..newnewobjectobject..to_sto_s

This isn't a direct hook: you're copying the original method and inserting a hookThis isn't a direct hook: you're copying the original method and inserting a hookby yourselfby yourself

Page 72: Ruby — An introduction

Wrapping UpWrapping Up

Page 73: Ruby — An introduction

RubyRuby

Ruby is an incredibly powerful languageRuby is an incredibly powerful language

Many successful projects/products use it at their core: Ruby on Rails, God,Many successful projects/products use it at their core: Ruby on Rails, God,Redmine, etcRedmine, etc

You can add and remove code in a running process, redefine methods on the fly,You can add and remove code in a running process, redefine methods on the fly,change their scopechange their scope

You can even modify basic types like You can even modify basic types like StringString, , FloatFloat or even or even ClassClass and and ObjectObject

After using it for a while, you'll notice the lack of flexibility on static languagesAfter using it for a while, you'll notice the lack of flexibility on static languageslike C++ or half-static languages like Javalike C++ or half-static languages like Java

Page 74: Ruby — An introduction

RubyRuby

This presentation, for instance, is running on a Sinatra applicationThis presentation, for instance, is running on a Sinatra application

And most of the shown code was executed in real timeAnd most of the shown code was executed in real time

No? Then check this out:No? Then check this out:

classclass Lecture Lecture defdef initialize initialize((name name == "TBA""TBA")) @name@name == name name endend

defdef finish finish "Finished at #{(Time.now.utc+3600).strftime('%H:%M:%S')}!""Finished at #{(Time.now.utc+3600).strftime('%H:%M:%S')}!" endendendend

lecture lecture == Lecture Lecture..newnew(("Ruby""Ruby"))lecturelecture..finishfinish

Page 75: Ruby — An introduction

MoreMore

Books:Books:

Programming Ruby 1.9 by Dave ThomasProgramming Ruby 1.9 by Dave Thomas

Metaprogramming Ruby by Paolo PerrottaMetaprogramming Ruby by Paolo Perrotta

Mailing lists:Mailing lists:

Ruby-Talk (subscribe through Ruby-Talk (subscribe through Ruby's websiteRuby's website))

Ruby-pt (Google Groups)Ruby-pt (Google Groups)

IRC:IRC:

#ruby and #ruby-pt on Freenode#ruby and #ruby-pt on Freenode

Page 76: Ruby — An introduction

??