I am thoroughly enjoying your framework. I really like the way it is
designed, easy to use, easy to extend. Anyway, I have a quick question
regarding conditions. What is the recommended approach to and'ing and
or'ing expressions, like this (which doesn't seem to work)
_if :test=>'${f:consent_form_on_file} == yes && ${f:is_patient_eligible}
== yes' do
Looking at the implementation of Condition I can see why what I'm trying
to do isn't working, but I was wondering if there is some way? Is there
a way to provide an array of conditions and an operator, or should I try
to use nesting of flow expressions or something? I'm happy to use Ruby
eval as well, but in that case I'm not sure how to get hold of work item
variables. Can dollar syntax be used with ruby eval in expressions?
Thanks for your time,
Nathan
Hello,
many thanks !
> What is the recommended approach to and'ing and
> or'ing expressions, like this (which doesn't seem to work)
>
> _if :test=>'${f:consent_form_on_file} == yes && ${f:is_patient_eligible}
> == yes' do
>
> Looking at the implementation of Condition I can see why what I'm trying
> to do isn't working, but I was wondering if there is some way? Is there
> a way to provide an array of conditions and an operator, or should I try
> to use nesting of flow expressions or something? I'm happy to use Ruby
> eval as well, but in that case I'm not sure how to get hold of work item
> variables. Can dollar syntax be used with ruby eval in expressions?
OK, I will answer in variants :
== decision participants
I tend to use "decision participants" like in
---8<---
sequence do
decide
_if "${f:decided}" do
accept
reject
end
end
--->8---
Where the 'decision participant' might look like
---8<---
class DecisionOne
include Ruote::LocalParticipant
def consume(workitem)
workitem.fields['decided'] =
workitem.fields['is_patient_eligible'] &&
workitem.fields['consent_form_on_file'] == 'yes'
reply_to_engine(workitem)
end
end
# ...
engine.register_participant 'decide', DecisionOne
--->8---
This makes the process definition more readable and lets you change the decision logic independently from the business process.
That implies being able to hook more complex decisions (rule engine, decision tables, your own complex decision library) or simply, sometimes, when the decision is very very complex, switch from an automated participant to a human participant (our dear friend the "knowledge worker").
== ruby evaluation
You can write :
---8<---
_if "${r:wi.fields[consent_form_on_file] == 'yes' && wi.fields['is_patient_eligible']}"
--->8---
Within the ${r: } you're free to use ruby code (and to shoot yourself in the foot with it). There is a minimal sanity check ( http://github.com/jmettraux/ruote/blob/ruote2.1/lib/ruote/util/treechecker.rb ) but you have to have ruby evaluation allowed :
---8<---
engine.context['ruby_eval_allowed'] = true
--->8---
== hypothetical variant
Not a real variant : I have thought of things like
---8<---
sequence do
decide
_if do
_and do
test "${f:consent_form_on_file} == yes"
test "${f:is_patient_eligible}"
end
accept
reject
end
end
--->8---
but I never implemented it, preferring to guide people towards decision participants or the ${r: } notation.
I hope this will help, best regards,
--
John Mettraux - http://jmettraux.wordpress.com
Thanks again for the help.
> --
> you received this message because you are subscribed to the "ruote users" group.
> to post : send email to openwfe...@googlegroups.com
> to unsubscribe : send email to openwferu-use...@googlegroups.com
> more options : http://groups.google.com/group/openwferu-users?hl=en
Sorry, begin curious, which expression evaluator is this ?
> I come from .net and they are everywhere because there is no possibility of a
> language level "eval." But sometimes for expressing human readable business
> rules a simple sandboxed expression language really fits the bill. Maybe it
> is finally time to take Treetop for a spin.
I tend to use ruby directly to express business rules, with a bit of eval/metaprogramming/dslery sometimes.
Cheers,
_if "${r:consent_form_on_file == yes and is_patient_eligible}
Instead of
_if "${r:wi.fields['consent_form_on_file'] == 'yes' &&
wi.fields['is_patient_eligible'] }" do
With liberal use of method missing I can try to resolve unknown symbols
from fields, variables or domain specific constants, and turn the rest
into simple strings. I may very well be able to monkey patch this in,
which is fine, but I wonder if there is any value in having expression
evaluation in general be an official extensibility point, like parsing
and storage and things, or of there is already a natural way of
accomplishing this that I'm not seeing.
Thanks,
Nathan
Cheers,
--
Hello Nathan,
I have to say I like your ideas.
Do you mind if I lift them and integrate them into ruote ?
a) more concise ruby
> _if "${r:consent_form_on_file == yes and is_patient_eligible} do
this looks great and is easily doable, while keeping backward compatibility with the classical
> _if "${r:wi.fields['consent_form_on_file'] == 'yes' && wi.fields['is_patient_eligible'] }" do
b) ruby evaluation as an extensibility point
Makes sense as well, I will work on it as a foundation for a)
Many thanks,
Thanks again for the great project.
Nathan
-----Original Message-----
From: openwfe...@googlegroups.com
[mailto:openwfe...@googlegroups.com] On Behalf Of John Mettraux
Sent: Friday, September 03, 2010 6:13 PM
To: openwfe...@googlegroups.com
Subject: Re: [ruote:2586] Boolean operators and filters/conditions in
Ruote
Hello Nathan,
a) more concise ruby
Many thanks,
--
Hello Nathan,
thanks for the feedback and the advice, it helps make the project better.
Here are the changes I made; at first, I made a service out of the substitution code :
http://github.com/jmettraux/ruote/commit/9376e80f92bb1471f4540799a7cdf0283aa9099d
Then, I made sure the dictionary used for substitution and the ruby context in case of ${r:...} were available for exchange / monkey patching :
http://github.com/jmettraux/ruote/commit/6ddc16d233211dd02f1c8aa79edbe64cecb7af61
The last step was to allow for ${r:name_of_field} from the ruby context :
http://github.com/jmettraux/ruote/commit/6968d9aad58f5d6694617ee508cb679ec88e54b5
You can thus now write things like
participant 'sales_manager', :if => '${r: amount > 10_000 }'
Loose methods are mapped to workitem fields.
Now there is an issue, should a missing field/method result in a NoMethodError triggering a process error or should the method missing simply return nil ?
${r: (amount || 0) > 10_000 }
looks OK.
What do you think ?
Now back to extensibility : it's now easy to add methods visible to the ruby context by doing things like
class Ruote::Dollar::RubyContext
def amount
@workitem.fields['articles'].inject(0) { |i, a|
i + a['count'] * a['price']
}
end
end
All the work happens in :
http://github.com/jmettraux/ruote/blob/ruote2.1/lib/ruote/svc/dollar_sub.rb
Tell me if you have any question about other extensibility means.
Cheers,
Whatever the case, there is now nothing left in ruote that will prevent
us from making it fit our solution like a glove, so I'm very
appreciative of your work.
We'll be contributing a MongoDB storage service in the near future, so
we'll be sure to post a link when we do. What is your process when you
do a new storage back end? Do you have a common test suite you run to
verify the new storage mechanism, or do you write fresh tests for each
one?
Thanks again. This may be the most responsive open source project I've
encountered so far :)
Nathan
-----Original Message-----
From: openwfe...@googlegroups.com
[mailto:openwfe...@googlegroups.com] On Behalf Of John Mettraux
Sent: Sunday, September 05, 2010 5:50 PM
To: openwfe...@googlegroups.com
Subject: Re: [ruote:2588] Boolean operators and filters/conditions in
Ruote
Hello Nathan,
http://github.com/jmettraux/ruote/commit/9376e80f92bb1471f4540799a7cdf02
83aa9099d
http://github.com/jmettraux/ruote/commit/6ddc16d233211dd02f1c8aa79edbe64
cecb7af61
http://github.com/jmettraux/ruote/commit/6968d9aad58f5d6694617ee508cb679
ec88e54b5
looks OK.
http://github.com/jmettraux/ruote/blob/ruote2.1/lib/ruote/svc/dollar_sub
.rb
Cheers,
--
Hello Nathan,
I think I'm tempted to return nil, but I will give it more thinking. I know it's OK either way for you and I know you'll tell me if there anything wrong.
> We'll be contributing a MongoDB storage service in the near future, so
> we'll be sure to post a link when we do. What is your process when you
> do a new storage back end? Do you have a common test suite you run to
> verify the new storage mechanism, or do you write fresh tests for each
> one?
MongoDB ? Great ! There's so much buzz about it, I'd love someone to come up with a ruote storage for it.
I have to say that I'd love it to be maintained (at least initially) by you guys. I have to watch my workload.
That calls for a piece of documentation on what is expected from a storage and how to test it. Stay tuned for it.
Many thanks,
Hello,
I've started this piece of documentation at :
http://ruote.rubyforge.org/implementing_a_storage.html
In the coming days I will fill the blanks. Feel free to point at the blanks you want filled first and to point at inaccuracies and obscurities in the page.
Thanks in advance,