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. Intro to Object Oriented Programming* *in Ruby Burlington Ruby -

    September 2012 - Peter Brown
  2. 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
  3. 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
  4. What can be improved? Procedural programming alone can be: difficult

    to relate to real world objects tough to read and modify hard to test
  5. 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
  6. What is Object Oriented Programming? Design Refactoring Testing

  7. Object Oriented Design Modeling Domain Objects Messages and Interfaces

  8. What are Objects? Instance of a class Properties / State

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

    Method Array Hash File Regexp Exception Boolean
  10. 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
  11. Interface (API) Public methods exposed to consumers Consumers = developers

    or code Hide implementation (Encapsulation)
  12. 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 # =>
  13. Interfaces: Good vs Bad Predictable Familiar Consistent Dependable Hide implementation

    Unpredictable Unfamiliar Inconsistent Subject to change Expose implementation
  14. Interfaces: A Comparison

  15. Interfaces: A Comparison jack = Person.new('Jack', 35, 'brown') jill =

    Person.new('Jill', 31, 'red')
  16. 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')
  17. Predictable Interfaces jack.name # => ‘Jack’ jack.hair # => ‘brown’

    jack.male? # => true jack.siblings.size # => 2 jack.reset! # => Dangerous!
  18. Designing Objects Classical Inheritance Sharing via Modules Composition

  19. 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
  20. Classical Inheritance class Alarm def check notify if active? end

    def notify puts "#{self.class} is active!" end def active? raise NotImplementedError end end
  21. 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!
  22. Classical Inheritance class Person < Object end

  23. 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
  24. 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
  25. 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
  26. Composition 20.meters.to_feet # => 65.6168

  27. Composition 20.meters.to_feet # => 65.6168 class Meter def initialize(value) @value

    = value end def to_feet @value * 3.28084 end end
  28. 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
  29. 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
  30. Composition house = Building.new(height: 6.meters) house.height.to_feet # => 19.68504 skyscraper

    = Building.new(height: 500.feet) skyscraper.height.to_feet # => 500
  31. 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
  32. Unit Testing Interfaces & BDD go hand in hand Makes

    refactoring less painful Testing Public vs Private methods
  33. 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
  34. Refactoring Improving internal design of existing code without changing external

    behavior
  35. 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
  36. 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
  37. ClassyEnum Gem Combines classes, enums and ActiveRecord Composition and Polymorphism

    https://github.com/beerlington/classy_enum
  38. Learning More http://rubyrogues.com/ object-oriented- programming-in-rails-with- jim-weirich/ http://www.confreaks.com/ videos/763- rubymidwest2011-confident- code

  39. Thanks! @beerlington pete@lette.us