SlideShare ist ein Scribd-Unternehmen logo
1 von 30
Downloaden Sie, um offline zu lesen
#7
       “Clos
             ures”
Ruby
Closures sind Codeblöcke, …


 die zugewiesen und rumgereicht werden können.

 die jederzeit und von jedem aufgerufen werden können.

 die Zugriff auf Variablen im ursprünglich definierenden Kontext haben.



 Alle antworten auf call()
7
Blöcke


@my_bag = Bag.new

%w(MacBook Headphones iPhone Camera).each do |item|
  @my_bag.add item
end


            @my_bag.each_item       ?
class Bag
  def each_item
    @items.each do |item|
      yield item
    end
  end
end

@my_bag.each_item { |item| puts item }
%w(MacBook Headphones iPhone Camera).each do |item|
     item_count ||= 0
     @my_bag.add item
     item_count += 1
   end

   puts "#{item_count} item(s) have been added to my bag."




NameError: undefined local variable or method ‘item_count’
Blöcke
Werden an Methoden übergeben

Fangen den definierenden Kontext ein



Erweitern den definierenden Kontext nicht

Können nicht

  herumgereicht oder

  jederzeit aufgerufen werden
class Bag
  def initialize(items)
    @items = items
  end

  def each_item(&block)
    @items.each(&block)
  end
end

bag = Bag.new %w(MacBook Headphones Keys)
bag.each_item { |item| puts item }
class Bag
  def initialize(items)
    @items = items
  end

  def define_iterator(&block)
    @iterator = block # Proc.new &block
  end

  def iterate!
    @items.each(&@iterator)
  end
end

bag = Bag.new(%w(MacBook Headphones Keys))
bag.define_iterator { |item| puts item }
bag.iterate!
“echte” Closures?


&block ohne & ist wie Proc.new(&block)

proc {}

lambda {}
Kontrollfluss
       &
Aritätsprüfung
Kontrollfluss


Proc.new ist abhängig von dem definierenden Kontext

lambda verhält sich wie eine Methode (“true closure”)

proc ist ein Alias auf lambda (Ruby 1.8)

proc ist ein Alias auf Proc.new (Ruby 1.9)
def call_closure(closure)
  puts "Calling a closure"
  result = closure.call
  puts "The result of the call was: #{result}"
end

call_closure(Proc.new { return "All hell breaks loose!" })




      LocalJumpError: unexpected return
def cc(closure)
    puts "Calling a closure"
    result = closure.call
    puts "The result of the call was: '#{result}'"
  end

  cc(lambda { return "Everypony calm down. All is good." })




Calling a closure
The result of the call was: ‘Everypony calm down. All is good.’
Aritätsprüfung


arity()-Methode

Instanzen von Proc.new prüfen die Artität nicht

Closures durch lambda prüfen die Arität (in Ruby 1.9)
Aritätsprüfung: Proc

proc_closure = Proc.new do |arg1, arg2|
  puts "arg1: #{arg1}; arg2: #{arg2}"
end


proc_closure.call(1,2,3,4) # arg1: 1; arg2: 2
proc_closure.call(1,2) # arg1: 1; arg2: 2
proc_closure.call(1) # arg1: 1; arg2: nil
Aritätsprüfung: Lambda

lambda_closure = lambda do |arg1, arg2|
  puts "arg1: #{arg1}; arg2: #{arg2}"
end


lambda_closure.call(1,2,3,4) # ArgumentError
lambda_closure.call(1,2) # arg1: 1; arg2: 2
lambda_closure.call(1) # ArgumentError
Fun facts

In Ruby 1.8

  lambda {||}.artiy != lambda {}.arity

  lambda {}.arity == -1

  lambda checkt nicht die Argumente, wenn Arität 1 ist WTF!?

In Ruby 1.9

  lambda {}.arity == lambda {||}.arity == 0
Beispiel: Lazy Collection
class BlogEntry
  class LazyLoadCollection
    include Enumerable

    def initialize(lazy_collection, after_load_callback = nil)
      @lazy_collection     = lazy_collection
      @after_load_callback = after_load_callback.present? ? after_load_callback : lambda { |args| return args }
      @collection          = @after_load_callback.call(@lazy_collection.call)
    end

    def each(&block)
      @collection.each(&block)
    end
  end

  class <<self
    def find_all(language)
      lazy_feed            = lambda { Nokogiri::XML(open(Rails.config.blog_feed_url)) }
      create_blog_entries = lambda do |feed|
        feed.xpath("//item").collect { |item| BlogEntry.new(xml_item) }
      end

      LazyLoadCollection.new lazy_feed, create_blog_entries
    end
  end

  def initialize(xml)
    self.attributes = (item.xpath("*/text()").inject({}) do |attributes, text|
      attributes[attribute_name] = text.content if text.parent.name.present?
      attributes
    end)
  end
