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

Rails is A Follower

Rails is A Follower

what we can learn from dRuby’s metaprogramming magic.
@ dRubyConf2012

seki at druby.org

November 02, 2012
Tweet

More Decks by seki at druby.org

Other Decks in Programming

Transcript

  1. Rails is A Follower what we can learn from dRuby’s

    metaprogramming magic Masatoshi SEKI Makoto Inoue
  2. Masatoshi Seki Ruby committer Author of dRuby/Rinda Author of ERB

    Pokemon Master The ERB Book Embed ruby script in any document using ERB
  3. Seki san @ RubyKaigi (06 - 11) 2006 dRuby as

    a session storage 2007 Rinda: Distributed TupleSpace 2008 RIP ERB 2009 dRuby and BigTable 2010 dRuby and Object Database 2011 Drip: A stream based database
  4. History of dRuby 1999-3 ERB 1999-9 DRb 2003 committer 2010

    pokemon-master 2000 Rinda 1998 started ruby 2006 - 2011 Ruby Kaigi
  5. Thank you to Our Sponsors @PUPRL @ayumin @arika @mame @

    vestige_ @track8 @ nagachika "ruby trunk changes" @ktou Powered by Rabbit @tsuboi @ayako119 @hisashim
  6. What is dRuby? Distributed Object System Can invoke methods in

    different processes Can send objects between processes Pure Ruby Ruby standard library
  7. Old-fashioned programmer (BD8) Used to program in old Unix style

    IPC (Inter-Process Communication) fork/pipe, SystemV IPC
  8. Embedding HTTP into processes Embedding web server into small apps

    are fun Application communication via HTTP
  9. Not so cool because... Converting Ruby way into Web way

    HTTP restricts how to exchange objects Server - Client relationship Functional APIʢRPCʣ Cool URL No REST at that time
  10. I just want Ruby to talk each other Converting Ruby

    world to Web world is restricting Too much abstraction?
  11. Back to Ruby Distributed objects acting like Ruby RPC ->

    RMI Extending Ruby’s method invocation to socket programming
  12. module DRbProtocol ... def dump(obj, soc) begin str = Marshal::dump(obj)

    rescue ro = DRbObject.new(obj) str = Marshal::dump(ro) end soc.write(str) if soc str end ... end
  13. Marshal File, Thread, Proc raise exceptions If you can not

    serialize, then serialize its proxy Send Object references
  14. module DRbProtocol ... def dump(obj, soc) begin str = Marshal::dump(obj)

    rescue ro = DRbObject.new(obj) str = Marshal::dump(ro) end soc.write(str) if soc str end ... end
  15. ObjectSpace._id2ref & send Find a object using object id The

    server finds the object and dispatches the method to it
  16. class DRbServer ... ! ro, msg, argv = recv_request(s) !

    if ro and ro.ref ! obj = ObjectSpace._id2ref(ro.ref) ! else ! obj = DRb.front ! end ! result = obj.__send__(msg.intern, *argv) ! succ = true ... end
  17. class DRbServer ... ! ro, msg, argv = recv_request(s) !

    if ro and ro.ref ! obj = ObjectSpace._id2ref(ro.ref) ! else ! obj = DRb.front ! end ! result = obj.__send__(msg.intern, *argv) ! succ = true ... end
  18. class DRbMessage ... def load(soc) ... begin ... Marshal.load(str) rescue

    NameError, ArgumentError DRbUnknown.new($!, str) ensure ... end ... end end
  19. class DRbUnknown def initialize(err, buf) case err.to_s when /uninitialized constant

    (\S+)/ @name = $1 when /undefined class\/module (\S+)/ @name = $1 else @name = nil end @buf = buf end
  20. class DRbUnknown ... def self._load(s) begin Marshal::load(s) rescue NameError, ArgumentError

    DRbUnknown.new($!, s) end end def reload self.class._load(@buf) end end
  21. Thread.start(@soc.accept) do |s| begin ro, msg, arg = recv_request(s) ...

    send_response(s, succ, result) ensure s.close end end
  22. ro, msg, argv, block = recv_request(s) obj = ro_to_obj(ro) if

    block result = obj.__send__(msg.intern, *argv) do |*x| block.call(*x) end else result = obj.__send__(msg.intern, *argv) end
  23. break? kvs.each do |k,v| break if k == "foo" p

    v end LocalJumpError: break from proc-closure ! from (druby://eleven.local:61018) ..... ! from (druby://eleven.local:61018) ..... ! from (druby://eleven.local:61018) .....
  24. def perform_with_block @obj.__send__(@msg_id, *@argv) do |*x| jump_error = nil begin

    block_value = block_yield(x) rescue LocalJumpError jump_error = $! end if jump_error case jump_error.reason when :break break(jump_error.exit_value) else raise jump_error end end block_value end endɹ
  25. My thoughts on Metaprogramming Isn’t metaprogramming too magical? Magic should

    not look like magic. Your magic is complete if no one notices it