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

Ruby is Magic: RedFrog Edition

Ruby is Magic: RedFrog Edition

This time @tisba and I got the chance to speak at the FrOSCon 2013. We compiled a special episode with some old things and some new magical moments.

Copyright Notice: My Little Pony - Friendship is Magic is Property of Hasbro and The Hub.

Avatar for Dirk Breuer

Dirk Breuer

August 25, 2013
Tweet

More Decks by Dirk Breuer

Other Decks in Programming

Transcript

  1. h t ://w w. i k .c m/p o o

    /j h _l m/1 1 9 8 1 / M t , w s m c t i e u e P o r m i r p a h a s? M t , E n e n o R b 8
  2. h t ://i c.c n e s t o s

    e w r .o g/s o s/d t i 1 3 .h m ★ “I h l s h m n t o g t ." ★ “I h l s o t i k b t e ." ★ “I m k s o a b t e p o r m e ."
  3. ★ “R b m k s p o r m

    e s h p y.” ★ “I w n e o m n m z y f u t a i n d r n p o r m i g.” ★ “D n't u d r s i a e h h m n f c o .” h t ://w w.a t m .c m/i t /r b .h m
  4. ★ E t o f n für P o u

    t v tät n S aß ★ P i z p e o I t r c i n D s g ★ “P i c p e f l a t a t n s m n " – V r i r n e f h e e E t i k e m n m e e W k p d a, h t ://e .w k p d a.o g/w k /R b _(p o r m i g_l n u g )#P i o o h
  5. I 's a k n o M g c -

    B i p e e -
  6. describe Account do it "has a balance of zero when

    first created" do expect(Account.new.balance).to eq(0) end end
  7. B u a t n für D L ★ C

    d B o k & C o u e ★ B öc e n v r c i d n n K n e t n a s üh e ★ F n t o a i ät n e S r c e e w i e n ★ M t p o r m i r n : d n m s h C d g n r e u g, method_missing C l b c s
  8. Application.configure do client_timeout 2.minutes buffer_size 500.kilobytes end class Application def

    self.configure(&block) new.instance_eval(&block) end def method_missing(method, *args) @config[method] = args.first end end 8
  9. class CacheDecorator < BaseDecorator def call(*args) # … before method

    result = @closure.call(*args) # … after method return result end end
  10. ???

  11. ★ Z d k r e e d M t

    o e n e ★ M t o e e t a i r n ★ D c r t r i e M t o e i i i l s e e ★ P o y M t o e d n e e
  12. # Detect the method for decoration def method_added(name) if decorator_class

    = @decorate_next_with @decorate_next_with = nil DecoratorHelper.apply_decorator(decorator_class, name, self) end end
  13. # Extract the original method decorated_method = target.instance_method(method_name) target.send(:remove_method, method_name)

    # Initialize decorator with original method target.decorators[method_name] = { decorator: decorator.new, method: decorated_method }
  14. # Define the proxy method new_method = <<-RUBY def #{method_name}(*params,

    &block) @_#{method_name}_decorator.call(*params, &block) end RUBY # Add the proxy method to the original class target.class_eval new_method
  15. Events.subscribe :create_user # [EVENT] The service 'create_user' was called with

    {:name=>"Rainbow Dash", :email=>"[email protected]"} # [CreateUserService] Creating the user 'Rainbow Dash' CreateUserService.execute(name: "Rainbow Dash", email: "[email protected]")
  16. ???

  17. ★ A f r e u g: K i e

    S p r-K a s , e n M d l i k u i r n ★ D n m s h S r i e-K a s n n e ★ execute-M t o e e w i e n
  18. subclass.instance_eval do def self.singleton_method_added(method_name) return nil unless method_name == :execute

    class << self # ... end end end CreateUserService.execute i t e n K a s n e h d 8 8 8 8 ? ? ? ? ? ? ?
  19. S n l t n C a s ★ J

    d s O j k a s i e e g n e a K a s , d r u h S n l t n C a s ★ I s a z-V r a l n (Z s a d) e t n O j k e /I s a z n ★ M t o e (V r a t n) l b n n K a s n/M d l n ★ D h r u s s für j d s O j k i e e g n K a s g b n!
  20. C a s s, S n l t n C

    a s s, O j c s....?! C a s C e t U e S r i e #<C a s:#C e t U e S r i e> s p r l s c a s s n l t n c a s
  21. M t o e n e i R b C

    e t U e S r i e O j c #<C e t U e S r i e> #<C a s:#<C e t U e S r i e:0x2A>> #<C a s:C e t U e S r i e>
  22. class << self alias_method :execute_without_event_trigger, :execute undef_method :execute def execute_with_event_trigger(*args)

    Events.publish … execute_without_event_trigger(*args) end def method_missing(meth, *args, &blk) if meth.to_sym == :execute execute_with_event_trigger(*args) else super end end end A t M t o e e t e n n… 8 …u d n u "h n u üg n" 8
  23. F n F c undef_method(symbol) → self P e e

    t h c r e t c a s r m r s o d n o c l s o t e n m d m t o . C n r s h s i h remove_method, w i h d l t s h m t o r m h p r i u a c a s; R b i l s i l s a c s p r l s e n m x d-i m d l s o a p s i l r c i e .
  24. ♌ gambit:rails $ git grep undef_method actionpack/lib/abstract_controller/base.rb: undef_method :not_implemented actionpack/lib/action_controller/metal/responder.rb:

    undef_method(:to_json) if method_defined?(:to_json) actionpack/lib/action_controller/metal/responder.rb: undef_method(:to_yaml) if method_defined?(:to_yaml) actionpack/test/lib/controller/fake_models.rb: undef_method :to_json activemodel/lib/active_model/attribute_methods.rb: instance_methods.each { |m| undef_method(m) } activemodel/test/cases/observing_test.rb: undef_method :observed_classes activerecord/lib/active_record/associations/collection_proxy.rb: instance_methods.each { |m| undef_method m unless m.to_s =~ … activerecord/lib/active_record/attribute_methods/read.rb: instance_methods.each { |m| undef_method(m) } activerecord/lib/active_record/attribute_methods/read.rb: undef_method :__temp__ activerecord/lib/active_record/attribute_methods/read.rb: undef_method :__temp__ activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb: undef_method :select_rows activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb: undef_method :execute activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb: undef_method :select activerecord/test/cases/attribute_methods_test.rb: Object.send(:undef_method, :title) # remove test method from object activerecord/test/cases/attribute_methods_test.rb: topic.method(:id).owner.send(:undef_method, :id) activerecord/test/cases/finder_test.rb: undef_method(:find_or_create_by_name) if … activesupport/lib/active_support/basic_object.rb: undef_method :== activesupport/lib/active_support/basic_object.rb: undef_method :equal? activesupport/lib/active_support/basic_object.rb: undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$)/ activesupport/lib/active_support/callbacks.rb: undef_method(name) if method_defined?(name) activesupport/lib/active_support/core_ext/rexml.rb: undef_method :unnormalized activesupport/lib/active_support/deprecation/proxy_wrappers.rb: instance_methods.each { |m| undef_method m unless m =~ /^__|^object_id$/ } activesupport/lib/active_support/option_merger.rb: undef_method(method) if method !~ /^(__|instance_eval|class|object_id)/ activesupport/test/core_ext/duration_test.rb: class << k; undef_method :== end Rails…
  25. • inherited • included • extended • append_features • const_missing

    • method_missing • method_added • method_removed • method_undefined • singleton_method_added • singleton_method_removed • singleton_method_undefined • ObjectSpace.define_finalizer(obj, aProc=proc()) • at_exit { block }
  26. sequence = Enumerator.new do |yielder| number = 0 loop do

    number += 1 puts "-> #{Fiber.current.object_id}" yielder.yield number end end E d o s h e f ?! 8
  27. sequence = Fiber.new do number = 0 loop do number

    += 1 Fiber.yield number end end def sequence.next resume end
  28. “R e t o i t e n b e

    t w y t l a n w s o .” – ޸෉ࢠ
  29. ★ R e t o b d u e u

    L u z i I f r a i n n … ★ üb r d n e t K n t n e , ★ O j k e u d ★ i r E g n c a t n a f a e R e t o
  30. def display_user_info(user_name) user = PonyStore.find :users, name: user_name puts "----

    USER ----" puts "Name: #{user.name}" puts "Age: #{user.age}" puts end user_names = ["Pinkie Pie", "Applejack"] user_names.each do |user_name| display_user_info user_name end
  31. ???

  32. class PonyStore def self.find(collection, query) record = storage[collection].find_by query return

    record unless record.nil? return NullObject.new(collection.class) end end S a t nil g b n w r e n O j k z rüc , d s s c "s n v l " v r äl 8
  33. class NullObject def initialize(original_class) original_class.instance_methods(false).each do |method_name| self.class.send(:define_method, method_name) {

    |*args| nil } end end end class User attr_accessor :name, :email, :address, :date_of_birth def age # non-trivial getter method end end
  34. ★ E d o e Mög i h e t

    n ★ Mäc t g , e n e a t W r z u e ★ E l u e e e a t Lös n e ★ N c t i m r s l t a a l s m c e ;-) d D n e M t !
  35. ★ K p e n e A s üh u

    g k n e t ★ E h l e Z g i u V r a l n, M t o e , self ★ W r e e z u t i Kernel#binding
  36. class Pony def say_hello(a_binding = nil) eval('puts "Hello, my name

    is #{@name}"', a_binding || binding) end end @name = "Rainbow Dash" somepony.say_hello(binding) # Hello, my name is Rainbow Dash somepony = Pony.new somepony.say_hello # Hello, my name is.
  37. class View def friend "Pinkie Pie" end def get_binding binding

    end end template = ERB.new <<-ERB <% @foo = 'bar' %> Welcome to Ruby is Magic! Let me introduce you to my good friend <%= friend %>. ERB puts template.result # (erb):3:in `<main>': undefined local variable or method `friend' view = View.new puts template.result(view.get_binding) # Let me introduce you to my good friend Pinkie Pie. puts view.instance_variable_get("@foo") # bar
  38. T a k ! D r B e e /

    @r i s r s_d r S b s i n C h e / @t s a h t ://g e s a m i c .d QaA “My Little Pony” © Hasbro Studios and DHX Media Vancouver