Ruby — An introduction

  • 1,749 views
Uploaded 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".

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

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,749
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
62
Comments
0
Likes
2

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. RubyAn introduction to the Ruby programming language LPOO — MIEIC — FEUP May 2011
  • 2. @goncalossilva
  • 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. 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. Basics
  • 6. Methodsdef hello_world() return "Hello world!"endhello_world()
  • 7. Methodsdef hello_world # no need for () "Hello world!" # implicit returnendhello_world # no need for ()
  • 8. Classesclass HelloWorld def say "Hello world done right!" endendhello_world_object = HelloWorld.newhello_world_object.say
  • 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 = Lecture.new("Ruby", 45)lecture.description
  • 10. Its really object-oriented// Javamaximum = Math.max(1, 3)# Rubymaximum = [1, 3].max
  • 11. Its really object-oriented# Pythonpositive = abs(num)# Rubypositive = num.abs
  • 12. Its really object-oriented// Clength = strlen(name)# Rubylength = name.length
  • 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. 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. 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 = MyClass.new# explicit receiver, so self will be my_object inside my_methodmy_object.my_method
  • 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. 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. 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. 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. Blocks and Iterators
  • 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. 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) @stored_block.call(parameter) endendfoo = BlockAsObject.newfoo.store_block { |param| "The block was called with " + param }foo.use_block("delay")
  • 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 = powers_of_2_procpowers_of_2.call # 2powers_of_2.call # 4powers_of_2.call # 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. 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. Iterators In many languages, collections implement methods to generate external iteratorobjects// C#IEnumerator<int> i = list.GetEnumerator();while (i.MoveNext()) { // code}
  • 26. Iterators In many languages, collections implement methods to generate external iteratorobjects// JavaIterator i = list.iterator();while (i.hasNext()) { // code}
  • 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. 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. 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. 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. 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"enumerator.next # returns "my" and moves to the next elementenumerator.next
  • 32. Enumerators Most internal iterators are can be used as enumeratorsstring = "le fu"enumerator = string.each_charenumerator.next # returns "l" and moves to the next charenumerator.next # returns "e" and moves to the next char
  • 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. SharingFunctionality
  • 35. Inheritanceclass SuperClass def hello_world "Hello world!" endendclass SubClass < SuperClassendsuperclass = SuperClass.newsubclass = SubClass.new"Hello world from the superclass: #{superclass.hello_world}n" +"Hello world from the subclass : #{subclass.hello_world}"
  • 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. 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 = MyModule::MyClass.new Modules have another wonderful use: mixins
  • 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. Mixins include is used to mix modules into classes or other modulesmodule ToBeIncluded def foo "bar" endendclass MyClass include ToBeIncludedendobject = MyClass.newobject.foo
  • 40. Mixins extend is used to add instance methods to a given objectmodule ToBeIncluded def foo "bar" endendclass MyClassendobject = MyClass.newobject.extend ToBeIncludedobject.foo
  • 41. Mixins extend is also used to mix instance methods into a classmodule ToBeIncluded def foo "bar" endendclass MyClass extend ToBeIncludedendMyClass.foo
  • 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 = Over9000Number.new(42) def initialize(value) number.status @value = value # => "Current status: Over 9000!" endend Inherit from one class, include functionality from multiple modules — mixins !
  • 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. 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. Reflection
  • 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. Reflection and Objects You can transverse all living objects:ObjectSpace.each_object(Float) { |x| puts x }
  • 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. 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. 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. Reflection and Classes Its also possible to look inside classes:String.ancestors # all superclasses and mixed-in modules
  • 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. 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. 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. 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 File.read(__FILE__) A program that outputs itself!
  • 56. Metaprogramming
  • 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. 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. 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. 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. 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. 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. 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. Eval Similarly to other languages, eval evaluates the passed Ruby expression(s)course = "LPOO"eval "Hello + course + !"
  • 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. 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. Eval evilnesseval is sloweval is dangerouseval doesnt generally make sense, given all other metaprogramming facilities
  • 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. 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 = BabyInfo.newbaby_info.surf
  • 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. 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. Wrapping Up
  • 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. 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 #{(Time.now.utc+3600).strftime(%H:%M:%S)}!" endendlecture = Lecture.new("Ruby")lecture.finish
  • 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. ?