<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>processi</title>
	<atom:link href="http://jmettraux.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://jmettraux.wordpress.com</link>
	<description>about processes and engines</description>
	<lastBuildDate>Sun, 21 Apr 2013 22:15:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='jmettraux.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>processi</title>
		<link>http://jmettraux.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://jmettraux.wordpress.com/osd.xml" title="processi" />
	<atom:link rel='hub' href='http://jmettraux.wordpress.com/?pushpress=hub'/>
		<item>
		<title>moving to jmettraux.github.com</title>
		<link>http://jmettraux.wordpress.com/2012/05/07/moving-to-jmettraux-github-com/</link>
		<comments>http://jmettraux.wordpress.com/2012/05/07/moving-to-jmettraux-github-com/#comments</comments>
		<pubDate>Mon, 07 May 2012 06:23:57 +0000</pubDate>
		<dc:creator>John Mettraux</dc:creator>
				<category><![CDATA[openwferu]]></category>

		<guid isPermaLink="false">http://jmettraux.wordpress.com/2012/05/07/moving-to-jmettraux-github-com/</guid>
		<description><![CDATA[This blog is moving to http://jmettraux.github.com The feed is at http://jmettraux.github.com/atom.xml Meet you there.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2418&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>This blog is moving to <a href="http://jmettraux.github.com">http://jmettraux.github.com</a></p>
<p>The feed is at <a href="http://jmettraux.github.com/atom.xml">http://jmettraux.github.com/atom.xml</a></p>
<p>Meet you there.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jmettraux.wordpress.com/2418/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jmettraux.wordpress.com/2418/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2418&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jmettraux.wordpress.com/2012/05/07/moving-to-jmettraux-github-com/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/8d96626e52beb1ff90f57a8e189e1e6f?s=96&#38;d=&#38;r=G" medium="image">
			<media:title type="html">jmettraux</media:title>
		</media:content>
	</item>
		<item>
		<title>rufus-scheduler 2.0.12 released</title>
		<link>http://jmettraux.wordpress.com/2011/10/28/rufus-scheduler-2-0-12-released/</link>
		<comments>http://jmettraux.wordpress.com/2011/10/28/rufus-scheduler-2-0-12-released/#comments</comments>
		<pubDate>Fri, 28 Oct 2011 11:27:02 +0000</pubDate>
		<dc:creator>John Mettraux</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[rufus]]></category>
		<category><![CDATA[rufus-scheduler]]></category>
		<category><![CDATA[scheduling]]></category>

		<guid isPermaLink="false">http://jmettraux.wordpress.com/?p=2397</guid>
		<description><![CDATA[rufus-scheduler is a thread-based scheduler written in Ruby. It lets you write code like: The main addition brought by this release is the :mutex attribute when scheduling blocks of code. I was seeing people misusing :blocking =&#62; true to exclude block execution overlapping. It works but the scheduler is blocked as well, and crons might [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2397&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p><a href="https://github.com/jmettraux/rufus-scheduler">rufus-scheduler</a> is a thread-based scheduler written in Ruby. It lets you write code like:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'rufus-scheduler'

s = Rufus::Scheduler.start_new

s.every '10m' do
  puts 'open the window for the cat'
end

s.at '2012-01-01 12:00' do
  puts 'reminder: wife's birthday'
end

s.cron '0 22 * * 1-5' do
  puts 'activate the security system'
end

s.join # in case of stand-alone script...
</pre>
<p>The main addition brought by this release is the :mutex attribute when scheduling blocks of code. I was seeing people misusing :blocking =&gt; true to exclude block execution overlapping. It works but the scheduler is blocked as well, and crons might get skipped:</p>
<pre class="brush: ruby; title: ; notranslate">
s.every '10m', :blocking =&gt; true do
  puts 'doing this...'
  sleep 60 * 60 # 1 hour
  puts 'done.'
end

# if the scheduler is in the blocking task above, crons will get skipped...
s.at '2012-01-01 12:00' do
  puts 'do that.'
end
</pre>
<p>My advice was to use mutexes instead:</p>
<pre class="brush: ruby; title: ; notranslate">
$m = Mutex.new

s.every '10m' do
  $m.synchronize do
    puts 'doing this...'
    sleep 60 * 60 # 1 hour
    puts 'done.'
  end
end

# if the scheduler is in the blocking task above, crons will get skipped...
s.at '2012-01-01 12:00' do
  $m.synchronize do
    puts 'do that.'
  end
end
</pre>
<p>For those of you who use such mutexes and are OK with them wrapping the whole block, rufus-scheduler 2.0.12 introduces the :mutex attribute:</p>
<pre class="brush: ruby; title: ; notranslate">
s.every '10m', :mutex =&gt; 'my_mutex_name' do
  puts 'doing this...'
  sleep 60 * 60 # 1 hour
  puts 'done.'
end

# if the scheduler is in the blocking task above, crons will get skipped...
s.at '2012-01-01 12:00', :mutex =&gt; 'my_mutex_name'  do
  puts 'do that.'
end
</pre>
<p>Where rufus-scheduler receives a mutex name and manages it for you.</p>
<p>When one wants more control over the granularity, it&#8217;s OK to do:</p>
<pre class="brush: ruby; title: ; notranslate">
$m = Mutex.new

s.every '10m', :mutex =&gt; $m do
  puts 'doing this...'
  sleep 60 * 60 # 1 hour
  puts 'done.'
end

# if the scheduler is in the blocking task above, crons will get skipped...
s.at '2012-01-01 12:00' do
  puts 'do that'
  $m.synchronize do
    puts 'and that.'
  end
end
</pre>
<p>&nbsp;</p>
<p>Remember that rufus-scheduler is not a cron replacement. Many thanks to all the people who complained or helped in the development of this piece of software over the years.</p>
<p>&nbsp;</p>
<p>source: <a href="https://github.com/jmettraux/rufus-scheduler">https://github.com/jmettraux/rufus-scheduler</a><br />
issues: <a href="https://github.com/jmettraux/rufus-scheduler/issues">https://github.com/jmettraux/rufus-scheduler/issues</a><br />
mailing list: <a href="http://groups.google.com/group/rufus-ruby">http://groups.google.com/group/rufus-ruby</a><br />
irc: freenode #ruote</p>
<p>&nbsp;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jmettraux.wordpress.com/2397/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jmettraux.wordpress.com/2397/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2397&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jmettraux.wordpress.com/2011/10/28/rufus-scheduler-2-0-12-released/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/8d96626e52beb1ff90f57a8e189e1e6f?s=96&#38;d=&#38;r=G" medium="image">
			<media:title type="html">jmettraux</media:title>
		</media:content>
	</item>
		<item>
		<title>Parslet and JSON</title>
		<link>http://jmettraux.wordpress.com/2011/05/11/parslet-and-json/</link>
		<comments>http://jmettraux.wordpress.com/2011/05/11/parslet-and-json/#comments</comments>
		<pubDate>Wed, 11 May 2011 07:10:45 +0000</pubDate>
		<dc:creator>John Mettraux</dc:creator>
				<category><![CDATA[json]]></category>
		<category><![CDATA[parslet]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://jmettraux.wordpress.com/?p=2362</guid>
		<description><![CDATA[Parslet is a small Ruby library for constructing parsers based on Parsing Expression Grammars (PEG). It&#8217;s written by Kaspar Schiess and various contributors. This blog post introduces Parslet with a parser example. Since JSON has very easy to grasp railroad diagrams for its syntax, it might make for a good example. Please note that the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2362&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p><a href="http://kschiess.github.com/parslet/">Parslet</a> is a small Ruby library for constructing parsers based on <a href="http://en.wikipedia.org/wiki/Parsing_expression_grammar">Parsing Expression Grammars</a> (PEG). It&#8217;s written by <a href="http://blog.absurd.li/">Kaspar Schiess</a> and various <a href="http://kschiess.github.com/parslet/contribute.html">contributors</a>.</p>
<p>This blog post introduces Parslet with a parser example. Since JSON has very easy to grasp <a href="http://json.org/">railroad diagrams</a> for its syntax, it might make for a good example.</p>
<p>Please note that the JSON parser here won&#8217;t compete for speed with available libraries. No benchmarks here.</p>
<p>Our goal is to take as input JSON strings and output the resulting value.</p>
<p>For the impatient, the end result is at <a href="https://gist.github.com/966020">https://gist.github.com/966020</a></p>
<p>How is an array encoded in JSON ?</p>
<p><img src="http://json.org/array.gif" style="border:0;" /></p>
<p>How would that look in our parser ?</p>
<pre class="brush: ruby; title: ; notranslate">
  class Parser &lt; Parslet::Parser

    rule(:spaces) { match('\s').repeat(1) }
      # at least 1 space character (space, tab, new line, carriage return)

    rule(:spaces?) { spaces.maybe }
      # a bunch of spaces or not

    rule(:comma) { spaces? &gt;&gt; str(',') &gt;&gt; spaces? }
      # a comma surrounded by optional spaces

    rule(:array) {
      str('[') &gt;&gt; spaces? &gt;&gt;
      (value &gt;&gt; (comma &gt;&gt; value).repeat).maybe.as(:array) &gt;&gt;
      spaces? &gt;&gt; str(']')
    }
  end
</pre>
<p>What is this value thing ?</p>
<p><img src="http://json.org/value.gif" style="border:0;" /></p>
<p>string or number or object or &#8230;</p>
<pre class="brush: ruby; title: ; notranslate">
    rule(:value) {
      string | number |
      object | array |
      str('true').as(:true) | str('false').as(:false) |
      str('null').as(:null)
    }
</pre>
<p>All is good, a few parsing rules laters, we have a complete JSON parser, but wait, what does it output ?</p>
<pre class="brush: ruby; title: ; notranslate">
p MyJson::Parser.new.parse(%{
  [ 1, 2, 3, null,
    &quot;asdfasdf asdfds&quot;, { &quot;a&quot;: -1.2 }, { &quot;b&quot;: true, &quot;c&quot;: false },
    0.1e24, true, false, [ 1 ] ]
})
# =&gt; {:array=&gt;[{:number=&gt;&quot;1&quot;@5}, {:number=&gt;&quot;2&quot;@8}, {:number=&gt;&quot;3&quot;@11}, {:null=&gt;&quot;null&quot;@14}, {:string=&gt;&quot;asdfasdf asdfds&quot;@25}, {:object=&gt;{:entry=&gt;{:val=&gt;{:number=&gt;&quot;-1.2&quot;@50}, :key=&gt;{:string=&gt;&quot;a&quot;@46}}}}, {:object=&gt;[{:entry=&gt;{:val=&gt;{:true=&gt;&quot;true&quot;@65}, :key=&gt;{:string=&gt;&quot;b&quot;@61}}}, {:entry=&gt;{:val=&gt;{:false=&gt;&quot;false&quot;@76}, :key=&gt;{:string=&gt;&quot;c&quot;@72}}}]}, {:number=&gt;&quot;0.1e24&quot;@89}, {:true=&gt;&quot;true&quot;@97}, {:false=&gt;&quot;false&quot;@103}, {:array=&gt;{:number=&gt;&quot;1&quot;@112}}]}
</pre>
<p>Oh well, that is not exactly what we want as final result. Parslet calls the output of its parser a &#8220;intermediate tree&#8221;. It separates <a href="http://kschiess.github.com/parslet/parser.html">parsing</a> from <a href="http://kschiess.github.com/parslet/transform.html">transformation</a>.</p>
<p>We need a transformer and it looks like :</p>
<pre class="brush: ruby; title: ; notranslate">
  class Transformer &lt; Parslet::Transform

    class Entry &lt; Struct.new(:key, :val); end

    rule(:array =&gt; subtree(:ar)) {
      ar.is_a?(Array) ? ar : [ ar ]
    }
    rule(:object =&gt; subtree(:ob)) {
      (ob.is_a?(Array) ? ob : [ ob ]).inject({}) { |h, e| h[e.key] = e.val; h }
    }

    rule(:entry =&gt; { :key =&gt; simple(:ke), :val =&gt; simple(:va) }) {
      Entry.new(ke, va)
    }

    rule(:string =&gt; simple(:st)) {
      st.to_s
    }
    rule(:number =&gt; simple(:nb)) {
      nb.match(/[eE\.]/) ? Float(nb) : Integer(nb)
    }

    rule(:null =&gt; simple(:nu)) { nil }
    rule(:true =&gt; simple(:tr)) { true }
    rule(:false =&gt; simple(:fa)) { false }
  end
</pre>
<p>Patterns in the intermediate tree are indentified and replaced, producing a final output (or yet another intermediate result, it&#8217;s up to you).</p>
<p>The complete parser (and transformer and small test) is at <a href="https://gist.github.com/966020">https://gist.github.com/966020</a></p>
<p>There isn&#8217;t much more I could say. Ah yes, about testing. Kaspar explains it in the <a href="http://kschiess.github.com/parslet/tricks.html">tricks</a>, you can directly test parsing rules individually :</p>
<pre class="brush: ruby; title: ; notranslate">
class MyJsonTest &lt; Test::Unit::TestCase
  def parser
    MyJson::Parser.new
  end
  def test_parser_number_integer
    assert_equal 1, parser.number(&quot;1&quot;)
  end
  def test_parser_number_float
    assert_equal 1.0, parser.number(&quot;1.0&quot;)
  end
  def test_parser_number_not_a_number
    assert_raise Parslet::ParseFailed do
      parser.number(&quot;whatever&quot;)
    end
  end
end
</pre>
<p>Happy parsing (and transforming) !</p>
<p>&nbsp;</p>
<p>the json parser : <a href="https://gist.github.com/966020">https://gist.github.com/966020</a></p>
<p>documentation : <a href="http://kschiess.github.com/parslet/">http://kschiess.github.com/parslet/</a><br />
source code : <a href="https://github.com/kschiess/parslet">https://github.com/kschiess/parslet</a><br />
mailing list : ruby.parslet@librelist.com<br />
irc : freenode.net #parslet</p>
<p>No animals got benchmarked during this blog post.</p>
<p>&nbsp;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jmettraux.wordpress.com/2362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jmettraux.wordpress.com/2362/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2362&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jmettraux.wordpress.com/2011/05/11/parslet-and-json/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/8d96626e52beb1ff90f57a8e189e1e6f?s=96&#38;d=&#38;r=G" medium="image">
			<media:title type="html">jmettraux</media:title>
		</media:content>

		<media:content url="http://json.org/array.gif" medium="image" />

		<media:content url="http://json.org/value.gif" medium="image" />
	</item>
		<item>
		<title>ruote 2.2.0 released</title>
		<link>http://jmettraux.wordpress.com/2011/03/02/ruote-2-2-0-released/</link>
		<comments>http://jmettraux.wordpress.com/2011/03/02/ruote-2-2-0-released/#comments</comments>
		<pubDate>Wed, 02 Mar 2011 10:46:43 +0000</pubDate>
		<dc:creator>John Mettraux</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruote]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://jmettraux.wordpress.com/?p=2241</guid>
		<description><![CDATA[Just released version 2.2.0 of ruote, a Ruby workflow engine. It interprets workflow definitions, routing tasks / work among participants. &#160; the changelog 2.2.x Why a 2.2.x ? It&#8217;s not that ruote 2.2.0 is not backward compatible but it now flags all the expression with a sub_id (formerly called a sub_wfid). Previously only the expressions [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2241&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Just released version 2.2.0 of <a href="http://ruote.rubyforge.org">ruote</a>, a Ruby workflow engine. It interprets workflow definitions, routing tasks / work among participants.</p>
<pre class="brush: ruby; title: ; notranslate">
Ruote.process_definition do
  alice :task =&gt; 'prepare offer'
  bob :task =&gt; 'revise offer'
  concurrence do
    david :task =&gt; 'revise offer'
    fred :task =&gt; 'revise offer', :if =&gt; '${offer.total} &gt; 1000'
    elie :notification =&gt; 'offer for ${customer.name} (${customer.city}) out'
  end
  charly :task =&gt; 'submit offer'
  accounting :task =&gt; 'emit invoice'
end
</pre>
<p>&nbsp;</p>
<p><a href="https://github.com/jmettraux/ruote/blob/ff32f3f702e9750626b68bb3ce4938546d50428f/CHANGELOG.txt#L4-61">the changelog</a></p>
<h3>2.2.x</h3>
<p>Why a 2.2.x ? It&#8217;s not that ruote 2.2.0 is not backward compatible but it now flags all the expression with a sub_id (formerly called a sub_wfid). Previously only the expressions in a subprocess would have a subid, now all the expressions have one. It prevents some nasty issues with <a href="http://ruote.rubyforge.org/exp/concurrent_iterator.html">concurrent-iterator</a> and <a href="http://ruote.rubyforge.org/common_attributes.html#forget">forget</a>.</p>
<p>The second justification for a 2.2.x are stateful participants being dropped.</p>
<h3>stateless participants</h3>
<p>Before 2.2.0, participants could be registered as classes or instances. From now on, only participant classes can be registered. Each time a ruote worker dispatches a workitem to a participant it uses a new instance. Such &#8220;stateless&#8221; participants cannot share info via instance variables.</p>
<p>Block participants like</p>
<pre class="brush: ruby; title: ; notranslate">
engine.register_participant 'total' do |workitem|
  workitem.fields['total'] = workitem.fields['items'].inject(0) { |t, (i, c)|
    item = Item.find(i)
    t = t + c * item.price
  end
end
</pre>
<p>are a bit harder to make &#8220;stateless&#8221;. But thanks to the ingenious <a href="https://github.com/ngty/sourcify">Sourcify</a>, grabbing the source of the block is not a problem. Small reminder, it grabs the source code of the block, not its closure.</p>
<p>Simply put, stateful participants have been dropped.</p>
<p>Now for the rest of the changes.</p>
<h3>composite conditions</h3>
<p>Conditions in process definitions were constrained to things like &#8220;${customer.level} == gold&#8221;, which works OK if you want to keep concise process definitions. Adding a quick &#8216;and&#8217; should not require too many workarounds. This is now possible :</p>
<pre class="brush: ruby; title: ; notranslate">
Ruote.process_definition do
  participant 'alice', :if =&gt; &quot;${customer.level} == 'gold'&quot;
  participant 'bob', :if =&gt; '${customer.level} == gold and ${customer.country} == Brazil'
end
</pre>
<p>Other idioms like &#8220;${customer_list} is empty&#8221;, &#8220;${customer} in ${customer_list}&#8221;, &#8220;${x} is null&#8221; are accepted. <a href="https://github.com/jmettraux/ruote/blob/ff32f3f702e9750626b68bb3ce4938546d50428f/test/unit/ut_6_condition.rb">The</a> <a href="https://github.com/jmettraux/ruote/blob/ff32f3f702e9750626b68bb3ce4938546d50428f/test/functional/ft_17_conditional.rb">tests</a> are probably a more exhaustive source of info about those idioms.</p>
<p>Speaking of the <a href="http://ruote.rubyforge.org/dollar.html">dollar notation</a>, it was all about strings, whatever the values it would turn them into strings. There is a new <a href="http://ruote.rubyforge.org/dollar.html#literally">literal way</a> for dealing directly with non string values.</p>
<h3>on_error, on_terminate</h3>
<p>The Engine instance has two new <a href="http://ruote.rubyforge.org/configuration.html#engine_on">setters</a>, on_error= and on_terminate=. For example, this</p>
<pre class="brush: ruby; title: ; notranslate">
engine.on_error = 'supervisor'
</pre>
<p>states that the &#8216;supervisor&#8217; participant (whatever you registered under that name) will receive a notification (a workitem) each time a process instance emits an error in the engine.</p>
<p>on_error and on_terminate accept participant names, subprocess names or directly process definitions :</p>
<pre class="brush: ruby; title: ; notranslate">
engine.on_error = Ruote.process_definition do
  concurrence do
    administrator :msg =&gt; 'something went wrong'
    supervisor :msg =&gt; 'houston, we have a problem'
  end
end
</pre>
<h3>filters</h3>
<p>Thanks to a <a href="http://groups.google.com/group/openwferu-users/browse_thread/thread/94f873bd667932dc">collaboration with Raphael</a> filters are [back] in ruote.</p>
<p>They come in two forms : the <a href="http://ruote.rubyforge.org/exp/filter.html">filter expression</a> (one-way filtering of passing workitems) and the <a href="http://ruote.rubyforge.org/common_attributes.html#filter">:filter attribute</a> (placing a filter around a process region).</p>
<p>The filter attribute may also point to participants (registered like any other participants), focused on workitem filtering (whereas regular participants pass work to the underlying, real, participant).</p>
<h3>history</h3>
<p>Prior to 2.2.0, ruote had no history, the worker activity was not &#8216;archived&#8217;. A ruote engine will now have a <a href="https://github.com/jmettraux/ruote/blob/ff32f3f702e9750626b68bb3ce4938546d50428f/lib/ruote/log/default_history.rb">default history</a> keeping in memory the most recent worker operations.</p>
<p>If you really need such a history, you&#8217;d better use/customize the <a href="https://github.com/jmettraux/ruote/blob/ff32f3f702e9750626b68bb3ce4938546d50428f/lib/ruote/log/storage_history.rb">StorageHistory</a> class.</p>
<p>(well, you probably don&#8217;t need to keep record of all these operations).</p>
<h3>sequel</h3>
<p>There is a new storage implementation, <a href="https://github.com/jmettraux/ruote-sequel">ruote-sequel</a>. As the name implies, it&#8217;s based on the excellent <a href="http://sequel.rubyforge.org/">Sequel</a>.</p>
<p>A nice addition to the list of <a href="http://ruote.rubyforge.org/configuration.html#storage">storage implementations</a>.</p>
<h3>participants (again)</h3>
<p>You register participants, they are all stateless, why not get a copy out for <a href="http://ruote.rubyforge.org/implementing_participants.html#applied_workitem">certain interactions</a> ? Engine#participant is the counterpoint to Engine#register_participant.</p>
<p>Participants may provide their own timeout value by implementing the <a href="http://ruote.rubyforge.org/implementing_participants.html#rtimeout">rtimeout method</a> (the timeout given in the process definition, if any, will take precedence though).</p>
<h3>expressions</h3>
<p>The listen expression now reacts to a process instance entering or leaving a tag (a process instance region). See <a href="http://jmettraux.wordpress.com/2011/01/07/ruote-and-tags/">ruote and tags</a> for an explanation. The Workitem class now has a dedicated __tags__ field containing a list of tag names the process instance (that emitted the workitem) is currently in.</p>
<p>Ruote now has a &#8220;switch&#8221; statement, it&#8217;s a <a href="http://jmettraux.wordpress.com/2011/01/03/ruote-and-switch/">given</a> (also covers the new <a href="http://ruote.rubyforge.org/exp/let.html">let</a> expression).</p>
<p>The <a href="http://ruote.rubyforge.org/exp/cancel_process.html">cancel_process</a> expression has got a new alias &#8220;terminate&#8221;, <a href="http://ruote.rubyforge.org/exp/concurrent_iterator.html">concurrent_iterator</a> can be shortened to &#8220;citerator&#8221; while the <a href="http://ruote.rubyforge.org/exp/once.html">when</a> expression can be written &#8220;once&#8221; (or &#8220;as_soon_as&#8221;).</p>
<p>There is a new <a href="http://ruote.rubyforge.org/exp/let.html">let expression</a>. The main usage is to isolate a set of subprocess definitions in a new scope (case like).</p>
<p>The <a href="http://ruote.rubyforge.org/exp/registerp.html">registerp</a> and <a href="http://ruote.rubyforge.org/exp/unregisterp.html">unregisterp</a> expressions let you register participants from process definitions (granted, you could do that from the consume method of a participant too).</p>
<p>It was present in ruote 0.9.x but got lost in the way. The <a href="http://ruote.rubyforge.org/exp/lose.html">lose expression</a> and the <a href="http://ruote.rubyforge.org/common_attributes.html#lose">:lose attribute</a> are back (thanks Claudio). &#8216;forget&#8217; and &#8216;lose&#8217; are ways to put aside certain execution branches of a process instance.</p>
<h3>next steps</h3>
<p>Next steps ? Workers registering in the storage, pausing individual processes, having process supervise other processes, improved ruote-redis, &#8230;</p>
<p>&nbsp;</p>
<p>Many thanks to all who helped along the way.</p>
<p>&nbsp;</p>
<p>website : <a href="http://ruote.rubyforge.org">http://ruote.rubyforge.org</a><br />
source : <a href="https://github.com/jmettraux/ruote">https://github.com/jmettraux/ruote</a><br />
mailing list : <a href="http://groups.google.com/group/openwferu-users">http://groups.google.com/group/openwferu-users</a><br />
irc : freenode.net #ruote</p>
<p>&nbsp;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jmettraux.wordpress.com/2241/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jmettraux.wordpress.com/2241/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2241&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jmettraux.wordpress.com/2011/03/02/ruote-2-2-0-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/8d96626e52beb1ff90f57a8e189e1e6f?s=96&#38;d=&#38;r=G" medium="image">
			<media:title type="html">jmettraux</media:title>
		</media:content>
	</item>
		<item>
		<title>ruote, process state and tags</title>
		<link>http://jmettraux.wordpress.com/2011/01/07/ruote-and-tags/</link>
		<comments>http://jmettraux.wordpress.com/2011/01/07/ruote-and-tags/#comments</comments>
		<pubDate>Fri, 07 Jan 2011 13:24:47 +0000</pubDate>
		<dc:creator>John Mettraux</dc:creator>
				<category><![CDATA[bpm]]></category>
		<category><![CDATA[openwferu]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruote]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://jmettraux.wordpress.com/?p=2221</guid>
		<description><![CDATA[A : &#8220;What state is this process in ?&#8221; B : &#8220;Well, it&#8217;s running&#8221; A : &#8220;I know, that&#8217;s not what I meant. Where is it now ?&#8221; B : &#8220;Let&#8217;s check which participants have workitems (tasks) about this process now&#8221; A : &#8220;No, I mean, the document is it still being reviewed ? What&#8217;s [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2221&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>A : &#8220;What state is this process in ?&#8221;<br />
B : &#8220;Well, it&#8217;s running&#8221;<br />
A : &#8220;I know, that&#8217;s not what I meant. Where is it now ?&#8221;<br />
B : &#8220;Let&#8217;s check which participants have workitems (tasks) about this process now&#8221;<br />
A : &#8220;No, I mean, the document is it still being reviewed ? What&#8217;s its state ?&#8221;<br />
B : &#8220;Ah you mean, the document state, not the process state ?&#8221;<br />
A : &#8220;Is there a difference ?&#8221;<br />
B : &#8220;Well, if a business process deals with the state of multiple resources, you can&#8217;t equate process state and resource state&#8221;</p>
<p>Initially, for <a href="http://ruote.rubyforge.org">ruote</a> (a <a href="http://www.ruby-lang.org/">ruby</a> workflow engine), the <strong>&#8220;state of a process&#8221;</strong> was limited to &#8220;the set of visible workitems for that process&#8221;.</p>
<pre class="brush: ruby; title: ; notranslate">
Ruote.process_definition do
  cursor do
    production
    concurrence do
      qa1
      qa2
    end
    rewind :unless =&gt; '${qa_ok}'
    packaging
    delivery
  end
end
</pre>
<p>For this process, the states are &#8220;nil&#8221; (not running), &#8220;production&#8221;, &#8220;qa1&#8243; and/or &#8220;qa2&#8243;, &#8220;delivery&#8221;, and &#8220;packaging&#8221;.</p>
<p>(note that there is no &#8220;terminated&#8221; state, since, out of the box, ruote doesn&#8217;t do &#8216;process archiving&#8217; for you).</p>
<p>Asking all the participants about the workitems could get expensive, especially if they&#8217;re remote participants. It&#8217;s easier to ask the engine :</p>
<pre class="brush: ruby; title: ; notranslate">
p engine.process(wfid)
  # =&gt;
  # == Ruote::ProcessStatus ==
  #    expressions : 3
  #      0!69176db85a0651e7a8d8a16426bd93df!20110107-betesuguto : define {}
  #      0_0!be7ac163b2c6ba47d6d4b24bbb83fd8c!20110107-betesuguto : cursor {}
  #      0_0_0!3b19bdf68a953597969bac507229bcf1!20110107-betesuguto : participant {&quot;ref&quot;=&gt;&quot;production&quot;}
  #    schedules : 0
  #    stored workitems : 1
  #    variables :     {}
  #    all_variables : {&quot;0!69176db85a0651e7a8d8a16426bd93df!20110107-betesuguto&quot;=&gt;{}}
  #    errors : 0

p engine.process(wfid).position
  # =&gt;
  # [
  #   [ &quot;0_0_0!3b19bdf68a953597969bac507229bcf1!20110107-betesuguto&quot;,
  #     &quot;production&quot;,
  #     {} ] ]
</pre>
<p>(full gist at <a href="https://gist.github.com/769362">https://gist.github.com/769362</a>)</p>
<p>What if the &#8220;state&#8221;, business-wise, has a different granularity than the simple one we derive from the participants ? Something more like a &#8220;stage&#8221;.</p>
<p>The <strong>&#8220;tag&#8221; attribute</strong> could help :</p>
<pre class="brush: ruby; title: ; notranslate">
Ruote.process_definition do
  cursor do
    sequence :tag =&gt; 'production-stage' do
      production
      concurrence do
        qa1
        qa2
      end
    end
    rewind :unless =&gt; '${qa_ok}'
    sequence :tag =&gt; 'delivery-stage' do
      packaging
      delivery
    end
  end
end
</pre>
<p>Our process [instance] can be in &#8220;production-stage&#8221; or &#8220;delivery-stage&#8221; (or nowhere).</p>
<p>We can then ask for the tags of a process status :</p>
<pre class="brush: ruby; title: ; notranslate">
p engine.process(wfid).tags
  # =&gt;
  #  { &quot;production-stage&quot; =&gt; {
  #      &quot;engine_id&quot; =&gt; &quot;engine&quot;,
  #      &quot;wfid&quot; =&gt; &quot;20110107-hopakeze&quot;,
  #      &quot;subid&quot; =&gt; &quot;0f62bbb3a0a19411aaef1524ebde657c&quot;,
  #      &quot;expid&quot; =&gt; &quot;0_0_0&quot; } }
</pre>
<p>(full gist at <a href="https://gist.github.com/769371">https://gist.github.com/769371</a>)</p>
<p>Tags were originally meant to be used in conjunction with the <a href="http://ruote.rubyforge.org/exp/undo.html">undo/cancel</a> and the <a href="http://ruote.rubyforge.org/exp/redo.html">redo</a> expressions.</p>
<p>They later were used within <a href="http://ruote.rubyforge.org/exp/cursor.html">cursor</a>s for jumps (along with participant names) and when &#8220;piloting&#8221; a cursor from outside.</p>
<p>Asking the engine about the &#8216;process state&#8217; / &#8216;stage&#8217; is fine, but what if a [remote] participant wants to know about the stage is in ?</p>
<p>Let&#8217;s add a &#8216;qa_stage&#8217; tag.</p>
<pre class="brush: ruby; title: ; notranslate">
Ruote.define do
  cursor do
    sequence :tag =&gt; 'production-stage' do
      production
      concurrence :tag =&gt; 'qa_stage' do
        qa1
        qa2
      end
    end
    rewind :unless =&gt; '${qa_ok}'
    sequence :tag =&gt; 'delivery-stage' do
      packaging
      delivery
    end
  end
end
</pre>
<p>The upcoming <strong>ruote 2.1.12</strong> adds a #tags method to its workitems (a shortcut for workitem.fields['__tags__']).</p>
<p>With a participant implementation that looks like</p>
<pre class="brush: ruby; title: ; notranslate">
class MyParticipant
  include Ruote::LocalParticipant

  def consume(workitem)
    p [ workitem.participant_name, :tags, workitem.tags ]
    workitem.fields['qa_ok'] = true
    reply_to_engine(workitem)
  end
end
</pre>
<p>a run of our process will output</p>
<pre class="brush: jscript; title: ; notranslate">
[&quot;production&quot;, :tags, [&quot;production-stage&quot;]]
[&quot;qa1&quot;, :tags, [&quot;production-stage&quot;, &quot;qa_stage&quot;]]
[&quot;qa2&quot;, :tags, [&quot;production-stage&quot;, &quot;qa_stage&quot;]]
[&quot;packaging&quot;, :tags, [&quot;delivery-stage&quot;]]
[&quot;delivery&quot;, :tags, [&quot;delivery-stage&quot;]]
</pre>
<p>(full gist at <a href="https://gist.github.com/769406">https://gist.github.com/769406</a>)</p>
<p>There is a difference between asking the engine for the tags of a process intance and the list of tags returned by workitem#tags. The former returns all the tags currently active for the process instance, while the latter returns the list of tags that were traversed to reach the participant expression that emitted the workitem.</p>
<p>Another novelty brought in by ruote 2.1.12 is the possibility to listen to tag events (entering and leaving tags).</p>
<p>Until now, the <a href="http://ruote.rubyforge.org/exp/listen.html">http://ruote.rubyforge.org/exp/listen.html</a> expression could only listen to participants (workitems reaching and returning from participants). The upcoming ruote 2.1.12 lets us listen to process instances entering and leaving tags.</p>
<p>For example, we could have a monitoring process that listen to process instances entering the &#8216;final-stage&#8217; tag. Each time it happens, the participant &#8216;supervisor&#8217; receives a copy of the workitem :</p>
<pre class="brush: ruby; title: ; notranslate">
Ruote.process_definition do
  listen :to =&gt; 'final-stage', :upon =&gt; 'entering' do
    participant 'supervisor'
  end
end
</pre>
<p>By setting the :wfid attribute of the listen expression to true, we can limit the listening to the process instance to which the listen expression belongs.</p>
<p>It can be useful to approximate the <a href="http://ruote.rubyforge.org/patterns.html#sa_milestone">&#8216;milestone&#8217; workflow pattern</a> :</p>
<pre class="brush: ruby; title: ; notranslate">
Ruote.define do

  concurrence :count =&gt; 1 do
    # will terminate as soon as 1 branch replies (and cancel the other)

    sequence do
      participant 'a'
      participant 'b', :tag =&gt; 'milestone'
      participant 'c'
    end

    listen :to =&gt; 'milestone', :upon =&gt; 'entering', :wfid =&gt; true do

      concurrence :count =&gt; 1 do
        # will terminate as soon as 1 branch replies (and cancel the other)

        listen :to =&gt; 'milestone', :upon =&gt; 'leaving', :wfid =&gt; true
          # as soon as the tag 'milestone' is left, this listen will
          # exit (reply to the parent concurrence) and d will get cancelled

        participant 'd'
      end
    end
  end
end
</pre>
<p>The participant &#8216;d&#8217; will only receive a workitem when the milestone is reached. As soon as the milestone is left, the workitem of participant &#8216;d&#8217; is cancelled (removed from him).</p>
<p>Note how this implementation relies on &#8220;concurrence :count =&gt; 1&#8243;, a concurrence that exits as soon as 1 of its branches replies (and cancels the remaining branches).</p>
<p>In <strong>conclusion</strong>, tags have multiple uses, designating process state / stages, letting undo / redo segments of processes. The next ruote (2.1.12) adds tag information in workitems and lets the listen expression observe tag events (entering or leaving a tag).</p>
<p>&nbsp;</p>
<p>* web : <a href="http://ruote.rubyforge.org">http://ruote.rubyforge.org</a><br />
* source : <a href="http://github.com/jmettraux">http://github.com/jmettraux</a><br />
* mailing list : <a href="http://groups.google.com/group/openwferu-users">http://groups.google.com/group/openwferu-users</a><br />
* irc : freenode.net #ruote</p>
<p>&nbsp;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jmettraux.wordpress.com/2221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jmettraux.wordpress.com/2221/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2221&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jmettraux.wordpress.com/2011/01/07/ruote-and-tags/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/8d96626e52beb1ff90f57a8e189e1e6f?s=96&#38;d=&#38;r=G" medium="image">
			<media:title type="html">jmettraux</media:title>
		</media:content>
	</item>
		<item>
		<title>ruote and switch</title>
		<link>http://jmettraux.wordpress.com/2011/01/03/ruote-and-switch/</link>
		<comments>http://jmettraux.wordpress.com/2011/01/03/ruote-and-switch/#comments</comments>
		<pubDate>Mon, 03 Jan 2011 07:08:38 +0000</pubDate>
		<dc:creator>John Mettraux</dc:creator>
				<category><![CDATA[bpm]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruote]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://jmettraux.wordpress.com/?p=2177</guid>
		<description><![CDATA[A programming language usually has some kind of super &#8220;if&#8221;, a switch statement. Ruote is nothing more that an interpreter, a very patient one, one that can get stopped and restarted. (it also runs multiple process instances concurrently). Since it interprets some kind of high level business process gibberish, a switch statement is nice to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2177&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>A programming language usually has some kind of super &#8220;if&#8221;, a <a href="http://en.wikipedia.org/wiki/Switch_statement">switch statement</a>.</p>
<p><a href="http://ruote.rubyforge.org">Ruote</a> is nothing more that an interpreter, a very patient one, one that can get stopped and restarted. (it also runs multiple process instances concurrently). Since it interprets some kind of high level business process gibberish, a switch statement is nice to have.</p>
<p>This post explores switch statement implementations for ruote, it starts with solutions for ruote 2.1.x and then shows solutions that use two new expressions in the upcoming ruote 2.1.12.</p>
<p>&nbsp;</p>
<p><strong>before ruote 2.1.12</strong></p>
<p>For ruote [2.1], I wasn&#8217;t sure if a switch statement was explicitely needed. With a workitem field or a process variable, it&#8217;s easy to switch to a given subprocess.</p>
<p>Suppose we have an item pickup process. The system is onboard, the drivers leaves the depot knowing his immediate pickup point, but not the next, as the system asks after each pickup what to do (via the &#8216;get_next_task&#8217; subprocess).</p>
<pre class="brush: ruby; title: ; notranslate">
Ruote.process_definition do

  define 'coast_pickup' do
    # ...
  end
  define 'mountain_pickup' do
    # ...
  end
  define 'get_back_to_depot' do
    # ...
  end

  sequence do # body of the process

    cursor do
      subprocess 'get_next_task'
      subprocess '${next_task}'
      rewind :unless =&gt; '${next_task} == get_back_to_depot'
        # cursor rewinds unless next task is getting back to depot
    end
  end
end
</pre>
<p>All is well, our switch occurs at &#8220;subprocess &#8216;${next_task}&#8217;&#8221;. Note that if we wished to, we could use <a href="http://ruote.rubyforge.org/exp/ref.html">ref</a> instead of <a href="http://ruote.rubyforge.org/exp/subprocess.html">subprocess</a> if we wanted to point to participants and/or subprocesses.</p>
<p>But wait&#8230; Those subprocesses are defined for the whole process, they are not limited to the switch.</p>
<p>We can go a bit further and isolate the switch and its cases into its own subprocess.</p>
<pre class="brush: ruby; title: ; notranslate">
Ruote.process_definition do

  define 'perform_next_task' do

    define 'coast_pickup' do
      # ...
    end
    define 'mountain_pickup' do
      # ...
    end
    define 'get_back_to_depot' do
      # ...
    end

    subprocess '${next_task}'
  end

  sequence do # body of the process

    cursor do
      subprocess 'check_tasks'
      subprocess 'perform_next_task'
      rewind :unless =&gt; '${next_task} == get_back_to_depot'
    end
  end
end
</pre>
<p>This is nice, we have a &#8216;perform_next_task&#8217; subprocess wrapping the cases, the body of that subprocess calls the right case given the value of the &#8220;next_task&#8221; workitem field. If there is another subprocess named &#8216;mountain_pickup&#8217; in the same process definition, the one in the switch subprocess will only shadow it within the case, in other words, the scope of the cases is limited to the switch subprocess.</p>
<p>But, you&#8217;ll say, with a real programming language not some toy process definition language, the switch and its cases are all wrapped neatly inline, they are not set apart.</p>
<p>Placing the switch and its cases in the main flow is OK, but it binds subprocesses&#8230; It can override subprocesses with the same name.</p>
<pre class="brush: ruby; title: ; notranslate">
    cursor do
      subprocess 'check_tasks'
      sequence do
        define 'coast_pickup' do
          # ...
        end
        define 'mountain_pickup' do
          # ...
        end
        define 'get_back_to_depot' do
          # ...
        end
        subprocess '${next_task}'
      end
      rewind :unless =&gt; '${next_task} == get_back_to_depot'
    end
</pre>
<p>We need to look at the next version of ruote to solve that issue.</p>
<p>&nbsp;</p>
<p><strong>with ruote 2.1.12</strong></p>
<p>For the upcoming ruote 2.1.12, I introduced a <a href="http://ruote.rubyforge.org/exp/let.html">let expression</a> :</p>
<pre class="brush: ruby; title: ; notranslate">
    cursor do
      subprocess 'check_tasks'
      let do # let's have a new scope, just for our cases
        define 'coast_pickup' do
          # ...
        end
        define 'mountain_pickup' do
          # ...
        end
        define 'get_back_to_depot' do
          # ...
        end
        subprocess '${next_task}'
      end
      rewind :unless =&gt; '${next_task} == get_back_to_depot'
    end
</pre>
<p>The &#8216;let&#8217; introduces a new scope, where our case subprocesses can get defined without overrides ones with the same name outside of the let block.</p>
<p>Now, how about something that really looks like a switch statement ?</p>
<pre class="brush: ruby; title: ; notranslate">
    cursor do
      subprocess 'check_tasks'
      given '${next_task}' do
        of 'coast_pickup' do
          # ...
        end
        of 'mountain_pickup' do
          # ...
        end
        of 'get_back_to_depot' do
          # ...
        end
      end
      rewind :unless =&gt; '${next_task} == get_back_to_depot'
    end
</pre>
<p>With some Ruby/Perl -like magic, all the pickups could get covered by the same case :</p>
<pre class="brush: ruby; title: ; notranslate">
    cursor do
      subprocess 'check_tasks'
      given '${next_task}' do
        of /^.+_pickup$/ do
          # ...
        end
        of 'get_back_to_depot' do
          # ...
        end
      end
      rewind :unless =&gt; '${next_task} == get_back_to_depot'
    end
</pre>
<p>The upcoming ruote 2.1.12 has this <a href="http://ruote.rubyforge.org/exp/given.html">given expression</a>. Look at its description, it not only covers &#8220;given an x of&#8221; scenarii but also &#8220;given that&#8221; ones.</p>
<p>&nbsp;</p>
<p><strong>conclusion</strong></p>
<p>I still like the first version, it&#8217;s vanilla ruote &#8220;trigger the subprocess whose name is found in workitem field x&#8221;, it&#8217;s nice to have subprocesses that can be used as cases or called from other parts of the process definition.</p>
<p>Calling subprocesses doesn&#8217;t limit us to processes bound within the same process, processes bound at the engine level (engine variables) or external processes (given by their URI) are callable as well (see the <a href="http://ruote.rubyforge.org/exp/subprocess.html">subprocess expression</a> doc for more information).</p>
<p>The given expression is interesting because it covers &#8220;given an x of&#8221; and &#8220;given that&#8221; scenarii (see the <a href="http://ruote.rubyforge.org/exp/given.html">doc</a>). It also has a &#8220;default&#8221; part which the first version doesn&#8217;t have.</p>
<p>Try to write processes that are concise and that read like english. And <a href="https://github.com/jmettraux/ruote/blob/28c5de96e5084406cb1ed57a15acec40f266870f/examples/pickup.rb">test them</a>.</p>
<p>&nbsp;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jmettraux.wordpress.com/2177/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jmettraux.wordpress.com/2177/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2177&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jmettraux.wordpress.com/2011/01/03/ruote-and-switch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/8d96626e52beb1ff90f57a8e189e1e6f?s=96&#38;d=&#38;r=G" medium="image">
			<media:title type="html">jmettraux</media:title>
		</media:content>
	</item>
		<item>
		<title>rufus-jig 1.0</title>
		<link>http://jmettraux.wordpress.com/2010/12/08/rufus-jig-1-0/</link>
		<comments>http://jmettraux.wordpress.com/2010/12/08/rufus-jig-1-0/#comments</comments>
		<pubDate>Wed, 08 Dec 2010 06:28:56 +0000</pubDate>
		<dc:creator>John Mettraux</dc:creator>
				<category><![CDATA[couchdb]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[rufus]]></category>

		<guid isPermaLink="false">http://jmettraux.wordpress.com/?p=2154</guid>
		<description><![CDATA[By the end of 2007 I had written a gem sitting on top of net/http. It was called rufus-verbs, this extra layer added a mini cache for conditional GETs, basic auth and digest auth, cookie jar and more. I used it for a while, I got surprised by people using it (IIRC the digest auth [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2154&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>By the end of 2007 I had written a gem sitting on top of net/http. It was called <a href="https://github.com/jmettraux/rufus-verbs">rufus-verbs</a>, this extra layer added a mini cache for conditional GETs, basic auth and digest auth, cookie jar and more.</p>
<p>I used it for a while, I got surprised by people using it (IIRC the digest auth was their reason for using it). And then I forgot it.</p>
<p>Since last year, I am working with things like <a href="http://couchdb.apache.org/">CouchDB</a> and <a href="https://github.com/tosch/ruote-kit">ruote-kit</a>. I need an HTTP client that groks JSON. I still need it to understand conditional GETs (etags and co).</p>
<p>So I built <a href="https://github.com/jmettraux/rufus-jig">rufus-jig</a>, something on top of Ruby&#8217;s <a href="http://ruby-doc.org/core/classes/Net/HTTP.html">net/http</a>, <a href="http://seattlerb.rubyforge.org/net-http-persistent/">net-http-persistent</a>, <a href="https://github.com/toland/patron">patron</a> or <a href="https://github.com/igrigorik/em-http-request">em-http-request</a>. It uses <a href="https://github.com/jmettraux/rufus-json">rufus-json</a> to select the best JSON library available (in the order <a href="https://github.com/brianmario/yajl-ruby/">yajl-ruby</a>, <a href="http://flori.github.com/json/doc/index.html">json</a>, activesupport, json-pure).</p>
<p>A GET would look like :</p>
<pre class="brush: ruby; title: ; notranslate">
require 'rubygems'

#require 'net/http/persistent'
  # http backend

require 'yajl' # gem install 'yajl-ruby'
  # json backend

require 'rufus/jig'

h = Rufus::Jig::Http.new('http://twitter.com')

p h.get('/users/jmettraux.json')['description']
  # =&gt; &quot;another fool&quot;
</pre>
<p>You specify the HTTP and the JSON backend before requiring rufus-jig and that&#8217;s it.</p>
<p>Rufus-jig comes with a class to deal with some of CouchDB specifics.</p>
<pre class="brush: ruby; title: ; notranslate">

require 'net/http/persistent'
require 'yajl'
require 'rufus/jig'

c = Rufus::Jig::Couch.new('http://127.0.0.1:5984', 'rufus_jig_test')

# PUT and GET

c.put('_id' =&gt; 'coffee0', 'category' =&gt; 'espresso')
c.put('_id' =&gt; 'coffee1', 'category' =&gt; 'instantaneous')

coffee1 = c.get('coffee1')
coffee1['brand'] = 'nescafe'
c.put(coffee1)

# attaching

coffee0 = c.get('coffee0')

c.attach(coffee0, 'picture', File.read('espresso.jpg'), :content_type =&gt; 'image/jpeg')

# fetching all docs

p c.all
p c.all(:skip =&gt; 100, :limit =&gt; 100)

# fetching a batch of docs

p c.all(:keys =&gt; %w[ coffee0 coffee2 coffee7 ])

# querying views

p c.query('my_design_doc:my_view', :key =&gt; 'Costa Rica')
p c.query_for_docs('my_design_doc:my_view', :key =&gt; 'Colombia')

# bulk operations

docs = c.all(:keys =&gt; %w[ doc0 doc1 doc3 ])
c.bulk_delete(docs) # deleting in one go

docs = c.all(:keys =&gt; %w[ doc0 doc1 doc3 ])
docs.each { |doc| doc['status'] = 'copied' }
c.bulk_put(docs) # updating in one go

# ...

# listening to CouchDB activity

c.on_change do |doc_id, deleted|
  puts &quot;doc #{doc_id} has been #{deleted ? 'deleted' : 'changed'}&quot;
end

c.on_change do |doc_id, deleted, doc|
  puts &quot;doc #{doc_id} has been #{deleted ? 'deleted' : 'changed'}&quot;
  p doc
end
</pre>
<p>&nbsp;</p>
<p>Rufus-jig just reached 1.0. I&#8217;ll probably go on with extending it. It&#8217;ll probably need digest authentication at some point, gzipping, why not. I&#8217;ll leave the CouchDB function in it for now. We&#8217;ll see.</p>
<p>&nbsp;</p>
<p>source code : <a href="https://github.com/jmettraux/rufus-jig">https://github.com/jmettraux/rufus-jig</a></p>
<p>&nbsp;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jmettraux.wordpress.com/2154/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jmettraux.wordpress.com/2154/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2154&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jmettraux.wordpress.com/2010/12/08/rufus-jig-1-0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/8d96626e52beb1ff90f57a8e189e1e6f?s=96&#38;d=&#38;r=G" medium="image">
			<media:title type="html">jmettraux</media:title>
		</media:content>
	</item>
		<item>
		<title>resource lifecycle tuple</title>
		<link>http://jmettraux.wordpress.com/2010/10/27/resource-lifecycle-tuple/</link>
		<comments>http://jmettraux.wordpress.com/2010/10/27/resource-lifecycle-tuple/#comments</comments>
		<pubDate>Wed, 27 Oct 2010 05:24:27 +0000</pubDate>
		<dc:creator>John Mettraux</dc:creator>
				<category><![CDATA[bpms]]></category>
		<category><![CDATA[state machine]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://jmettraux.wordpress.com/?p=2136</guid>
		<description><![CDATA[I came across this passage : Moving from design to implementation, we need to think about the protocol in a slightly different way. In a resource-oriented distributed application, an application protocol can be thought of as a function of one or more resource life cycles and the business rules that connect these resources. Because of [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2136&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>I came across this passage :</p>
<blockquote><p>Moving from design to implementation, we need to think about the protocol in a slightly different way. In a resource-oriented distributed application, <strong>an application protocol can be thought of as a function of one or more resource life cycles and the business rules that connect these resources</strong>. Because of its resource-centric nature, the Restbucks service does not host an application protocol state machine. In other words, there’s no workflow or business logic for the application protocol as such. Rather, the service governs the life cycles of the orders and payments participating in the application protocol. Any workflows in the service implementation relate to resource life cycles, not the application protocol life cycle. While we’ve been explicit in modeling the business process as an application protocol state machine, we’ve been diligent in implementing it wholly in terms of resource state machines.</p></blockquote>
<p><a href="http://oreilly.com/catalog/9780596805838/">REST in practice</a>, page 131, (emphasis mine).</p>
<p>&nbsp;</p>
<p>I had to link that passage to this blog post :</p>
<blockquote><p>The bottom line is that a business entity lifecycle represents some business logic that is &#8220;business process independent&#8221;. This is probably news to many of you and some of you might say that a BEL is a &#8220;long running process&#8221; but it is not. It is long running. It is a process in the sense of an operating system point of view (nearly), but it is not and will never be a &#8220;business process&#8221;. The business process is represented by the activities (human or automated) that advance the lifecycle of one or more business entities.</p></blockquote>
<p><a href="http://www.ebpml.org/blog2/index.php/2010/09/14/soa-bpm-rest-lifecycle-example">Lifecycle example</a>, from <a href="http://www.ebpml.org/blog2/index.php">Carnets de Bord</a></p>
<p>&nbsp;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jmettraux.wordpress.com/2136/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jmettraux.wordpress.com/2136/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2136&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jmettraux.wordpress.com/2010/10/27/resource-lifecycle-tuple/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/8d96626e52beb1ff90f57a8e189e1e6f?s=96&#38;d=&#38;r=G" medium="image">
			<media:title type="html">jmettraux</media:title>
		</media:content>
	</item>
		<item>
		<title>volute</title>
		<link>http://jmettraux.wordpress.com/2010/10/12/volute/</link>
		<comments>http://jmettraux.wordpress.com/2010/10/12/volute/#comments</comments>
		<pubDate>Tue, 12 Oct 2010 07:28:54 +0000</pubDate>
		<dc:creator>John Mettraux</dc:creator>
				<category><![CDATA[decision]]></category>
		<category><![CDATA[dsl]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[rules]]></category>
		<category><![CDATA[state machine]]></category>

		<guid isPermaLink="false">http://jmettraux.wordpress.com/?p=2091</guid>
		<description><![CDATA[Vos luttes partent en fumée Vers des flûtes enchantées Et de cruelles espérances Me lancent Des dagues et des lances En toute innocence J&#8217;cloue des clous sur des nuages Un marteau au fond du garage J&#8217;cloue des clous sur des nuages Sans échafaudage volutes Alain Bashung (funny auto-translation) &#160; This started out in a notebook. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2091&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<blockquote><p>Vos luttes partent en fumée<br />
Vers des flûtes enchantées  Et de cruelles espérances<br />
Me lancent  Des dagues et des lances  En toute innocence</p>
<p>J&#8217;cloue des clous sur des nuages  Un marteau au fond du garage<br />
J&#8217;cloue des clous sur des nuages  Sans échafaudage</p></blockquote>
<p><a href="http://www.youtube.com/watch?v=qwtEEzh-zok">volutes</a> Alain Bashung (<a href="http://translate.google.com/#auto|en|%20%20%20%20Vos%20luttes%20partent%20en%20fum%C3%A9e%0A%20%20%20%20Vers%20des%20fl%C3%BBtes%20enchant%C3%A9es%0A%20%20%20%20Et%20de%20cruelles%20esp%C3%A9rances%0A%20%20%20%20Me%20lancent%0A%20%20%20%20Des%20dagues%20et%20des%20lances%0A%20%20%20%20En%20toute%20innocence%0A%0A%20%20%20%20Je%20cloue%20des%20clous%20sur%20des%20nuages%0A%20%20%20%20Un%20marteau%20au%20fond%20du%20garage%0A%20%20%20%20Je%20cloue%20des%20clous%20sur%20des%20nuages%0A%20%20%20%20Sans%20%C3%A9chafaudage">funny auto-translation</a>)</p>
<p>&nbsp;</p>
<p>This started out in a notebook. I wanted to do something about &#8216;state&#8217; and &#8216;lifecyle&#8217;, something like a state machine for multiple objects or a rule system for families of resources.</p>
<p>It ended up as something that feels like the subset of an aspect oriented framework. Subset because in its most vanilla usage it only cares about calls to set methods, and there is no &#8220;before&#8221; (at first glance).</p>
<p>This Ruby gem is named <a href="http://github.com/jmettraux/volute">volute</a>. Here is an example of its usage :</p>
<pre class="brush: ruby; title: ; notranslate">
require 'volute'

class Package
  include Volute

  attr_accessor :location
  attr_accessor :delivered
end

volute Package do
  # filters non Package instance out

  volute :delivered =&gt; true do
    # applies when delivered switches to true
    object.emit_invoice
  end

  volute :location do
    # filters out changes that are not for the :location attribute

    volute 'SFO' =&gt; :any, 'FRA' =&gt; :any do
      # SFO and FRA are our international hubs, for any package transiting from there,
      # initial 'international' tracking
      TrackingSystem.track_international(object)
    end
  end
end
</pre>
<p>The &#8220;include Volute&#8221; reworks the attr_accessor, and triggers the evaluation of the volutes on each set.</p>
<p>It&#8217;s not always necessary to include Volute. Here is a example of [business] rules derived from <a href="http://github.com/codeaspects/ruleby">Ruleby</a> (volute is very dumb compared to Ruleby, the <a href="http://github.com/codeaspects/ruleby/blob/master/examples/diagnosis.rb">example</a> doesn&#8217;t do justice to that project).</p>
<p>Here is the <a href="http://github.com/jmettraux/volute/blob/master/examples/diagnosis.rb">diagnosis example</a> with volute :</p>
<pre class="brush: ruby; title: ; notranslate">
require 'volute'

class Patient

  attr_reader :name
  attr_accessor :fever
  attr_accessor :rash
  attr_accessor :spots
  attr_accessor :sore_throat
  attr_accessor :innoculated

  attr_accessor :diagnosis

  def initialize(name)
    @name = name
    @symptoms = {}
    @innoculated = false
  end

  def diagnose!
    Volute.apply(self) # trigger evalution of volutes
    return @diagnosis
  end
end

volute Patient do

  volute :fever =&gt; :high, :spots =&gt; :true, :innoculated =&gt; true do
    object.diagnosis = 'measles'
    over # prevent further evals
  end
  volute :spots =&gt; true do
    object.diagnosis = 'allergy (spots but no measles)'
  end
  volute :rash =&gt; true do
    object.diagnosis = 'allergy (rash)'
  end
  volute :sore_throat =&gt; true, :fever =&gt; :mild do
    object.diagnosis = 'flu'
  end
  volute :sore_throat =&gt; true, :fever =&gt; :high do
    object.diagnosis = 'flu'
  end
end

pat = Patient.new('alice')
pat.rash = true

puts &quot;#{pat.name} : diagnosed with #{pat.diagnose!}&quot;

pat = Patient.new('bob')
pat.sore_throat = true
pat.fever = :high

puts &quot;#{pat.name} : diagnosed with #{pat.diagnose!}&quot;
</pre>
<p>&nbsp;</p>
<p>The <a href="http://github.com/jmettraux/volute">readme for volute</a> is quite extensive. There are <a href="http://github.com/jmettraux/volute/tree/master/examples/">a few examples</a> included.</p>
<p>You&#8217;ve already seen the <a href="http://github.com/jmettraux/volute/blob/master/examples/diagnosis.rb">diagnosis</a> one, it aimed at using volute for some mini rule engine (nothing fancy at all).</p>
<p>There is an example about a simple (kph = km/h) <a href="http://github.com/jmettraux/volute/blob/master/examples/equation.rb">equation</a> where each time an attribute is changed, other attributes get adjusted.</p>
<p>The <a href="http://github.com/jmettraux/volute/blob/master/examples/light.rb">light</a> example simply keeps tracks of the last time an attribute got modified.</p>
<p>There is a book in a bookshop <a href="http://github.com/jmettraux/volute/blob/master/examples/state_machine.rb">state machine</a> example with a <a href="http://github.com/jmettraux/volute/blob/master/examples/state_machine_2.rb">variation</a>, to explore state volutes and transition volutes.</p>
<p>Note that state machines built with volute are incomplete, they know nothing about further transitions (could I even call them state machines ? Rather a &#8216;state transition system&#8217;).</p>
<p><a href="http://github.com/jmettraux/volute/blob/master/examples/traffic.rb">Traffic</a> could be fun : it tracks the state of two &#8220;lines&#8221; and adjust the colour of their lights according to the number of cars waiting. It&#8217;s more in line with the &#8220;multiple objects&#8221; goal I had initially (still here somehow, but examples with 1 class are smaller).</p>
<p>Not sure if it&#8217;s worth moving logic out of objects, but it is a fun experiment.</p>
<p>&nbsp;</p>
<p><a href="http://github.com/jmettraux/volute">http://github.com/jmettraux/volute</a></p>
<p>&nbsp;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jmettraux.wordpress.com/2091/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jmettraux.wordpress.com/2091/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2091&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jmettraux.wordpress.com/2010/10/12/volute/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/8d96626e52beb1ff90f57a8e189e1e6f?s=96&#38;d=&#38;r=G" medium="image">
			<media:title type="html">jmettraux</media:title>
		</media:content>
	</item>
		<item>
		<title>ruote 2.1.11 released</title>
		<link>http://jmettraux.wordpress.com/2010/10/05/ruote-2-1-11-released/</link>
		<comments>http://jmettraux.wordpress.com/2010/10/05/ruote-2-1-11-released/#comments</comments>
		<pubDate>Tue, 05 Oct 2010 06:07:16 +0000</pubDate>
		<dc:creator>John Mettraux</dc:creator>
				<category><![CDATA[opensource]]></category>
		<category><![CDATA[openwferu]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruote]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://jmettraux.wordpress.com/?p=2020</guid>
		<description><![CDATA[ruote is an open source workflow engine implemented in Ruby. It takes as input process definitions and interprets them. It routes work among participants according to the flow described in those process definitions. It can orchestrate ping pong matches as well. The main motivation behind this release is Torsten being tired of advising people to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2020&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p><a href="http://ruote.rubyforge.org">ruote</a> is an open source workflow engine implemented in Ruby.</p>
<p>It takes as input process definitions and interprets them. It routes work among participants according to the flow described in those process definitions. It can orchestrate <a href="http://jmettraux.wordpress.com/2010/09/27/amqp-ruote-pong/">ping pong</a> matches as well.</p>
<p>The main motivation behind this release is <a href="http://github.com/tosch">Torsten</a> being tired of advising people to use ruote edge (thanks Bundler) for their ruote-kit installs, ruote was more than ripe for a new release. This version includes the result of the feedback of numerous people, as the <a href="http://github.com/jmettraux/ruote/blob/ruote2.1/CHANGELOG.txt">changelog</a> can attest.</p>
<p>I&#8217;ll address here two aspects, one in ruote itself, and one on its periphery.</p>
<p><strong>participant in a workflow</strong></p>
<p>Up until now, participants were registered one by one (order of registration matters).</p>
<pre class="brush: ruby; title: ; notranslate">
engine.register_participant 'reception', Acme::ReceptionParticipant
engine.register_participant 'support', Acme::SupportParticipant
engine.register_participant '.+', Ruote::StorageParticipant
</pre>
<p>Torsten came up with an idiomatic solution in ruote-kit, that was soon promoted to ruote itself :</p>
<pre class="brush: ruby; title: ; notranslate">
engine.register do
  reception Acme::ReceptionParticipant
  support Acme::SupportParticipant
  catchall
end
</pre>
<p>All is well in a vanilla world were participants are all known at system startup. People were asking about adding participants on-the-fly. Ruote has always been able to do that :</p>
<pre class="brush: ruby; title: ; notranslate">
engine.register_participant 'reception2', Acme::ReceptionParticipant, :site =&gt; 'two'
</pre>
<p>but our reception2 gets registered after the catchall participant, and thus might never receive any workitems. A solution would be to place the participant as second to last :</p>
<pre class="brush: ruby; title: ; notranslate">
engine.register_participant(
  'reception2', Acme::ReceptionParticipant, :site =&gt; 'two', :position =&gt; -2)
</pre>
<p>But blindly inserting participants isn&#8217;t good. Ruote 2.1.11 has a new method for setting the participant list in a single batch :</p>
<pre class="brush: ruby; title: ; notranslate">
engine.participant_list = [
  [ '^reception$', 'Acme::ReceptionParticipant', {} ],
  [ '^reception2$', 'Acme::ReceptionParticipant', { 'site' =&gt; 'two' } ],
  [ '^support$', 'Acme::SupportParticipant', {} ],
  [ '^.+$', 'Ruote::StorageParticipant', {} ]
]
</pre>
<p>Very rough, but full control.</p>
<p><strong>ruote in kit</strong></p>
<p><a href="http://github.com/tosch/ruote-kit">ruote-kit</a> was kind of left behind at version 2.1.8. Torsten and I resumed its development and brought it to 2.1.11.</p>
<p>Ruote-kit is a web administration console for ruote. <a href="http://opensourcery.co.za">Kenneth Kalmer&#8217;s</a> genius idea was to make it a rack middleware (component), so that it works standalone or fits nicely in a rails application, under /_ruote/</p>
<p><a href="http://jmettraux.files.wordpress.com/2010/10/processes.png"><img src="http://jmettraux.files.wordpress.com/2010/10/processes.png?w=150&#038;h=74" alt="list of processes" title="processes" width="150" height="74" class="alignleft size-thumbnail wp-image-2054" style="border:1px solid;" /></a><a href="http://jmettraux.files.wordpress.com/2010/10/error.png"><img src="http://jmettraux.files.wordpress.com/2010/10/error.png?w=150&#038;h=87" alt="view on a process error" title="error" width="150" height="87" class="alignleft size-thumbnail wp-image-2053" style="border:1px solid;" /></a><a href="http://jmettraux.files.wordpress.com/2010/10/participants.png"><img src="http://jmettraux.files.wordpress.com/2010/10/participants.png?w=150&#038;h=57" alt="list of participants" title="participants" width="150" height="57" class="alignleft size-thumbnail wp-image-2061" style="border:1px solid;" /></a><a href="http://jmettraux.files.wordpress.com/2010/10/workitem.png"><img src="http://jmettraux.files.wordpress.com/2010/10/workitem.png?w=150&#038;h=102" alt="view on a workitem" title="workitem" width="150" height="102" class="alignleft size-thumbnail wp-image-2055" style="border:1px solid;" /></a></p>
<p>Ruote-kit is more than a web administration console, it&#8217;s also an HTTP/JSON based interface to ruote, for example : <a href="http://gist.github.com/611044">http://gist.github.com/611044</a>. The entry point of the interface is /_ruote/ all the resources are linked to from this &#8220;root&#8221;. The links are annotated with &#8220;rel&#8221; attributes that indicate to clients what stands behind the link.</p>
<p>There is more to it, we&#8217;re working on conveying the capabilities of both interfaces HTML / JSON from the HTML (the one that is easily navigated by a human and his browser).</p>
<p><strong>storages got updates</strong></p>
<p><a href="http://github.com/jmettraux/ruote-dm">ruote-dm</a>, <a href="http://github.com/jmettraux/ruote-redis">ruote-redis</a>, <a href="http://github.com/jmettraux/ruote-couch">ruote-couch</a> have been upgraded to 2.1.11.</p>
<p>Note that there is a piece of documentation on <a href="http://ruote.rubyforge.org/implementing_a_storage.html">how to implement storages</a> that is in the works as it was requested by people who want to have a <a href="http://www.mongodb.org/">MongoDB</a> backend.</p>
<p><strong>next steps</strong></p>
<p>Still have to release an updated <a href="http://github.com/jmettraux/ruote-amqp">ruote-amqp</a>, and bring <a href="http://github.com/jmettraux/ruote-beanstalk">ruote-beanstalk</a> to 2.1.11. Then it will be time to think about 2.1.12. As said, there is still work to do on ruote-kit, and since it&#8217;s used by many ruote people, it deserves full attention.</p>
<p>Many thanks to Eric Platon, Nathan Stults, Asier, Hartog de Mik, Brett Anthoine, Eric Smith, Kaspar Schiess, David Greaves, Rich Meyers, Kenneth Kalmer, Don French and David Goodlad (and many others) for their contributions !</p>
<p>source : <a href="http://github.com/jmettraux/ruote">http://github.com/jmettraux/ruote</a><br />
mailing list : <a href="http://groups.google.com/group/openwferu-users">http://groups.google.com/group/openwferu-users</a><br />
doc : <a href="http://ruote.rubyforge.org">http://ruote.rubyforge.org</a><br />
irc : #ruote on freenode.net</p>
<p>&nbsp;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jmettraux.wordpress.com/2020/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jmettraux.wordpress.com/2020/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jmettraux.wordpress.com&#038;blog=120793&#038;post=2020&#038;subd=jmettraux&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jmettraux.wordpress.com/2010/10/05/ruote-2-1-11-released/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/8d96626e52beb1ff90f57a8e189e1e6f?s=96&#38;d=&#38;r=G" medium="image">
			<media:title type="html">jmettraux</media:title>
		</media:content>

		<media:content url="http://jmettraux.files.wordpress.com/2010/10/processes.png?w=150" medium="image">
			<media:title type="html">processes</media:title>
		</media:content>

		<media:content url="http://jmettraux.files.wordpress.com/2010/10/error.png?w=150" medium="image">
			<media:title type="html">error</media:title>
		</media:content>

		<media:content url="http://jmettraux.files.wordpress.com/2010/10/participants.png?w=150" medium="image">
			<media:title type="html">participants</media:title>
		</media:content>

		<media:content url="http://jmettraux.files.wordpress.com/2010/10/workitem.png?w=150" medium="image">
			<media:title type="html">workitem</media:title>
		</media:content>
	</item>
	</channel>
</rss>
