module Delayer::Deferred::Deferredable::Graph

graphvizによってChainableなDeferredをDOT言語形式でダンプする機能を追加するmix-in。 いずれかのノードに対して graph メソッドを呼ぶと、再帰的に親子を全て辿り、digraphの断片の文字列を得ることが出来る。

出力例

20892180 [shape=egg,label="#<Class:0x000000027da288>.Promise\n(reserved)"]
20892480 [shape=box,label="test/thread_test.rb:53\n(connected)"]
20891440 [shape=diamond,label="test/thread_test.rb:56\n(fresh)"]
20892480 -> 20891440
20892180 -> 20892480

Public Instance Methods

graph(child_only: false, output: String.new) click to toggle source

この一連のDeferredチェインの様子を、DOT言語フォーマットで出力する

Args

child_only:

true なら、このノードとその子孫のみを描画する。 false なら、再帰的に親を遡り、そこから描画を開始する。

output:

このオブジェクトに、 _<<_ メソッドで内容が書かれる。 省略した場合は、戻り値が String になる。

Return

String

DOT言語によるグラフ

output:

引数 output: に指定されたオブジェクト

# File lib/delayer/deferred/deferredable/graph.rb, line 28
def graph(child_only: false, output: String.new)
  if child_only
    output << "digraph Deferred {\n".freeze
    Enumerator.new{ |yielder|
      graph_child(output: yielder)
    }.lazy.each{|l|
      output << "\t#{l}\n"
    }
    output << '}'.freeze
  else
    ancestor.graph(child_only: true, output: output)
  end
end
graph_child(output:) click to toggle source

このノードとその子全てのDeferredチェインの様子を、DOT言語フォーマットで出力する。 Delayer::Deferred::Deferredable::Graph#graph の内部で利用されるため、将来このメソッドのインターフェイスは変更される可能性がある。

# File lib/delayer/deferred/deferredable/graph.rb, line 79
def graph_child(output:)
  output << graph_mynode
  if has_child?
    @child.graph_child(output: output)
    output << "#{__id__} -> #{@child.__id__}"
  end
  if has_awaited?
    awaited.each do |awaitable|
      if awaitable.is_a?(Delayer::Deferred::Deferredable::Chainable)
        awaitable.ancestor.graph_child(output: output)
      else
        label = "#{awaitable.class}"
        output << "#{awaitable.__id__} [shape=oval,label=#{label.inspect}]"
      end
      output << "#{awaitable.__id__} -> #{__id__} [label = \"await\", style = \"dotted\"]"
    end
  end
  nil
end
graph_draw(dir: '/tmp', format: 'svg'.freeze) click to toggle source

画像ファイルとしてグラフを書き出す。 dotコマンドが使えないと失敗する。

Args

format:

画像の拡張子

Return

String

書き出したファイル名

# File lib/delayer/deferred/deferredable/graph.rb, line 68
def graph_draw(dir: '/tmp', format: 'svg'.freeze)
  graph_save do |dotfile|
    base = File.basename(dotfile.path)
    dest = File.join(dir, "#{base}.#{format}")
    system("dot -T#{format} #{dotfile.path} -o #{dest}")
    dest
  end
end
graph_save(permanent: false, &block) click to toggle source

Graph.graph の結果を内容とする一時ファイルを作成して返す。 ただし、ブロックを渡された場合は、一時ファイルを引数にそのブロックを一度だけ実行し、ブロックの戻り値をこのメソッドの戻り値とする。

Args

&block

一時ファイルを利用する処理

Return

Tempfile

ブロックを指定しなかった場合。作成された一時ファイルオブジェクト

Object

ブロックが指定された場合。ブロックの実行結果。

# File lib/delayer/deferred/deferredable/graph.rb, line 49
def graph_save(permanent: false, &block)
  if block
    Tempfile.open{|tmp|
      graph(output: tmp)
      tmp.seek(0)
      block.(tmp)
    }
  else
    tmp = Tempfile.open
    graph(output: tmp).tap{|t|t.seek(0)}
  end
end

Private Instance Methods

graph_mynode() click to toggle source

このノードの形などをDOT言語の断片で返す。 このメソッドをオーバライドすることで、描画されるノードの見た目を自由に変更することが出来る。 ただし、簡単な変更だけなら別のメソッドをオーバライドするだけで可能なので、このmix-inの他のメソッドも参照すること。

# File lib/delayer/deferred/deferredable/graph.rb, line 111
def graph_mynode
  label = "#{node_name}\n(#{sequence.name})"
  "#{__id__} [shape=#{graph_shape},label=#{label.inspect}]"
end
graph_shape() click to toggle source

このノードを描画する時の形の名前を文字列で返す。 以下のページにあるような、graphvizで取り扱える形の中から選ぶこと。 www.graphviz.org/doc/info/shapes.html

# File lib/delayer/deferred/deferredable/graph.rb, line 104
def graph_shape
  'oval'.freeze
end