Ruby — An introduction


Published on

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".

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Ruby — An introduction

  1. 1. RubyAn introduction to the Ruby programming language LPOO — MIEIC — FEUP May 2011
  2. 2. @goncalossilva
  3. 3. Ruby Created by Yukihiru “Matz” Matsumoto, in Japan Perl + SmallTalk + Eiffel + Ada + Lisp = Ruby“I wanted a scripting language that was more powerful than Perl, and more object-oriented than Python.” — matz
  4. 4. Ruby Interpreted language, with many implementations: YARV , Rubinius , JRuby , etc Functional, object-oriented, imperative and reflective Dynamically typed, with automatic garbage collection, exception handling andbuilt-in unit testing Optimized for programmer productivity and happiness
  5. 5. Basics
  6. 6. Methodsdef hello_world() return "Hello world!"endhello_world()
  7. 7. Methodsdef hello_world # no need for () "Hello world!" # implicit returnendhello_world # no need for ()
  8. 8. Classesclass HelloWorld def say "Hello world done right!" endendhello_world_object = HelloWorld.newhello_world_object.say
  9. 9. Its object-orientedclass Lecture def initialize(name = "TBA", duration_in_minutes = 60) @name = name @duration = duration_in_minutes/60.0; end def description "Name: #{@name}nDuration: #{@duration} hours" endendlecture ="Ruby", 45)lecture.description
  10. 10. Its really object-oriented// Javamaximum = Math.max(1, 3)# Rubymaximum = [1, 3].max
  11. 11. Its really object-oriented# Pythonpositive = abs(num)# Rubypositive = num.abs
  12. 12. Its really object-oriented// Clength = strlen(name)# Rubylength = name.length
  13. 13. Its really object-orientedIn Ruby, all functions and most operators are methods of an objectIn Python, for instance, some functions are proceduralClasses themselves are instances of Class
  14. 14. Its really object-orientedRuby has a permanent notion of the current object : selfself controls how Ruby accesses instance variablesAll method calls are made on some object, called the receiverIf no receiver is specified, self is used — it is implicit!
  15. 15. Its really object-oriented# self is "main", an instance of Objectclass MyClass # self is MyClass def my_method # self will depend on the receiver for this method endend# self is "main" again, so my_object exists in the main scopemy_object = explicit receiver, so self will be my_object inside my_methodmy_object.my_method
  16. 16. Arrays Store indexed collections of objects accessible through an integer key Can contain objects with different classes simultaneously# arraya = [1, "second", 3.14]a[2]
  17. 17. Hashes Store indexed collections of objects accessible through a key which can be anyobject Slightly less efficient but much more flexible# hashh = { "string" => [3,4,5], 2 => "everything can be a value!", [1,2] => "everything can be a key!"}h[[1,2]]
  18. 18. Symbols A significant name, generally a static variable// javastatic final int NORTH = 1;// ... more codemove(NORTH);# rubymove(:north) No need to predeclare these constants, they are uniquereturn true if direction == :north
  19. 19. Control Structures# ifif score.between?(100, 199) puts "You rock!"elsif score < 50 puts "You suck!"else puts "Meh"end# whilewhile score < 100 puts "Youre almost there! Try again..." # ...end# more goodness with unless, until, case, for, etc# and awesome shortcuts like statement modifiersputs "You cheated!" if score >= 200
  20. 20. Blocks and Iterators
  21. 21. Blocks A chuck of code enclosed between { } or do/end keywords Similar to the concept of anonymous methods Can take parameters Can be passed to methods as arguments (at the end, like an extra parameter)sum = 0(1..5).each do |n| # same as [1,2,3,4,5] sum += nendsum# same thing with { }sum = 0(1..5).each { |n| sum += n }sum
  22. 22. Blocks as Objects Can be converted into objects Can be stored in variables, pass them around, invoke them whenever you want Great for implementing callbacks, dispatch tables, etcclass BlockAsObject def store_block(&my_block) @stored_block = my_block # converted to Proc end def use_block(parameter) endendfoo = BlockAsObject.newfoo.store_block { |param| "The block was called with " + param }foo.use_block("delay")
  23. 23. Blocks as Closures They can use local variables from the surrounding scopedef powers_of_2_proc value = 1 lambda { value += value }endpowers_of_2 = # # # will return 8! So, powers_of_2_proc returns a Proc that references value When the block is called, value is out of scope The block is still able to access it (and will be for the remaining life of this block)
  24. 24. Iterators In many languages, collections implement methods to generate external iteratorobjects// C++for (std::vector<int>::iterator i=list.begin(); i!=list.end(); i++) { // code}
  25. 25. Iterators In many languages, collections implement methods to generate external iteratorobjects// C#IEnumerator<int> i = list.GetEnumerator();while (i.MoveNext()) { // code}
  26. 26. Iterators In many languages, collections implement methods to generate external iteratorobjects// JavaIterator i = list.iterator();while (i.hasNext()) { // code}
  27. 27. Iterators When coming from other languages, many people iterate collections like this:# familiar?for i in 0..2 number = array[i][0] word = array[i][1] puts "#{word}: #{number}"end
  28. 28. Iterators However, theres another approach:# the "ruby way", with a lot less couplingarray.each do |word, number| puts "#{word}: #{number}"end The “Ruby way” is different: an iterator is internal to the collection... its just amethod that calls yield every time it generates a new value
  29. 29. Iterators Ruby provides a lot of useful iterators: each, map , inject , etc But you can build your owndef fib(max) i1, i2 = 1, 1 # parallel assignment while i1 <= max yield i1 i1, i2 = i2, i1+i2 endendresult = ""fib(1337) { |n| result += "#{n} " }result
  30. 30. IteratorsRubys internal iterators arent necessarily the best solutionWhat if you need the iterator to be an object?What if you want to iterate multiple collections simultaneously?
  31. 31. Enumerators When iterators arent suitable, you can resort to enumerators To put it simply, an enumerator is an external iteratorarray = ["my", 1337, "array"]enumerator = array.to_enum # same as "enumerator = array.each" # returns "my" and moves to the next
  32. 32. Enumerators Most internal iterators are can be used as enumeratorsstring = "le fu"enumerator = # returns "l" and moves to the next # returns "e" and moves to the next char
  33. 33. Containers, containers, containers! Blocks and iterators are core concepts of Ruby With practice, youll start building classes that iterate over their contents insteadof using the conventional looping constructs It might seem complicated at first, but youll start using these features naturally Easy to read and maintain
  34. 34. SharingFunctionality
  35. 35. Inheritanceclass SuperClass def hello_world "Hello world!" endendclass SubClass < SuperClassendsuperclass = SuperClass.newsubclass ="Hello world from the superclass: #{superclass.hello_world}n" +"Hello world from the subclass : #{subclass.hello_world}"
  36. 36. InheritanceSingle inheritance, unlike C++Top-level classes are subclasses of Object , which is a subclass of BasicObjectClasses have built-in functionality because they inherited it!
  37. 37. Modules Modules provide a namespace, avoiding name collisionsmodule MyModule # a module has it all MY_CONSTANT = "my constant" # constants def my_method # methods end class MyClass # and classes endendnamespaced = Modules have another wonderful use: mixins
  38. 38. Mixins and Inheritance Some OO languages support multiple inheritance (C++, Lisp, Python, etc) This is very powerful, but can be troublesome because of inheritance ambiguity Ruby offers a great compromise: the simplicity of single inheritance and thepower of multiple inheritance
  39. 39. Mixins include is used to mix modules into classes or other modulesmodule ToBeIncluded def foo "bar" endendclass MyClass include ToBeIncludedendobject =
  40. 40. Mixins extend is used to add instance methods to a given objectmodule ToBeIncluded def foo "bar" endendclass MyClassendobject = MyClass.newobject.extend
  41. 41. Mixins extend is also used to mix instance methods into a classmodule ToBeIncluded def foo "bar" endendclass MyClass extend
  42. 42. Mixinsmodule StringHelpers class Over9000Number < Number def stringify include StringHelpers if self.value > 9000 "Over 9000!" def initialize(value) else super(value + 9000) "Meh" end end end def statusend "Current status: "+stringify endclass Number end attr_reader :value number = def initialize(value) number.status @value = value # => "Current status: Over 9000!" endend Inherit from one class, include functionality from multiple modules — mixins !
  43. 43. Inheritance, Mixins and DesignRuby allows you to right code once and inject it into multiple placesWhen to use each? Inheritance You should be able to replace a parent object with a child object, honoring its contract A child object is a kind of the parent (an apple is a fruit) In the real world, strict hierarchies are restrictive... we need composition! Mixins For composition: A has a B, or A uses a B Exclusively using mixins can be messy — both should be combined
  44. 44. Inheritance, Mixis and Design Each of them serves its purpose, our job is to use the appropriately None of these make any sense:class Person < DataWrapperendclass Banana include FruitPropertiesend Think before you type
  45. 45. Reflection
  46. 46. Reflection Ruby is very powerful when it comes to examining the aspects of a program within itself It can discover information about: What objects exist All class hierarchies Attributes and methods of all objects Information about methods“When you introspect, you think about your thoughts and feelings. This is interesting because youre using thought to analyze thought.” — Dave Thomas
  47. 47. Reflection and Objects You can transverse all living objects:ObjectSpace.each_object(Float) { |x| puts x }
  48. 48. Reflection and Objects You can look inside objects:[1,2,3].methods[0..4][1,2,3].respond_to?(:to_s)[1,2,3].kind_of?(Hash)
  49. 49. Reflection and Objects You can invoke any method by name using send :a = [1,2,3]a.send(a.private_methods.first.to_sym) # "initialize"a # now its empty!
  50. 50. Reflection and Objects Another way is to use the Method class:a = [1,2,3]constructor = a.method(:initialize)constructor.calla You get a Method object which you can store, pass around and call anytime!
  51. 51. Reflection and Classes Its also possible to look inside classes:String.ancestors # all superclasses and mixed-in modules
  52. 52. Reflection and Classes Its also possible to look inside classes:klass = Stringresult = klass.to_sbegin klass = klass.superclass result += " < " + klass.to_send while klass.superclassresult
  53. 53. Reflection and Classes Its also possible to look inside classes:Fixnum.constantsFixnum.class_variablesFixnum.singleton_methods(false)Fixnum.instance_methods(false) # private/protected/public prefix
  54. 54. Reflection and the Programs Execution Ruby lets you look at the interpreter while it executes your codeset_trace_func lambda { |event, file, line, id, binding, classname| printf "%8s %s:%s-2d %-15sn", event, file, line, classname, id}# all code is traced from now on And you can also get the current call stack by using calling caller on yourmethods
  55. 55. Reflection and the Programs Execution You can even get the current source file being executed with the __FILE__ specialvariable, leading to an interesting Quine :print A program that outputs itself!
  56. 56. Metaprogramming
  57. 57. Metaprogramming Ruby code can modify aspects of its own structure at runtime and it makes it alleasy Youve seen it before on this presentation: remember include and extend? Ruby iseffectively injecting their code into their receiver
  58. 58. Singleton Methods Ruby lets you define methods specific to a particular objectperson = "person" # String objectdef person.say_hi "Hi!"endperson.say_hi Magic? No. Ruby created an anonymous class (often called singleton class) basedon String and added the method say_hi to it
  59. 59. Singleton Class There are other ways of creating methods in an objects singleton classperson = "person"class << person def say_hi "Hi there!" endendperson.say_hi
  60. 60. Inherited Visibility The visibility of an inherited method can be changedclass SuperClass private def my_private_method "U cant touch this" endendclass SubClass < SuperClass public :my_private_methodendobject = SubClass.newobject.my_private_method # not so private anymore
  61. 61. Inherited Visibility Whats really happening is that Ruby is inserting a hidden proxy method in thesubclass that invokes the original method with superclass SubClass < SuperClass def my_private_method super end public :my_private_methodend super calls can access the parents method regardless of its visibility
  62. 62. Defining Methods Ruby allows you to define methods at runtime using define_methodclass BabyInfo ["cry", "eat", "poop"].each do |baby_action| define_method(baby_action) do "Of course, babies #{baby_action}" end endendbaby_info = BabyInfo.newbaby_info.cry Methods can also be blocked/removed by calling undef_method and remove_method,respectively
  63. 63. Class-level Macros Ruby has a few class-level macros that generate code behind the scenesclass Laptop attr_accessor :memory # injects a getter/setter for "memory"end If youve used Ruby on Rails, youve probably dealt with associationsclass Post < ActiveRecord::Base has_many :commentsend
  64. 64. Eval Similarly to other languages, eval evaluates the passed Ruby expression(s)course = "LPOO"eval "Hello + course + !"
  65. 65. Instance eval instance_eval allows you to evaluate Ruby expression(s) in the context of aninstancestring = "cool man cool"string.instance_eval "def shout; self.upcase; end"string.shout Remember: classes are instances of Class, so you can also use instance_eval withthem:Fixnum.instance_eval "def ten; 10; end"Fixnum.ten
  66. 66. Class eval As the name implies, class_eval can only be used with classes It evaluates the code as if you were in the context of the class definitionString.class_eval do def shout self.upcase endendstring = "cool man cool"string.shout Note: eval, instance_eval and class_eval can take blocks as arguments as shownabove
  67. 67. Eval evilnesseval is sloweval is dangerouseval doesnt generally make sense, given all other metaprogramming facilities
  68. 68. Callbacks Ruby provides hook methods , called by the interpreter when a specific eventoccurs Among all available hook methods —also known as callbacks —are: Method-related hooks: method_added, method_missing, method_removed, etc Class/Module-related hooks: const_missing, extended, included, inherited, etc Object marshaling and coercion hooks
  69. 69. Callbacks: method_missing Ruby allows you to act upon calls to undefined methods by using method missingclass BabyInfo ["cry", "eat", "poop"].each do |baby_action| define_method(baby_action) do "Of course, babies #{baby_action}" end end def method_missing(name, *args, &block) "Nope, babies dont #{name}" endendbaby_info =
  70. 70. Callbacks: inherited Ruby allows your classes to act when theyre subclassedclass SuperClass @children = [] # class variable def self.inherited(child) @children << child end def self.children @children endend
  71. 71. Callback: method calls Ruby allows you to intercept calls to specific methods:class Object alias_method :old_to_s, :to_s def to_s result = self.old_to_s "Your modified to_s returned this (should be "+result+")" endendobject = Object.newobject.to_s This isnt a direct hook: youre copying the original method and inserting a hookby yourself
  72. 72. Wrapping Up
  73. 73. Ruby Ruby is an incredibly powerful language Many successful projects/products use it at their core: Ruby on Rails, God,Redmine, etc You can add and remove code in a running process, redefine methods on the fly,change their scope You can even modify basic types like String, Float or even Class and Object After using it for a while, youll notice the lack of flexibility on static languageslike C++ or half-static languages like Java
  74. 74. Ruby This presentation, for instance, is running on a Sinatra application And most of the shown code was executed in real time No? Then check this out:class Lecture def initialize(name = "TBA") @name = name end def finish "Finished at #{(}!" endendlecture ="Ruby")lecture.finish
  75. 75. MoreBooks: Programming Ruby 1.9 by Dave Thomas Metaprogramming Ruby by Paolo PerrottaMailing lists: Ruby-Talk (subscribe through Rubys website) Ruby-pt (Google Groups)IRC: #ruby and #ruby-pt on Freenode
  76. 76. ?