end
block (implizit übergeben)

block (explizit übergeben)

block (explizit übergeben und zu Proc)

Proc.new

proc (Alias auf lambda / Proc.new)

lambda




6 Möglichkeiten
One More Thing …
method()
class Bag
  def each_item(closure)
    @items.each { |item| closure.call(item) }
  end
end

class Iterator
  def self.print_element(element)
    puts "Element: #{element}"
  end
end

my_bag = Bag.new(%w(MacBook Headphones iPad Gloves))

my_bag.each_item lambda { |item| puts "Element: #{item}" }

my_bag.each_item Iterator.method(:print_element)
class DBLayer

 decorate CacheDecorator
 def find(id)
   puts "Called :find with #{id}"
   puts "I am: #{self}"
 end

 def destroy; end
 def create; end

 decorate CacheDecorator
 def count
   puts "Called :count"
   return 1337
 end

end
class CacheDecorator < BaseDecorator

 def call(*args)
   puts "Before closure"
   result = @closure.call(*args)
   puts "After closure"

   return result
 end

end
Was müssen wir machen?

Erkennen welche Methode zu dekorieren ist

Methode extrahieren

Decorator mit extrahierter Methode inititalisieren

Proxy Methode definieren

Binding vor Ausführung der “alten” Methode umsetzen
module FunctionDecorators
  def self.apply_decorator(decorator, method_name, target)
    decorated_method = target.instance_method(method_name)

    target.send(:remove_method, method_name)

    target.__decorators[method_name] = decorator.new(decorated_method)

    params = decorated_method.parameters.collect(&:last).join(',')

    class_eval <<-RUBY
      def #{method_name}(#{params})
         self.class.__decorators[:#{method_name}].bind_to(self)
         self.class.__decorators[:#{method_name}].call(#{params})
      end
    RUBY
  end
end
class BaseDecorator
  def bind_to(receiver)
    @closure = @closure.bind(receiver)
  end
end
Thanks! Q & A?



                                  ?



                                                                                 “My Little Pony” © Hasbro Studios and DHX Media Vancouver
                        Dirk Breuer / @railsbros_dirk

                         Sebastian Cohnen / @tisba

Thanks to Paul Cantrell (http://innig.net/software/ruby/closures-in-ruby.html)

Weitere ähnliche Inhalte

Was ist angesagt?

An Introduction to Ruby
An Introduction to RubyAn Introduction to Ruby
An Introduction to RubyJonathan Weiss
 
Perl 5.20: Feature, Kultur, Module, Werkzeuge
Perl 5.20: Feature, Kultur, Module, WerkzeugePerl 5.20: Feature, Kultur, Module, Werkzeuge
Perl 5.20: Feature, Kultur, Module, Werkzeugelichtkind
 
Die freie Programmiersprache Python
Die freie Programmiersprache Python Die freie Programmiersprache Python
Die freie Programmiersprache Python Andreas Schreiber
 
Prototype 1.7
Prototype 1.7Prototype 1.7
Prototype 1.7msebel
 
Was geht mit Java 17?
Was geht mit Java 17?Was geht mit Java 17?
Was geht mit Java 17?gedoplan
 

Was ist angesagt? (7)

Ein Gopher im Netz
Ein Gopher im NetzEin Gopher im Netz
Ein Gopher im Netz
 
An Introduction to Ruby
An Introduction to RubyAn Introduction to Ruby
An Introduction to Ruby
 
Perl 5.20: Feature, Kultur, Module, Werkzeuge
Perl 5.20: Feature, Kultur, Module, WerkzeugePerl 5.20: Feature, Kultur, Module, Werkzeuge
Perl 5.20: Feature, Kultur, Module, Werkzeuge
 
Die freie Programmiersprache Python
Die freie Programmiersprache Python Die freie Programmiersprache Python
Die freie Programmiersprache Python
 
Prototype 1.7
Prototype 1.7Prototype 1.7
Prototype 1.7
 
Was geht mit Java 17?
Was geht mit Java 17?Was geht mit Java 17?
Was geht mit Java 17?
 
Php Schulung
Php SchulungPhp Schulung
Php Schulung
 

Andere mochten auch

W dorsey week4 assignment
W dorsey week4 assignmentW dorsey week4 assignment
W dorsey week4 assignmentBigWil
 
Metaprogramming in Ruby
Metaprogramming in RubyMetaprogramming in Ruby
Metaprogramming in RubyRoss Lawley
 
Blocks and loops.pptx
Blocks and loops.pptxBlocks and loops.pptx
Blocks and loops.pptxsandeep kumar
 
Blocks by Lachs Cox
Blocks by Lachs CoxBlocks by Lachs Cox
Blocks by Lachs Coxlachie
 
Slides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammersSlides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammersGiovanni924
 
Study: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsStudy: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsLinkedIn
 

Andere mochten auch (7)

W dorsey week4 assignment
W dorsey week4 assignmentW dorsey week4 assignment
W dorsey week4 assignment
 
Metaprogramming in Ruby
Metaprogramming in RubyMetaprogramming in Ruby
Metaprogramming in Ruby
 
Blocks and loops.pptx
Blocks and loops.pptxBlocks and loops.pptx
Blocks and loops.pptx
 
Blocks by Lachs Cox
Blocks by Lachs CoxBlocks by Lachs Cox
Blocks by Lachs Cox
 
Slides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammersSlides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammers
 
Playing With Ruby
Playing With RubyPlaying With Ruby
Playing With Ruby
 
Study: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving CarsStudy: The Future of VR, AR and Self-Driving Cars
Study: The Future of VR, AR and Self-Driving Cars
 

Ähnlich wie Ruby is Magic - Episode #7: Closures

Objektorientierte Programmierung mit extbase und fluid
Objektorientierte Programmierung mit extbase und fluidObjektorientierte Programmierung mit extbase und fluid
Objektorientierte Programmierung mit extbase und fluidOliver Klee
 
Creasoft - Windows powershell
Creasoft - Windows powershellCreasoft - Windows powershell
Creasoft - Windows powershellCreasoft AG
 
Skalierbare Anwendungen mit Google Go
Skalierbare Anwendungen mit Google GoSkalierbare Anwendungen mit Google Go
Skalierbare Anwendungen mit Google GoFrank Müller
 
Go - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare SystemeGo - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare SystemeFrank Müller
 
Java und Go im Vergleich
Java und Go im VergleichJava und Go im Vergleich
Java und Go im VergleichQAware GmbH
 
Battle of the Languages: Java und Python im Wettstreit beim Lösen von Program...
Battle of the Languages: Java und Python im Wettstreit beim Lösen von Program...Battle of the Languages: Java und Python im Wettstreit beim Lösen von Program...
Battle of the Languages: Java und Python im Wettstreit beim Lösen von Program...gedoplan
 
Perl - die Taschenkettensäge unter den Programmiersprachen - Vortrag 2003
Perl - die Taschenkettensäge unter den Programmiersprachen - Vortrag 2003Perl - die Taschenkettensäge unter den Programmiersprachen - Vortrag 2003
Perl - die Taschenkettensäge unter den Programmiersprachen - Vortrag 2003Brigitte Jellinek
 
Drupal 8: TWIG Template Engine
Drupal 8:  TWIG Template EngineDrupal 8:  TWIG Template Engine
Drupal 8: TWIG Template Enginedrubb
 
Praesentation TYPO3Camp Berlin Speed mit Extbase
Praesentation TYPO3Camp Berlin Speed mit ExtbasePraesentation TYPO3Camp Berlin Speed mit Extbase
Praesentation TYPO3Camp Berlin Speed mit ExtbaseStefan Frömken
 
Java Design Pattern
Java Design PatternJava Design Pattern
Java Design Patternmanuelberger
 
Python builds mit ant
Python builds mit antPython builds mit ant
Python builds mit antroskakori
 

Ähnlich wie Ruby is Magic - Episode #7: Closures (20)

Objektorientierte Programmierung mit extbase und fluid
Objektorientierte Programmierung mit extbase und fluidObjektorientierte Programmierung mit extbase und fluid
Objektorientierte Programmierung mit extbase und fluid
 
Creasoft - Windows powershell
Creasoft - Windows powershellCreasoft - Windows powershell
Creasoft - Windows powershell
 
Scala Workshop
Scala WorkshopScala Workshop
Scala Workshop
 
FLOW3-Workshop F3X12
FLOW3-Workshop F3X12FLOW3-Workshop F3X12
FLOW3-Workshop F3X12
 
Scala
ScalaScala
Scala
 
Skalierbare Anwendungen mit Google Go
Skalierbare Anwendungen mit Google GoSkalierbare Anwendungen mit Google Go
Skalierbare Anwendungen mit Google Go
 
Go - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare SystemeGo - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare Systeme
 
Scala und Lift
Scala und LiftScala und Lift
Scala und Lift
 
Java und Go im Vergleich
Java und Go im VergleichJava und Go im Vergleich
Java und Go im Vergleich
 
Battle of the Languages: Java und Python im Wettstreit beim Lösen von Program...
Battle of the Languages: Java und Python im Wettstreit beim Lösen von Program...Battle of the Languages: Java und Python im Wettstreit beim Lösen von Program...
Battle of the Languages: Java und Python im Wettstreit beim Lösen von Program...
 
Testing tools
Testing toolsTesting tools
Testing tools
 
Perl - die Taschenkettensäge unter den Programmiersprachen - Vortrag 2003
Perl - die Taschenkettensäge unter den Programmiersprachen - Vortrag 2003Perl - die Taschenkettensäge unter den Programmiersprachen - Vortrag 2003
Perl - die Taschenkettensäge unter den Programmiersprachen - Vortrag 2003
 
jQuery & CouchDB - Die zukünftige Webentwicklung?
jQuery & CouchDB - Die zukünftige Webentwicklung?jQuery & CouchDB - Die zukünftige Webentwicklung?
jQuery & CouchDB - Die zukünftige Webentwicklung?
 
T3ak12 extbase
T3ak12 extbaseT3ak12 extbase
T3ak12 extbase
 
Drupal 8: TWIG Template Engine
Drupal 8:  TWIG Template EngineDrupal 8:  TWIG Template Engine
Drupal 8: TWIG Template Engine
 
Ruby on Rails SS09 03
Ruby on Rails SS09 03Ruby on Rails SS09 03
Ruby on Rails SS09 03
 
Praesentation TYPO3Camp Berlin Speed mit Extbase
Praesentation TYPO3Camp Berlin Speed mit ExtbasePraesentation TYPO3Camp Berlin Speed mit Extbase
Praesentation TYPO3Camp Berlin Speed mit Extbase
 
Java Design Pattern
Java Design PatternJava Design Pattern
Java Design Pattern
 
Python builds mit ant
Python builds mit antPython builds mit ant
Python builds mit ant
 
Ruby on Rails SS09 08
Ruby on Rails SS09 08Ruby on Rails SS09 08
Ruby on Rails SS09 08
 

Ruby is Magic - Episode #7: Closures

  • 1. #7 “Clos ures” Ruby
  • 2. Closures sind Codeblöcke, … die zugewiesen und rumgereicht werden können. die jederzeit und von jedem aufgerufen werden können. die Zugriff auf Variablen im ursprünglich definierenden Kontext haben. Alle antworten auf call()
  • 3. 7
  • 4. Blöcke @my_bag = Bag.new %w(MacBook Headphones iPhone Camera).each do |item| @my_bag.add item end @my_bag.each_item ?
  • 5. class Bag def each_item @items.each do |item| yield item end end end @my_bag.each_item { |item| puts item }
  • 6. %w(MacBook Headphones iPhone Camera).each do |item| item_count ||= 0 @my_bag.add item item_count += 1 end puts "#{item_count} item(s) have been added to my bag." NameError: undefined local variable or method ‘item_count’
  • 7. Blöcke Werden an Methoden übergeben Fangen den definierenden Kontext ein Erweitern den definierenden Kontext nicht Können nicht herumgereicht oder jederzeit aufgerufen werden
  • 8. class Bag def initialize(items) @items = items end def each_item(&block) @items.each(&block) end end bag = Bag.new %w(MacBook Headphones Keys) bag.each_item { |item| puts item }
  • 9. class Bag def initialize(items) @items = items end def define_iterator(&block) @iterator = block # Proc.new &block end def iterate! @items.each(&@iterator) end end bag = Bag.new(%w(MacBook Headphones Keys)) bag.define_iterator { |item| puts item } bag.iterate!
  • 10. “echte” Closures? &block ohne & ist wie Proc.new(&block) proc {} lambda {}
  • 11. Kontrollfluss & Aritätsprüfung
  • 12. Kontrollfluss Proc.new ist abhängig von dem definierenden Kontext lambda verhält sich wie eine Methode (“true closure”) proc ist ein Alias auf lambda (Ruby 1.8) proc ist ein Alias auf Proc.new (Ruby 1.9)
  • 13. def call_closure(closure) puts "Calling a closure" result = closure.call puts "The result of the call was: #{result}" end call_closure(Proc.new { return "All hell breaks loose!" }) LocalJumpError: unexpected return
  • 14. def cc(closure) puts "Calling a closure" result = closure.call puts "The result of the call was: '#{result}'" end cc(lambda { return "Everypony calm down. All is good." }) Calling a closure The result of the call was: ‘Everypony calm down. All is good.’
  • 15. Aritätsprüfung arity()-Methode Instanzen von Proc.new prüfen die Artität nicht Closures durch lambda prüfen die Arität (in Ruby 1.9)
  • 16. Aritätsprüfung: Proc proc_closure = Proc.new do |arg1, arg2| puts "arg1: #{arg1}; arg2: #{arg2}" end proc_closure.call(1,2,3,4) # arg1: 1; arg2: 2 proc_closure.call(1,2) # arg1: 1; arg2: 2 proc_closure.call(1) # arg1: 1; arg2: nil
  • 17. Aritätsprüfung: Lambda lambda_closure = lambda do |arg1, arg2| puts "arg1: #{arg1}; arg2: #{arg2}" end lambda_closure.call(1,2,3,4) # ArgumentError lambda_closure.call(1,2) # arg1: 1; arg2: 2 lambda_closure.call(1) # ArgumentError
  • 18. Fun facts In Ruby 1.8 lambda {||}.artiy != lambda {}.arity lambda {}.arity == -1 lambda checkt nicht die Argumente, wenn Arität 1 ist WTF!? In Ruby 1.9 lambda {}.arity == lambda {||}.arity == 0
  • 20. class BlogEntry class LazyLoadCollection include Enumerable def initialize(lazy_collection, after_load_callback = nil) @lazy_collection = lazy_collection @after_load_callback = after_load_callback.present? ? after_load_callback : lambda { |args| return args } @collection = @after_load_callback.call(@lazy_collection.call) end def each(&block) @collection.each(&block) end end class <<self def find_all(language) lazy_feed = lambda { Nokogiri::XML(open(Rails.config.blog_feed_url)) } create_blog_entries = lambda do |feed| feed.xpath("//item").collect { |item| BlogEntry.new(xml_item) } end LazyLoadCollection.new lazy_feed, create_blog_entries end end def initialize(xml) self.attributes = (item.xpath("*/text()").inject({}) do |attributes, text| attributes[attribute_name] = text.content if text.parent.name.present? attributes end) end end
  • 21. block (implizit übergeben) block (explizit übergeben) block (explizit übergeben und zu Proc) Proc.new proc (Alias auf lambda / Proc.new) lambda 6 Möglichkeiten
  • 24. class Bag def each_item(closure) @items.each { |item| closure.call(item) } end end class Iterator def self.print_element(element) puts "Element: #{element}" end end my_bag = Bag.new(%w(MacBook Headphones iPad Gloves)) my_bag.each_item lambda { |item| puts "Element: #{item}" } my_bag.each_item Iterator.method(:print_element)
  • 25. class DBLayer decorate CacheDecorator def find(id) puts "Called :find with #{id}" puts "I am: #{self}" end def destroy; end def create; end decorate CacheDecorator def count puts "Called :count" return 1337 end end
  • 26. class CacheDecorator < BaseDecorator def call(*args) puts "Before closure" result = @closure.call(*args) puts "After closure" return result end end
  • 27. Was müssen wir machen? Erkennen welche Methode zu dekorieren ist Methode extrahieren Decorator mit extrahierter Methode inititalisieren Proxy Methode definieren Binding vor Ausführung der “alten” Methode umsetzen
  • 28. module FunctionDecorators def self.apply_decorator(decorator, method_name, target) decorated_method = target.instance_method(method_name) target.send(:remove_method, method_name) target.__decorators[method_name] = decorator.new(decorated_method) params = decorated_method.parameters.collect(&:last).join(',') class_eval <<-RUBY def #{method_name}(#{params}) self.class.__decorators[:#{method_name}].bind_to(self) self.class.__decorators[:#{method_name}].call(#{params}) end RUBY end end
  • 29. class BaseDecorator def bind_to(receiver) @closure = @closure.bind(receiver) end end
  • 30. Thanks! Q & A? ? “My Little Pony” © Hasbro Studios and DHX Media Vancouver Dirk Breuer / @railsbros_dirk Sebastian Cohnen / @tisba Thanks to Paul Cantrell (http://innig.net/software/ruby/closures-in-ruby.html)