Search code examples
ruby

block sees self as the object it is sent to


I have the following code for connecting to websockets

class Connection < AbstractConnection
  def initialize

    @conn = WebSocket::Client::Simple.connect @url

    @conn.on :message do |event|
      puts 'received message' 
      #this is the weird part
      puts self
      event_data = event.data.to_json
      on_message event_data
    end
  end
end

the weird thing is that inside those blocks self is equal to Websocket:Client:Simple - and those methods I am calling inside the blocks are missing, so there is an error.

the library I am using for connecting to the websocket is this https://github.com/shokai/websocket-client-simple and it uses event emitter gem to emit events when messages are received.

I really would expect the blocks to identify self as where they are created - as they do in .each method.

so the qustion is what is going on, and how can I call local methods.


Solution

  • I really would expect the blocks to identify self as where they are created - as they do in .each method.

    Normally this would be what happens, if the method used yield or blk.call, but in this case the on method captures the block as a proc, and later calls it with instance_exec, so it executes in the context of WebSocket::Client::Simple::Client.

    Unfortunately there is no way to tell from the signature alone what any given method will do with a block passed to it.

    One option might be to store the value of self in a local variable before the block. Local variables are still available from the block when it is executed in a different context.

    # capture self
    this = self
    @conn.on :message do |event|
      # ...
    
      # use this to call methods
      this.on_message event_data
    end