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

    View Slide

  2. Makoto Inoue
    Web Developer @ New Bamboo (UK)
    Translator of “The dRuby Book”

    View Slide

  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

    View Slide

  4. Seki san @ Work
    Embedded
    RealTime
    Network
    GUI

    View Slide

  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

    View Slide

  6. History of dRuby
    1999-3
    ERB
    1999-9
    DRb
    2003
    committer
    2010
    pokemon-master
    2000
    Rinda
    1998
    started ruby
    2006 - 2011
    Ruby Kaigi

    View Slide

  7. Thank you to Our Sponsors
    Ruby No Kai
    new bamboo

    View Slide

  8. Thank you to Our Sponsors
    @PUPRL @ayumin
    @arika @mame
    @ vestige_ @track8
    @ nagachika
    "ruby trunk changes"
    @ktou
    Powered by Rabbit
    @tsuboi @ayako119
    @hisashim

    View Slide

  9. Table Of Contents
    What is dRuby ?
    Before dRuby (BD)
    Designing dRuby
    Q&A

    View Slide

  10. What is dRuby?
    Distributed Object System
    Can invoke methods in different processes
    Can send objects between processes
    Pure Ruby
    Ruby standard library

    View Slide

  11. Demo1 Starting up

    View Slide

  12. Demo2 Which is the server?

    View Slide

  13. Demo3 Distributed Queue

    View Slide

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

    View Slide

  15. dRuby usage: prototyping

    View Slide

  16. Before dRuby (BD)

    View Slide

  17. Old-fashioned programmer (BD8)
    Used to program in old Unix style
    IPC (Inter-Process Communication)
    fork/pipe, SystemV IPC

    View Slide

  18. Simple world of CGI (BD5)
    request/response, stateless
    Converted my IPC programs to CGI

    View Slide

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

    View Slide

  20. Ruby & shttpsrv
    Web server written in Ruby
    Before WEBrick
    Small and extensible

    View Slide

  21. Embedding HTTP into processes
    Embedding web server into small apps are fun
    Application communication via HTTP

    View Slide

  22. Ruby everywhere
    I used to play with various languages with CGI, but now
    everything is Ruby

    View Slide

  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

    View Slide

  24. I just want Ruby to talk each other
    Converting Ruby world to Web world is restricting
    Too much abstraction?

    View Slide

  25. Back to Ruby
    They are Ruby objects. Let’s call them in Ruby-ish way

    View Slide

  26. Back to Ruby
    Distributed objects acting like Ruby
    RPC -> RMI
    Extending Ruby’s method invocation to socket programming

    View Slide

  27. Why metaprogramming?
    Need a perfect proxy acting like Ruby
    Perfect fake that acts like normal Ruby

    View Slide

  28. Designing dRuby
    method_missing
    Marshal
    ObjectSpace._id2ref & send
    Other Techniques

    View Slide

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

    View Slide

  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

    View Slide

  31. Marshal
    Serializes objects

    View Slide

  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

    View Slide

  33. Marshal
    File, Thread, Proc raise exceptions
    If you can not serialize, then serialize its proxy
    Send Object references

    View Slide

  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

    View Slide

  35. ObjectSpace._id2ref & send
    Find a object using object id
    The server finds the object and dispatches the method to it

    View Slide

  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

    View Slide

  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

    View Slide

  38. Other techniques
    How do you recover unknown objects?
    Multithreading
    Handling method call with block

    View Slide

  39. Demo4 DRbUnknown

    View Slide

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

    View Slide

  41. class DRbMessage
    ...
    def load(soc)
    ...
    begin
    ...
    Marshal.load(str)
    rescue NameError, ArgumentError
    DRbUnknown.new($!, str)
    ensure
    ...
    end
    ...
    end
    end

    View Slide

  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

    View Slide

  43. class DRbUnknown
    ...
    def _dump(lv)
    @buf
    end
    ...
    end

    View Slide

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

    View Slide

  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

    View Slide

  46. Multithreading
    Ruby socket programming patterns from shttpsrv

    View Slide

  47. Thread.start(@soc.accept) do |s|
    begin
    ro, msg, arg = recv_request(s)
    ...
    send_response(s, succ, result)
    ensure
    s.close
    end
    end

    View Slide

  48. Handling method call with block
    kvs.each do |k,v|
    p v
    end

    View Slide

  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

    View Slide

  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) .....

    View Slide

  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ɹ

    View Slide

  52. Did you get it?

    View Slide

  53. Summary
    IPC -> http RPC -> dRuby
    dRuby metaprogramming techniques
    It’s your turn now.

    View Slide

  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

    View Slide

  55. You have everything you need
    Now it’s your turn

    View Slide