Suppose I have a complex chain of ifs. Now I want to be sure that one of the conditions are triggered, so I add the final line to notify me when nothing was triggered.
if condition1 ...
else if condition2 ...
else if condition3 ...
else print( "Ooops nothing triggered" )
Since I only want to print this in DEBUG mode, I wrap the final line
#if DEBUG
else print( "Ooops nothing triggered" )
#endif
and I get the strangest errors. "Closure expression is unused" and "Expected expression".
Here is some simple working code to illustrate with.
let x = Int ( arc4random_uniform ( 100 ) ) - 50
// This works
if x > 0 { print ( "Positive" ) }
else if x < 0 { print ( "Negative" ) }
else { print ( "Oops - neither" ) }
// After adding the #if this does not compile
if x > 0 { print ( "Positive" ) }
else if x < 0 { print ( "Negative" ) }
#if DEBUG
else { print ( "Oops - neither" ) }
#endif
Obviously Swift's conditional compilation here fails. I wonder why and ask how to to do this so that the test is only applied in DEBUG mode?
FWIW I am not interested in e.g. using switch - the actual logic is complex. How to do this with ifs and else ifs if possible please?
These #ifs don't really work like those preprocessor directives in C. They
According to the grammar, the syntax of these directives are the following:
if-directive-clause → if-directive compilation-condition statements(opt)
elseif-directive-clauses → elseif-directive-clause elseif-directive-clauses(opt)
elseif-directive-clause → elseif-directive compilation-condition statements(opt)
else-directive-clause → else-directive statements(opt)
if-directive → #if
elseif-directive → #elseif
else-directive → #else
endif-directive → #endif
Note that an if-directive-clause consists of #if, then a compilation-condition, then some statements. Not just anything, but statements.
else { print ( "Oops - neither" ) }
is not a statement (or a list of statements).
How about putting the #if inside the else block? That is guaranteed to be a statements:
if x > 0 { print ( "Positive" ) }
else if x < 0 { print ( "Negative" ) }
else {
#if DEBUG
print ( "Oops - neither" )
#endif
}
Can anyone explain following piece of code in https://github.com/simondeziel/custom-nagios-plugins/blob/master/plugins/check_megaraid_sas . (line num 220-223)
Why this code is there
} elsif ( $slotnumber != 255 ) {
$pdbad++;
$status = 'CRITICAL';
}
It makes sense to look at the complete section:
PDISKS: while (<PDLIST>) {
if ( m/Slot Number\s*:\s*(\d+)/ ) {
$slotnumber = $1;
$pdcount++;
} elsif ( m/(\w+) Error Count\s*:\s*(\d+)/ ) {
if ( $1 eq 'Media') {
$mediaerrors += $2;
} else {
$othererrors += $2;
}
} elsif ( m/Predictive Failure Count\s*:\s*(\d+)/ ) {
$prederrors += $1;
} elsif ( m/Firmware state\s*:\s*(\w+)/ ) {
$fwstate = $1;
if ( $fwstate eq 'Hotspare' ) {
$hotsparecount++;
} elsif ( $fwstate eq 'Online' ) {
# Do nothing
} elsif ( $fwstate eq 'Unconfigured' ) {
# A drive not in anything, or a non drive device
$pdcount--;
} elsif ( $slotnumber != 255 ) {
$pdbad++;
$status = 'CRITICAL';
}
}
} #PDISKS
That section loops over a list of PDs (Primary Disks?), and I assume that this file / program output contains a human readable status for every attached device. The code looks at every line and performs some actions depending on the content of that line:
$slotnumber is assigned whenever there is Slot Number : ... in the contents of PDLIST. From looking at the logic, if there is a Firmware state line that is not Hotspare, Online or Unconfigured, and the $slotnumber is not 255, then something went horribly wrong and the status is considered CRITICAL. The number of bad PDs ($pdbad) is then increased by one.
I have two .drl files:
.dlr file one
rule "Lower Elementary Level"
no-loop
when
$m: MockBean ( overAllScore >= 40.51 && overAllScore < 60.76 )
$s : StudentMockBean()
then
$s.setKnowledgeLevel( "Lower Elementary Level" );
update( $s );
end
// some other condition
.drl file two
rule "Concept Lower Elementary Level"
no-loop
when
$m: MockBean ( mockOneScore >= 40.51 && mockOneScore < 60.76 )
$s : StudentMockBean()
then
$s.setMockOneKnowledgeLevel( "Lower Elementary Level" );
update( $s );
end
// some other condition
I'm reading both of them through this:
...
for( String fileName : aRuleFileName )
{
kbuilder.add( ResourceFactory.newClassPathResource( fileName, getClass() ), ResourceType.DRL );
}
// get error
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
return kbase;
I fired both rules and both .drl file met the condition but they are updating same object.
My question is why does my web app keep on loading infinitely?
You are having an infinite loop caused by the combination of your rules.
I.e. rule A activates -> rule A fires -> modifies $s -> rule B activates -> rule B fires -> modifies $s -> rule A activates -> rule A fires -> modifies $s -> rule B activates -> rule B fires -> ...
no-loop is not enough solution for this situation.
For a better explanation on what's going on and possible ways to solve your problem please read this blog entry.
Hope it helps,
Right now, I have the following Perl code
my $tmpl1="download1_video.html"
if $file->{file_name}=~/\.(avi|divx|mkv|flv|mp4|wmv)$/i;
$tmpl1||="download1.html";
so it's checking to see if the file is a video, and if so it directs it to the certain page. Although I'm just wondering how I can add another if statement in there to check if the extension is .mp3, and if so direct it to download1_audio.html.
if ( $file->{file_name} =~ m/\.(avi|divx|mkv|flv|mp4|wmv)$/i ){
## Download video
}
elsif($file->{file_name} =~ m/\.(mp3)$/i){
## Download Audio
}
Is this what you needed ?
if ($file->{file_name} =~ /\.(avi|divx|mkv|flv|mp4|mp3|wmv)$/i )
{
if ($1 eq "mp3")
{
# mp3 stuff
}
elsif ($1 eq "mp4")
{
# mp4 stuff
}
else
{
# all other file types
}
}
else
{
# It didn't match
}
A fancier way would be to create a hash keyed by your file types in advance with the info you needed for your next page; the filename I guess?
my %pageHash = ( "mp3" => "mp3Page.html", "divx" => "divxPage.html", ... );
...
$file->{file_name} =~ /\.(.*)$/i;
if (exists $pageHash{$1})
{
$page = $pageHash{$1};
}
else
{
# unknown file extension
}
Having just been burnt by this, I must advise you against declaring a variable with a conditional modifier. If the condition does not hold true, it runs no part of the other clause, which means that you are not declaring $tmpl1, but since it's already passed strict, it allows you to assign to an undefined position in memory.
There is a safer way to do what your predecessor is doing here, that can yet illustrate a solution.
my $tmpl1
= $file->{file_name} =~ /\.(avi|divx|mkv|flv|mp4|wmv)$/i
? 'download1_video.html'
: $file->{file_name} =~ m/\.mp3$/i
? 'download1_audio.html'
: 'download1.html'
;
Thus,
$tmpl1 is always declared
$tmpl1 is always assigned a value
There is something like status changes check logic in our app.
Currently checking is being handled by ugly if statement
I want to replace it by transition matrix:
my %allowed_status_changes = (
1 => (2,5),
2 => (1,2,3,4,5),
3 => (4,2),
4 => (3,2),
5 => (),
);
my $is_allowed_transition =
$submitted_status ~~ $allowed_status_changes {$original_status};
if ($prerequestsites && !$is_allowed_transition) {
return;
}
certain transitions can be allowed only on additional condition, therefore I will need something like
2 => (
(target => 1)
(target => 2, condition => $some_condition)
(target => (3,4), condition => $other_condition),
(target => 5)
),
(in my opinion it is too long)
What structure would you use in this situation if you should focus on readability and maintainability?
How you will parse it to check if transition is allowed?
If the conditions are very prevalent (e.g. almost every allowed transition has them) then your latter structure is perfectly fine, other than your syntax error of representing a hashref with "()" instead of "{}".
If the conditions are rare, I'd suggest going with #1, augmented by optional constructs similar to your #2.
Please note that readability of checking code is IMHO very clear though voluminous and not very idiomatic.
OTOH, maintainability of the matrix is high - you have terse yet readable syntax from #1 where no conditions are needed and a clear though longer syntax for conditions which is flexible enough for many conditions per many settings like your #2.
my %allowed_status_changes = (
1 => [2,5],
2 => [1,5,{targets=>[2], conditions=>[$some_condition]}
,{targets=>[3,4], conditions=>[$other_condition, $more_cond]}]
3 => [4,2],
4 => [3,2],
5 => [],
);
sub is_allowed_transition {
my ($submitted_status, $original_status ) = #_;
foreach my $alowed_status (#$allowed_status_changes{$original_status}) {
return 1 if !ref $alowed_status && $alowed_status == $submitted_status;
if (ref $alowed_status) {
foreach my $target (#$alowed_status{targets}) {
foreach my $condition (#$alowed_status{conditions}) {
return 1 if check_condition($submitted_status
, $original_status, $condition);
}
}
}
}
return 0;
}
if ($prerequestsites
&& !$is_allowed_transition($submitted_status, $original_status )) {
return;
}
Although I agree with DVK for the most part, I have to say, once you start delving into arrays of arrays of hashes, you're reaching a code complexity level that is hard to maintain without much spinning of heads and bugs.
At this point, I'd probably reach for an object and a class, for a bit of syntactic sugar.
my $transitions = TransitionGraph->new();
$transition->add( 1, { targets => [ 2, 5 ] });
$transition->add( 2, { targets => [ 1, 5 ] });
$transition->add( 2, { targets => [ 2 ], conditions => [ $some_condition ] });
$transition->add( 2, { targets => [ 3, 4 ], conditions => [ $other_condition, $more_cond ]});
$transition->add( 3, { targets => [4,2] } );
$transition->add( 4, { targets => [3,2] } );
$transition->add( 5, { targets => [] } );
if( $transition->allowed( 1 , 3 )){
}
Class implementation is up to the user, but I'd use Moose.
The primary benefits of this is you're encapsulating how the state graph works so you can Just Use it and worry about how the graph works seperate from where its used.
nb. in the above proposed API, add() creates a new record if one does not exist, and updates that record if it does exist. This turned out to be simpler than having "upgrade" methods or "get this item and then modify it" techniques.
Internally, it could do this, or something like it:
sub add {
my ( $self , $input_state, $rules ) = #_;
my $state;
if ( $self->has_state( $input_state ) ) {
$state = $self->get_state( $input_state );
} else {
$state = TransitionGraphState->new( source_id => $input_state );
$self->add_state( $input_state, $state );
}
my $targets = delete $rules{targets};
for my $target ( #$targets ) {
$state->add_target( $target, $rules );
}
return $self;
}
sub allowed {
my ( $self, $from, $to ) = #_;
if ( not $self->has_state( $from ) ){
croak "NO source state $from in transition graph";
}
my $state = $self->get_state( $from );
return $state->allowed_to( $to );
}
This also has the cool perk of not requiring one particular code set to work on the sub-nodes, you can create seperate instances with their own behaviour just in case you want one source state to be treated differently.
$transition->add_state( 2, $some_other_class_wich_works_like_transitiongraphstate );
Hope this is helpful =).
There is nothing wrong with the second form. You are not going to be able to get around the fact that you must encode the state machine somewhere. In fact, I think having the entire machine encoded in one place like that is far easier to understand that something with too many layers of abstraction where you need to look in n different places to understand the flow of the machine.