@m_seki の

I like ruby tooから引っ越し

iUI

iUIっていうのを見つけたので、Rinda::TupleSpaceのインスペクタを書いてみた。

持っているタプル、takeで待っているパターンとpeeraddr、readで待っているパターンとpeeraddrが見られるので、きっと勉強会とか勉強会とか勉強会とかで使い道がありそう。

まず、いつもと同じCGI部分。

#!/usr/local/bin/ruby
require 'drb/drb'

DRb.start_service
ro = DRbObject.new_with_uri('druby://localhost:54321?cgi')
ro.start(ENV.to_hash, $stdin, $stdout)

つぎにインスペクタ+iUIインターフェイス。これがサーバとして常駐するよ。
DRbObject.new_with_uri('druby://localhost:54321?ts')というオブジェクトがタプルスペースなので、irbなり、スクリプトなりを書いてdRuby経由で叩くと実験できる。
なお、CGI部分が叩いてるDRbObject.new_with_uri('druby://localhost:54321?cgi')はWEBrick::CGIね。

require 'rinda/tuplespace'
require 'rinda_inspect'
require 'erb'
require 'webrick/cgi'

class Page
  include ERB::Util
  
  Base = <<EOS
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Rinda Inspector</title>
<meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
<style type="text/css" media="screen">@import "../iui/iui.css";</style>
<script type="application/x-javascript" src="../iui/iui.js"></script>
</head>

<body>
    <div class="toolbar">
        <h1 id="pageTitle"></h1>
        <a id="backButton" class="button" href="#"></a>
    </div>
    <ul id="home" title="Rinda" selected="true">
        <li><a href="#tuple">Tuples <small><%= context.tuple.size%></small></a></li>
        <li><a href="#taker">Takers <small><%= context.taker.size%></small></a></li>
        <li><a href="#reader">Readers <small><%= context.reader.size%></small></a></li>
    </ul>
    <ul id="tuple" title="Tuples">
<% context.tuple.each do |t| %>
        <li><%=p t%></li>
<% end %>
    </ul>
    <ul id="taker" title="Takers">
<% context.taker.each do |t| %>
        <li><%=p t[0]%>@<%=p (t[1][1] || t[1][0])%></li>
<% end %>
    </ul>
    <ul id="reader" title="Readers">
<% context.reader.each do |t| %>
        <li><%=p t[0]%>@<%=p (t[1][1] || t[1][0])%></li>
<% end %>
    </ul>
</body>
</html>
EOS

  ERB.new(Base).def_method(self, 'to_html(context)')

  def p(obj)
    h(obj.inspect)
  end
end

class MyApp < WEBrick::CGI
  def initialize(*args)
    super(*args)
    @ts = Rinda::TupleSpace.new
  end
  attr_reader :ts
  
  def do_GET(req, res)
    res['content-type'] = 'text/html; charset= EUC-JP'
    report = @ts.report
    res.body = Page.new.to_html(report)
    res.status = 200
  end

  def do_POST(req, res); do_GET(req, res); end
end

class Front
  def initialize(app)
    @app = app
  end

  def [](key)
    return @app.ts if key == 'ts'
    @app
  end
end

app = MyApp.new
DRb.start_service('druby://:54321', Front.new(app))
DRb.thread.join

まえにも載せた気がするけどRinda::TupleSpaceに穴を開けて中をのぞくrinda_inspect.rb。

require 'drb/drb'
require 'rinda/tuplespace'
require 'pp'

module Rinda
  class TupleSpace
    attr_reader :bag, :read_waiter, :take_waiter, :notify_waiter

    def report
      synchronize do
        TupleSpaceReport.new(self)
      end
    end
  end

  class TupleBag
    include Enumerable
    def each(&blk)
      each_entry(&blk)
    end
  end

  class WaitTemplateEntry
    attr_reader :cond
  end

  class TupleSpaceReport
    def initialize(ts)
      @tuple = ts.bag.collect {|t| t.value}
      @reader = ts.read_waiter.collect {|t| [t.value, waiters(t)]}
      @taker = ts.take_waiter.collect {|t| [t.value, waiters(t)]}
    end
    attr_reader :tuple, :reader, :taker

    def waiters(tuple)
      tuple.cond.instance_variable_get(:@waiters).collect do |th|
        [th, (th[:DRb]['client'].stream.peeraddr rescue nil)]
      end[0]
    end
  end
end