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.

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