• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Ruby is Magic - Episode #7: Closures
 

Ruby is Magic - Episode #7: Closures

on

  • 1,450 views

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

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

Statistics

Views

Total Views
1,450
Views on SlideShare
1,101
Embed Views
349

Actions

Likes
0
Downloads
2
Comments
1

6 Embeds 349

http://rubyismagic.de 200
http://localhost 125
http://feeds.feedburner.com 12
http://gambit.local 9
http://www.hanrss.com 2
http://translate.googleusercontent.com 1

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

11 of 1 previous next

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • Kannste auch #1 - #6 mal uppen? :) thx.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Ruby is Magic - Episode #7: Closures Ruby is Magic - Episode #7: Closures Presentation Transcript

    • #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 itemend @my_bag.each_item ?
    • 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 puts "#{item_count} item(s) have been added to my bag."NameError: undefined local variable or method ‘item_count’
    • BlöckeWerden an Methoden übergebenFangen den definierenden Kontext einErweitern den definierenden Kontext nichtKönnen nicht herumgereicht oder jederzeit aufgerufen werden
    • 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 }
    • 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!
    • “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 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}"endcall_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 closureThe result of the call was: ‘Everypony calm down. All is good.’
    • Aritätsprüfungarity()-MethodeInstanzen von Proc.new prüfen die Artität nichtClosures durch lambda prüfen die Arität (in Ruby 1.9)
    • 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
    • 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
    • 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
    • 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) endend
    • block (implizit übergeben)block (explizit übergeben)block (explizit übergeben und zu Proc)Proc.newproc (Alias auf lambda / Proc.new)lambda6 Möglichkeiten
    • One More Thing …
    • method()
    • 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)
    • 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
    • class CacheDecorator < BaseDecorator def call(*args) puts "Before closure" result = @closure.call(*args) puts "After closure" return result endend
    • 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
    • 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
    • class BaseDecorator def bind_to(receiver) @closure = @closure.bind(receiver) endend
    • 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)