Save 37% off PRO during our Black Friday Sale! »

Rails is A Follower

Rails is A Follower

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

40f4d1f2e77078955bd01e9fb4a503ba?s=128

seki at druby.org

November 02, 2012
Tweet

Transcript

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

    metaprogramming magic Masatoshi SEKI Makoto Inoue
  2. Makoto Inoue Web Developer @ New Bamboo (UK) Translator of

    “The dRuby Book”
  3. Masatoshi Seki Ruby committer Author of dRuby/Rinda Author of ERB

    Pokemon Master The ERB Book Embed ruby script in any document using ERB
  4. Seki san @ Work Embedded RealTime Network GUI

  5. 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
  6. History of dRuby 1999-3 ERB 1999-9 DRb 2003 committer 2010

    pokemon-master 2000 Rinda 1998 started ruby 2006 - 2011 Ruby Kaigi
  7. Thank you to Our Sponsors Ruby No Kai new bamboo

  8. Thank you to Our Sponsors @PUPRL @ayumin @arika @mame @

    vestige_ @track8 @ nagachika "ruby trunk changes" @ktou Powered by Rabbit @tsuboi @ayako119 @hisashim
  9. Table Of Contents What is dRuby ? Before dRuby (BD)

    Designing dRuby Q&A
  10. What is dRuby? Distributed Object System Can invoke methods in

    different processes Can send objects between processes Pure Ruby Ruby standard library
  11. Demo1 Starting up

  12. Demo2 Which is the server?

  13. Demo3 Distributed Queue

  14. dRuby usage: distributed RSpec Used at Cookpad Ask @mrkn for

    the detail
  15. dRuby usage: prototyping

  16. Before dRuby (BD)

  17. Old-fashioned programmer (BD8) Used to program in old Unix style

    IPC (Inter-Process Communication) fork/pipe, SystemV IPC
  18. Simple world of CGI (BD5) request/response, stateless Converted my IPC

    programs to CGI
  19. Ruby & shttpsrv (BD1) 1998-9 Met Ruby & shttpsrv

  20. Ruby & shttpsrv Web server written in Ruby Before WEBrick

    Small and extensible
  21. Embedding HTTP into processes Embedding web server into small apps

    are fun Application communication via HTTP
  22. Ruby everywhere I used to play with various languages with

    CGI, but now everything is Ruby
  23. 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
  24. I just want Ruby to talk each other Converting Ruby

    world to Web world is restricting Too much abstraction?
  25. Back to Ruby They are Ruby objects. Let’s call them

    in Ruby-ish way
  26. Back to Ruby Distributed objects acting like Ruby RPC ->

    RMI Extending Ruby’s method invocation to socket programming
  27. Why metaprogramming? Need a perfect proxy acting like Ruby Perfect

    fake that acts like normal Ruby
  28. Designing dRuby method_missing Marshal ObjectSpace._id2ref & send Other Techniques

  29. method_missing Respond to unknown methods Used for Proxies to catch

    method calls
  30. class DRbObject ... def method_missing(msg_id, *a) succ, result = DRbConn.new(@uri).send_message(self,

    msg_id, *a) raise result if ! succ result end ... end
  31. Marshal Serializes objects

  32. 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
  33. Marshal File, Thread, Proc raise exceptions If you can not

    serialize, then serialize its proxy Send Object references
  34. 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
  35. ObjectSpace._id2ref & send Find a object using object id The

    server finds the object and dispatches the method to it
  36. 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
  37. 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
  38. Other techniques How do you recover unknown objects? Multithreading Handling

    method call with block
  39. Demo4 DRbUnknown

  40. What has just happened? Who did replace Foo with DRbUnknown?

  41. class DRbMessage ... def load(soc) ... begin ... Marshal.load(str) rescue

    NameError, ArgumentError DRbUnknown.new($!, str) ensure ... end ... end end
  42. 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
  43. class DRbUnknown ... def _dump(lv) @buf end ... end

  44. What has just happened? How does DRbUnkown#reload work?

  45. 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
  46. Multithreading Ruby socket programming patterns from shttpsrv

  47. Thread.start(@soc.accept) do |s| begin ro, msg, arg = recv_request(s) ...

    send_response(s, succ, result) ensure s.close end end
  48. Handling method call with block kvs.each do |k,v| p v

    end
  49. 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
  50. 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) .....
  51. 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ɹ
  52. Did you get it?

  53. Summary IPC -> http RPC -> dRuby dRuby metaprogramming techniques

    It’s your turn now.
  54. My thoughts on Metaprogramming Isn’t metaprogramming too magical? Magic should

    not look like magic. Your magic is complete if no one notices it
  55. You have everything you need Now it’s your turn