Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Intro to Object Oriented Programming in Ruby

Peter Brown
September 20, 2012

Intro to Object Oriented Programming in Ruby

An introduction to Object Oriented Programming in Ruby, presented by Peter Brown at the Burlington Ruby Group

Peter Brown

September 20, 2012
Tweet

More Decks by Peter Brown

Other Decks in Programming

Transcript

  1. Introduction OOP Overview Designing Objects Testing Refactoring OOP Tips class

    Presentation def language 'Ruby' end def topic 'OOP' end def totally_awesome? true end end
  2. Procedural Programming Model a sequence of events Data and functions

    (procedures) are separate Perfect for procedural languages class DataProcessor def process data = get_data_from_file new_data = convert_to_format(data) write_data_to_file(new_data) end def get_data_from_file end def convert_to_format(data) end def write_data_to_file(new_data) end end processor = DataProcessor.new processor.process
  3. What can be improved? Procedural programming alone can be: difficult

    to relate to real world objects tough to read and modify hard to test
  4. Objects to the rescue! OOP is a shift in thinking

    Dividing code into small classes with a single responsibility: React to change Reuse code Self documenting
  5. What are Objects? Instance of a class Properties / State

    Instance variables (@var) Methods: Command vs Query
  6. Everything in Ruby is an Object String Integer Float Symbol

    Method Array Hash File Regexp Exception Boolean
  7. Object Example pete = Person.new pete.age = 30 pete.age #

    => 30 class Person def age=(value) @age = value end def age @age end end Class vs Object
  8. Public Methods [:!, :!=, :! ~, :<=>, :==, :===, :=~,

    :__id__, :__send__, :class, :clone, :define_singleton_method, :display, :dup, :enum_for, :eql?, :equal?, :extend, :freeze, :frozen?, :hash, :initialize_clone, :initialize_dup, :inspect, :instance_eval, :instance_exec, :instance_of?, :instance_variable_defined?, :instance_variable_get, :instance_variable_set, :instance_variables, :is_a?, :kind_of?, :method, :methods, :nil?, :object_id, :private_methods, :protected_methods, :public_method, :public_methods, :public_send, :respond_to?, :respond_to_missing?, :send, :singleton_class, :singleton_methods, :taint, :tainted?, :tap, :to_enum, :to_s, :trust, :untaint, :untrust, :untrusted?] class Person; end Person.new.methods # =>
  9. Interfaces: Good vs Bad Predictable Familiar Consistent Dependable Hide implementation

    Unpredictable Unfamiliar Inconsistent Subject to change Expose implementation
  10. Interfaces: A Comparison jack = Person.new('Jack', 35, 'brown') jill =

    Person.new('Jill', 31, 'red') jack = Person.new(name: 'Jack', age: 35, hair: 'brown') jill = Person.new(age: 31, name: 'Jill', hair: 'red') bill = Person.new(age: 40, name: 'Bill')
  11. Predictable Interfaces jack.name # => ‘Jack’ jack.hair # => ‘brown’

    jack.male? # => true jack.siblings.size # => 2 jack.reset! # => Dangerous!
  12. Classical Inheritance Object A is an Object B All objects

    have a superclass Methods automatically delegated to superclass class Beverage end class Beer < Beverage end
  13. Classical Inheritance class Alarm def check notify if active? end

    def notify puts "#{self.class} is active!" end def active? raise NotImplementedError end end
  14. Classical Inheritance class FireAlarm < Alarm def active? fire_detected? end

    private def fire_detected? true end end alarm = FireAlarm.new alarm.check # => FireAlarm is active!
  15. Sharing via Modules Object A behaves like Object B Can

    be reused by other classes Classes can include multiple modules module Drinkable def drink puts "mmmm" end end class Beer include Drinkable end
  16. Sharing via Modules class Alarm include Notifiable def check notify

    if active? end def active? raise NotImplementedError end end module Notifiable def notify puts "#{self.class} is active!" end end
  17. Composition Object A has an Object B Create objects that

    are composed of other objects class Roof end class House def roof Roof.new end end
  18. Composition 20.meters.to_feet # => 65.6168 class Meter def initialize(value) @value

    = value end def to_feet @value * 3.28084 end end class Numeric def meters Meter.new(self) end end
  19. Composition class Numeric def feet Foot.new(self) end def meters Meter.new(self)

    end end 20.feet.to_feet # => 20 20.meters.to_feet # => 65.6168
  20. Composition house = Building.new(height: 6.meters) house.height.to_feet # => 19.68504 skyscraper

    = Building.new(height: 500.feet) skyscraper.height.to_feet # => 500
  21. Composition class Building attr_reader :height def initialize(options={}) @height = options[:height]

    end end house = Building.new(height: 6.meters) house.height.to_feet # => 19.68504 skyscraper = Building.new(height: 500.feet) skyscraper.height.to_feet # => 500
  22. Unit Testing Interfaces & BDD go hand in hand Makes

    refactoring less painful Testing Public vs Private methods
  23. Unit Testing: RSpec describe Person do subject { Person.new(name: 'Jack')

    } context '#siblings' do it { should have(:no).siblings } specify 'adding siblings behaves like an array' do subject.siblings << Person.new(name: 'Jill') subject.siblings << Person.new(name: 'Bill') subject.should have(2).siblings end end end
  24. Code Smells Abusing Inheritance Defensive coding Class names that end

    in ‘er’ and `or` Complex tests Arrays representing objects Class uses methods from another class excessively Too many parameters Large classes Long methods
  25. OOP Tips Avoid unexpected state change Think in terms of

    what an object does, not what it is (BDD) Don’t have to start with objects, add them as needed Code to an interface Be consistent Favor composition over inheritance Avoid tight coupling