Get expression value from drools - drools

I want to get expression value from drools.The drl like this.
global java.util.Map $globalVar;
global java.lang.Object $result;
import java.util.Map;
function myFunc(Map map){
return "hello";
}
rule "onlyone"
when
$factMap: Map($tmpResult:(myFunc($globalVar)), eval(true))
then
$result = $tmpResult;
end
When the rule get exception,like this
Caused by: org.mvel2.PropertyAccessException: [unable to resolve method: java.util.Map.$globalVar() [argslength=0]]
The global variable $globarVar has no relation with the fact.
It is likely drools can't recognize the global variable.Is there any grammar error in my drl?

Your syntax is so wrong I can't even figure out what you're trying to do.
Functions are very simple, they're just like methods in Java. They even look like methods in Java -- yours is missing a return type.
function String myFunc(Map map) {
return "hello";
}
function String greeting(String name) {
return "Hello, " + name + ". How are you?"
}
You can invoke them in your rules as you would any other function, either on the left hand side ("when") or on the right hand side ("then").
rule "Apply Greeting and Send Memo"
when
$memo: Memo( $recipient: recipient, sent == false )
$greeting: String() from greeting($recipient)
then
MemoSender.send($greeting, $memo);
modify( $memo ) {
setSent(true)
};
end
rule "Apply Greeting and Send Memo - v2"
when
$memo: Memo( $recipient: recipient, sent == false )
then
String $greeting = greeting($recipient);
MemoSender.send( $greeting, $memo );
modify( $memo ) {
setSent(true)
}
end
The bits with the globals in your question are red herrings. Yes, they're not working and throwing errors, but the syntax is so wrong that I'm not sure how it was supposed to work in the first place.
One way you might interact with a global in a function would possibly be something like ...
global Float taxRate; // passed in as a global because it's an external constant value
global Float freeShippingThreshold;
function float calculateTotal(float subtotal) {
// some math here that references taxRate
return calculatedTotal
}
rule "Apply free shipping"
when
Cart( $subtotal: subtotal )
Float( this >= freeShippingThreshold) from calculateTotal($subtotal)
then
// you get free shipping
end

Related

Pre-compile textual replacement macro with arguments

