#7       “Clos             ures”Ruby
Closures sind Codeblöcke, … die zugewiesen und rumgereicht werden können. die jederzeit und von jedem aufgerufen werden kö...
7
Blöcke@my_bag = Bag.new%w(MacBook Headphones iPhone Camera).each do |item|  @my_bag.add itemend            @my_bag.each_it...
class Bag  def each_item    @items.each do |item|      yield item    end  endend@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   ...
BlöckeWerden an Methoden übergebenFangen den definierenden Kontext einErweitern den definierenden Kontext nichtKönnen nicht ...
class Bag  def initialize(items)    @items = items  end  def each_item(&block)    @items.each(&block)  endendbag = Bag.new...
class Bag  def initialize(items)    @items = items  end  def define_iterator(&block)    @iterator = block # Proc.new &bloc...
“echte” Closures?&block ohne & ist wie Proc.new(&block)proc {}lambda {}
Kontrollfluss       &Aritätsprüfung
KontrollflussProc.new ist abhängig von dem definierenden Kontextlambda verhält sich wie eine Methode (“true closure”)proc i...
def call_closure(closure)  puts "Calling a closure"  result = closure.call  puts "The result of the call was: #{result}"en...
def cc(closure)    puts "Calling a closure"    result = closure.call    puts "The result of the call was: #{result}"  end ...
Aritätsprüfungarity()-MethodeInstanzen von Proc.new prüfen die Artität nichtClosures durch lambda prüfen die Arität (in Ru...
Aritätsprüfung: Procproc_closure = Proc.new do |arg1, arg2|  puts "arg1: #{arg1}; arg2: #{arg2}"endproc_closure.call(1,2,3...
Aritätsprüfung: Lambdalambda_closure = lambda do |arg1, arg2|  puts "arg1: #{arg1}; arg2: #{arg2}"endlambda_closure.call(1...
Fun factsIn Ruby 1.8  lambda {||}.artiy != lambda {}.arity  lambda {}.arity == -1  lambda checkt nicht die Argumente, wenn...
Beispiel: Lazy Collection
class BlogEntry  class LazyLoadCollection    include Enumerable    def initialize(lazy_collection, after_load_callback = n...
block (implizit übergeben)block (explizit übergeben)block (explizit übergeben und zu Proc)Proc.newproc (Alias auf lambda /...
One More Thing …
method()
class Bag  def each_item(closure)    @items.each { |item| closure.call(item) }  endendclass Iterator  def self.print_eleme...
class DBLayer decorate CacheDecorator def find(id)   puts "Called :find with #{id}"   puts "I am: #{self}" end def destroy...
class CacheDecorator < BaseDecorator def call(*args)   puts "Before closure"   result = @closure.call(*args)   puts "After...
Was müssen wir machen?Erkennen welche Methode zu dekorieren istMethode extrahierenDecorator mit extrahierter Methode initi...
module FunctionDecorators  def self.apply_decorator(decorator, method_name, target)    decorated_method = target.instance_...
class BaseDecorator  def bind_to(receiver)    @closure = @closure.bind(receiver)  endend
Thanks! Q & A?                                  ?                                                                         ...
Upcoming SlideShare
Loading in …5
×

Ruby is Magic - Episode #7: Closures

1,370
-1

Published on

In dieser Ausgabe von 'Ruby is Magic' stellen wir euch Closures in Ruby einmal etwas genauer vor.

Published in: Technology, Business
1 Comment
0 Likes
Statistics
Notes
  • Be the first to like this

No Downloads
Views
Total Views
1,370
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
3
Comments
1
Likes
0
Embeds 0
No embeds

No notes for slide

Ruby is Magic - Episode #7: Closures

  1. 1. #7 “Clos ures”Ruby
  2. 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. 3. 7
  4. 4. Blöcke@my_bag = Bag.new%w(MacBook Headphones iPhone Camera).each do |item| @my_bag.add itemend @my_bag.each_item ?
  5. 5. class Bag def each_item @items.each do |item| yield item end endend@my_bag.each_item { |item| puts item }
  6. 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. 7. BlöckeWerden an Methoden übergebenFangen den definierenden Kontext einErweitern den definierenden Kontext nichtKönnen nicht herumgereicht oder jederzeit aufgerufen werden
  8. 8. class Bag def initialize(items) @items = items end def each_item(&block) @items.each(&block) endendbag = Bag.new %w(MacBook Headphones Keys)bag.each_item { |item| puts item }
  9. 9. class Bag def initialize(items) @items = items end def define_iterator(&block) @iterator = block # Proc.new &block end def iterate! @items.each(&@iterator) endendbag = Bag.new(%w(MacBook Headphones Keys))bag.define_iterator { |item| puts item }bag.iterate!
  10. 10. “echte” Closures?&block ohne & ist wie Proc.new(&block)proc {}lambda {}
  11. 11. Kontrollfluss &Aritätsprüfung
  12. 12. KontrollflussProc.new ist abhängig von dem definierenden Kontextlambda 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. 13. def call_closure(closure) puts "Calling a closure" result = closure.call puts "The result of the call was: #{result}"endcall_closure(Proc.new { return "All hell breaks loose!" }) LocalJumpError: unexpected return
  14. 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 closureThe result of the call was: ‘Everypony calm down. All is good.’
  15. 15. Aritätsprüfungarity()-MethodeInstanzen von Proc.new prüfen die Artität nichtClosures durch lambda prüfen die Arität (in Ruby 1.9)
  16. 16. Aritätsprüfung: Procproc_closure = Proc.new do |arg1, arg2| puts "arg1: #{arg1}; arg2: #{arg2}"endproc_closure.call(1,2,3,4) # arg1: 1; arg2: 2proc_closure.call(1,2) # arg1: 1; arg2: 2proc_closure.call(1) # arg1: 1; arg2: nil
  17. 17. Aritätsprüfung: Lambdalambda_closure = lambda do |arg1, arg2| puts "arg1: #{arg1}; arg2: #{arg2}"endlambda_closure.call(1,2,3,4) # ArgumentErrorlambda_closure.call(1,2) # arg1: 1; arg2: 2lambda_closure.call(1) # ArgumentError
  18. 18. Fun factsIn 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
  19. 19. Beispiel: Lazy Collection
  20. 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) endend
  21. 21. block (implizit übergeben)block (explizit übergeben)block (explizit übergeben und zu Proc)Proc.newproc (Alias auf lambda / Proc.new)lambda6 Möglichkeiten
  22. 22. One More Thing …
  23. 23. method()
  24. 24. class Bag def each_item(closure) @items.each { |item| closure.call(item) } endendclass Iterator def self.print_element(element) puts "Element: #{element}" endendmy_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. 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 endend
  26. 26. class CacheDecorator < BaseDecorator def call(*args) puts "Before closure" result = @closure.call(*args) puts "After closure" return result endend
  27. 27. Was müssen wir machen?Erkennen welche Methode zu dekorieren istMethode extrahierenDecorator mit extrahierter Methode inititalisierenProxy Methode definierenBinding vor Ausführung der “alten” Methode umsetzen
  28. 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 endend
  29. 29. class BaseDecorator def bind_to(receiver) @closure = @closure.bind(receiver) endend
  30. 30. Thanks! Q & A? ? “My Little Pony” © Hasbro Studios and DHX Media Vancouver Dirk Breuer / @railsbros_dirk Sebastian Cohnen / @tisbaThanks to Paul Cantrell (http://innig.net/software/ruby/closures-in-ruby.html)
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×