I am trying to create some kind of a dut_error wrapper. Something that will take some arguments and construct them in a specific way to a dut_error.
I can't use a method to replace the calls to dut_error because to my understanding after check that ... then ... else can only come a dut_error (or dut_errorf). And indeed if I try to do something like:
my_dut_error(arg1: string, arg2: string) is {
dut_error("first argument is ", arg, " and second argument is ", arg2);
};
check that FALSE else my_dut_error("check1", "check2");
I get an error:
*** Error: Unrecognized exp
[Unrecognized expression 'FALSE else my_dut_error("check1", "check2")']
at line x in main.e
check that FALSE else my_dut_error("check1", "check2");
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
So I thought about defining a macro to simply do a textual replace from my wrapper to an actual dut_error:
define <my_dut_error'exp> "my_dut_error(<arg1'name>, <arg2'name>)" as {
dut_error("first argument is ", <arg1'name>, " and second argument is ", <arg2'name>)
};
But got the same error.
Then I read about the preprocessor directive #define so tried:
#define my_dut_error(arg1, arg2) dut_error("first argument is ", arg, " and second argument is ", arg2)
But that just gave a syntax error.
How can I define a pre-compiled textual replacement macro that takes arguments, similar to C?
The reason I want to do that is to achieve some sort of an "interface" to the dut_error so all errors have a consistent structure. This way, different people writing different errors will only pass the arguments necessary by that interface and internally an appropriate message will be created.
not sure i understood what you want to do in the wrapper, but perhaps you can achieve what you want by using the dut_error_struct.
it has set of api, which you can use as hooks (do something when the error is caught) and to query about the specific error.
for example:
extend dut_error_struct {
pre_error() is also {
if source_method_name() == "post_generate" and
source_struct() is a BLUE packet {
out("\nProblem in generation? ", source_location());
// do something for error during generation
};
write() is first {
if get_mesage() ~ "AHB Error..." {
ahb_monitor::increase_errors();
};
};
};
dut_error accepts one parameter, one string. but you can decide of a "separator", that will define two parts to the message.
e.g. - instruct people to write "XXX" in the message, before "first arg" and "second arg".
check that legal else dut_error("ONE thing", "XXX", "another thing");
check that x < 7 else dut_error("failure ", "XXX", "of x not 7 but is ", x);
extend dut_error_struct {
write() is first {
var message_parts := str_split(get_message(), "XXX");
if message_parts.size() == 2 {
out ("First part of message is ", message_parts[0],
"\nand second part of message is ", message_parts[1]
);
};
};
I could get pretty close to what I want using the dut_errorf method combined with a preprocessor directive defining the format string:
#define DUT_FORMAT "first argument is %s and second argument is %s"
check that FALSE else dut_errorf(DUT_FORMAT, "check1", "check2");
but I would still prefer a way that doesn't require this DUT_FORMAT directive and instead uses dut_error_struct or something similar.

Specify function return type

How do I specify the return type in a powershell function?
function getSomeString {
return "hello world"
}
$xyz = getSomeString() # <--- IDE does not recognize $xyz as a string
Before getting to the answer, I should point out that PowerShell commands do NOT have static return types!
In terms of I/O, commands in PowerShell are like little black boxes - you send 0 or more input objects in one end, and 0 or more outputs object are emitted at the other end - the type(s) of which may vary.
That being said, you can add a type inference hint to your function by adding an [OutputType] attribute decorator to the function's param block:
function Get-SomeString {
[OutputType([string])]
param()
return "hello world"
}
$xyz = Get-SomeString # Tools can now infer type of `$xyz`
Again, this is a hint, not a guarantee - you can lie if you want to:
function Get-Integers
{
[OutputType([int[]])]
param()
if((1..10 |Get-Random) -gt 7){
return "lol, I'll do what I want"
}
return 1,2,3
}
$f = Get-Integers
In this case, Get-Integers will return a [string] 30% of the time, but the IDE will always act like both $f and Get-Integers resolves to an array of [int]'s - because that's what we told it to expect.

How to indiciate a failure for a function with a void result

I have a function in scala which has no return-value (so unit). This function can sometimes fail (if the user provided parameters are not valid). If I were on java, I would simply throw an exception. But on scala (although the same thing is possible), it is suggested to not use exceptions.
I perfectly know how to use Option or Try, but they all only make sense if you have something valid to return.
For example, think of a (imaginary) addPrintJob(printJob: printJob): Unit command which adds a print job to a printer. The job definition could now be invalid and the user should be notified of this.
I see the following two alternatives:
Use exceptions anyway
Return something from the method (like a "print job identifier") and then return a Option/Either/Try of that type. But this means adding a return value just for the sake of error handling.
What are the best practices here?
You are too deep into FP :-)
You want to know whether the method is successful or not - return a Boolean!
According to this Throwing exceptions in Scala, what is the "official rule" Throwing exceptions in scala is not advised as because it breaks the control flow. In my opinion you should throw an exception in scala only when something significant has gone wrong and normal flow should not be continued.
For all other cases it generally better to return the status/result of the operation that was performed. scala Option and Either serve this purpose. imho A function which does not return any value is a bad practice.
For the given example of the addPrintJob I would return an job identifier (as suggested by #marstran in comments), if this is not possible the status of addPrintJob.
The problem is that usually when you have to model things for a specific method it is not about having success or failure ( true or false ) or ( 0 or 1 - Unit exit codes wise ) or ( 0 or 1 - true or false interpolation wise ) , but about returning status info and a msg , thus the most simplest technique I use ( whenever code review naysayers/dickheads/besserwissers are not around ) is that
val msg = "unknown error has occurred during ..."
val ret = 1 // defined in the beginning of the method, means "unknown error"
.... // action
ret = 0 // when you finally succeeded to implement FULLY what THIS method was supposed to to
msg = "" // you could say something like ok , but usually end-users are not interested in your ok msgs , they want the stuff to work ...
at the end always return a tuple
return ( ret , msg )
or if you have a data as well ( lets say a spark data frame )
return ( ret , msg , Some(df))
Using return is more obvious, although not required ( for the purists ) ...
Now because ret is just a stupid int, you could quickly turn more complex status codes into more complex Enums , objects or whatnot , but the point is that you should not introduce more complexity than it is needed into your code in the beginning , let it grow organically ...
and of course the caller would call like
( ret , msg , mayBeDf ) = myFancyFunc(someparam, etc)
Thus exceptions would mean truly error situations and you will avoid messy try catch jungles ...
I know this answer WILL GET down-voted , because well there are too much guys from universities with however bright resumes writing whatever brilliant algos and stuff ending-up into the spagetti code we all are sick of and not something as simple as possible but not simpler and of course something that WORKS.
BUT, if you need only ok/nok control flow and chaining, here is bit more elaborated ok,nok example, which does really throw exception, which of course you would have to trap on an upper level , which works for spark:
/**
* a not so fancy way of failing asap, on first failing link in the control chain
* #return true if valid, false if not
*/
def isValid(): Boolean = {
val lst = List(
isValidForEmptyDF() _,
isValidForFoo() _,
isValidForBar() _
)
!lst.exists(!_()) // and fail asap ...
}
def isValidForEmptyDF()(): Boolean = {
val specsAreMatched: Boolean = true
try {
if (df.rdd.isEmpty) {
msg = "the file: " + uri + " is empty"
!specsAreMatched
} else {
specsAreMatched
}
} catch {
case jle: java.lang.UnsupportedOperationException => {
msg = msg + jle.getMessage
return false
}
case e: Exception => {
msg = msg + e.getMessage()
return false
}
}
}
Disclaimer: my colleague helped me with the fancy functions syntax ...

Why is this defined value not recognized as a package or object reference?

I have the code below:
my $content = $response->decoded_content((charset => 'UTF-8'));
my $feed = XML::Feed->parse(\$content) || $logger->error("When retrieving $URL: ", XML::Feed->errstr);
if (defined $feed) {
for my $entry ($feed->entries) {
#DO SOMETHING
}
}
For some site, XML::FEED saying that it can't detect the feed type. This is something I have to look at but this is not my question at the moment.
This sample code is inside a while loop has I'm retrieving different RSS and I would like to have the script running even when some URLs failed.
The defined function seems to not work as I get the error message:
Can't call method "entries" without a package or object reference
Can someone tell me what is the right way to handle the test?
You first have to check the value of $feed.
The error message you describe is obvious: $feed is not a package / object reference, but it can be a simple hash for instance. So it's defined.
Add my favourite debugging line right in front of if(defined):
warn Data::Dumper->new([ $feed ],[ '*feed' ])->Sortkeys(1)->Dump();use Data::Dumper;
and you'll see the value in a nice way.
Without testing I'd say that $feed contains the result of your logger, which might be 1 or 0 or something like that, because you set the value of $feed to XML::Feed->parse, and if this is not successful (undefined) it's the result of $logger->error.
You'd better write it like:
my $feed = XML::Feed->parse(\$content);
if (defined $feed) {
for my $entry ($feed->entries) {
#DO SOMETHING
}
}
else {
$logger->error("When retrieving $URL: ", XML::Feed->errstr);
}
because parse is said to return an object, and I guess it returns undef on error.
The error message means what it says: $feed is neither a package nor an object reference. It passes the defined test because there are many defined values which are neither packages nor object references.
In this particular case, you're seeing this error because you are misuing ||:
my $feed = XML::Feed->parse(\$content) || $logger->error("When retrieving $URL: ", XML::Feed->errstr);
If the parse call should fail and return undef, this evaluates to
my $feed = ( undef || $logger->error("When retrieving $URL: ", XML::Feed->errstr) );
which evaluates to
my $feed = $logger->error("When retrieving $URL: ", XML::Feed->errstr);
. The return value of $logger->error is unknown to me, but presumably it is neither a package nor an object reference. And if it were one, it probably would be the wrong one to put in a variable named $feed.
The documentation for XML::Feed mentions parsing with a construct like
my $feed = XML::Feed->parse(URI->new('http://example.com/atom.xml'))
or die XML::Feed->errstr;
This is not the same thing. Their respective precedence rules make || and or suitable for different applications; specifically, you should only use || when you want the value on the right-hand side for something. Do not use it only for the short-circuit side effect.
You can solve this by replacing the || with or to get the right evaluation order. While you are there, you probably should also eliminate the redundant defined test.

Why does Perl complain "can't modify non-lvalue subroutine call"?

I have index.pl and subs.pl. When I run the program, the user inserts the date of birth and then it is passed to the getage() subroutine in subs.pl, which has many subroutines.
getage() than implicitly calls another subroutine called validate() which validates the date entered by user.
When I run the index.pl and the user enters the date as 03-04-2005, the following error comes out:
can't modify non-lvalue subroutine call at subs.pl line 85, <> line 1
At 85th line of subs.pl I have:
list(my $val,my #value) = validate($dob);
validate() returns a message and the date($dob) which is sent from getage().
Some code from validate():
sub validate {
my $dob = shift;
my $error;
my #test;
#test = split("-",$dob);
if (!#test) {
$error = "date separator should be - ";
return ($error,#test);
}
...
The solution seems to be:
my ($val, #value) = validate($dob);
based on my intuitive understanding of what that code intended - but I can't be certain till you provide some more context (what does validate() return, what does list() mean?)
If you meant list() as a means to force $val and #value into a list, you merely need to enclose both in parenthesis: ($val, #value) to do that
An lvalue is a variable you can modify. (one that can be on the left side of an assignment, hence the name). In most circumstances, a value returned by a sub is not one you can modify.
In your example, you are attempting exactly that: assigning the return value of validate($dob) to the nonmodifiable return value of list($val, #value).
in line
list(my $val,my #value) = validate($dob);
remove 'list' and it works fine
ie
(my $val,my #value) = validate($dob);
thanks to Kayra and others who answered