Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'm getting data to fill out an e-mail template, and I'm wondering if this method is too long. How could I refactor it?

sub getEmailData
{
    my $self = shift;

    my $defs = QuickContentFunction::Simple::QuerySearchFieldDefinitions->new();

    my $phParams = decode_json($self->parameters);
    my @aFields = split(/~/, $phParams->{sFields});
    my @aCategories = split(/~/, $phParams->{sCategories});
    my @aValues = split(/~/, $phParams->{sValues});
    my @aConditions = split(/~/, $phParams->{sConditions});

    my $sSummary = $phParams->{sSummary};
    $sSummary =~ s/\'//g;
    my @aSummary = split(/\d/, $sSummary);

    my $phData = { name => $self->name };

    my $mapping = $self->getOperatorMapping();
    for (my $i = 0; $i < scalar(@aFields); $i++) {
        my $phFieldInfo = $defs->getFieldHash( $aCategories[$i], $aFields[$i]);

        my $value = $aValues[$i];
        if ($phFieldInfo->{value_displays}) {
            $value = @{$phFieldInfo->{value_displays}}[$value];

        } elsif ($phFieldInfo->{value_keys}) {
            $value = @{$phFieldInfo->{value_keys}}[$value];
        }

        push( @{$phData->{conditions}}, {
            field    => $phFieldInfo->{field_display},
            operator => $mapping->{$phFieldInfo->{field_type}}->{$aConditions[$i]},
            value    => $value,
            postfix  => $aSummary[$i+1] || undef
        } );
    }

    $phData->{mode} = lc($phParams->{sMode});
    if ($self->hasResults()) {
        $phData->{deals} = \@{decode_json($self->result)};
    }

    return $phData;
}
share|improve this question

2 Answers 2

First off, stuff like my @aFields = split(/~/, $phParams->{sFields}); is a sign of something gone awry. You've just deserialized $phParams from a JSON object, so why isn't this just stored in a normal array?

There is no need to write $i < scalar(@aFields), just write $i < @aFields.

I have some comments wrt. this snippet:

my $value = $aValues[$i];
if ($phFieldInfo->{value_displays}) {
    $value = @{$phFieldInfo->{value_displays}}[$value];
} elsif ($phFieldInfo->{value_keys}) {
    $value = @{$phFieldInfo->{value_keys}}[$value];
}

You should always use warnings; and use strict;. The above won't run without warnings if warnings are on because @{$phFieldInfo->{value_keys}}[$value] should be written ${$phFieldInfo->{value_keys}}[$value].

Also, the whole thing can be written much shorter:

my $value = ${$phFieldInfo->{value_displays}}[$aValues[$i]]
    || ${$phFieldInfo->{value_keys}}[$aValues[$i]]
    || $aValues[$i];

Note: this isn't functionally identical with the original code, since I'm assuming that array refs at the keys value_displays and value_keys exists.

This essentially means "pick the first trueish value". Note that values like undef, 0 or the empty string won't be picked. If you want to be able to pick 0 or the empty string, replace || with //. This requires a recent version of perl (read: not ancient).

The rest looks reasonable. Fixing the stuff I suggested should cut the size a little, and I wouldn't try shortening it further.

share|improve this answer
    
awesome, thanks a lot! The reason the data is stored as a JSON is beyond my control, but I agree, it shouldn't be that way. I actually do have use warnings on, but we're on perl version 5.8..could that be why it didn't throw anything? I like your || ... || construct. Thanks again! –  Sam Selikoff Jul 12 '13 at 21:14
    
It should warn even with perl 5.8. That's odd. By the way - using strict is more important than warnings. –  Michael Zedeler Jul 13 '13 at 4:59
    
there are few problems with ||; first $value is defined with my and used on the same line; second $value should start with contents of $aValues[$i]; third undef or other false value will continue evaluation unlike in OP; and last, autovivification will take place unlike in OP. First two are essential problems while others may not spoil OP logic. –  mpapec Jul 13 '13 at 21:18
    
You're right. I didn't spot that $value is being reused. Duh. –  Michael Zedeler Jul 13 '13 at 22:04
    
I believe I've fixed it now. I'm not used to code where data is being set and reset in this way. –  Michael Zedeler Jul 13 '13 at 22:09

Some of the replaced lines are left as comments.

sub getEmailData {
    my $self = shift;

    my $defs = QuickContentFunction::Simple::QuerySearchFieldDefinitions->new();

    my $phParams = decode_json($self->parameters);
    # my @aFields = split(/~/, $phParams->{sFields});
    # my @aCategories = split(/~/, $phParams->{sCategories});
    # my @aValues = split(/~/, $phParams->{sValues});
    # my @aConditions = split(/~/, $phParams->{sConditions});

    my ($aFields, $aCategories, $aValues, $aConditions) = 
      map [ split /~/, $phParams->{$_} ],
      qw(sFields sCategories sValues sConditions);

    my $sSummary = $phParams->{sSummary};
    $sSummary =~ tr|'||d; # s/\'//g;
    my @aSummary = split(/\d/, $sSummary);

    my $phData = { name => $self->name };

    my $mapping = $self->getOperatorMapping();
    # for (my $i = 0; $i < scalar(@aFields); $i++) 
    for my $i (0 .. $#$aFields) {
        my $phFieldInfo = $defs->getFieldHash( $aCategories->[$i], $aFields->[$i]);

        my $value = $aValues->[$i];
        if ($phFieldInfo->{value_displays}) {
            $value = $phFieldInfo->{value_displays}[$value];
        } 
        elsif ($phFieldInfo->{value_keys}) {
            $value = $phFieldInfo->{value_keys}[$value];
        }

        push @{$phData->{conditions}}, {
            field    => $phFieldInfo->{field_display},
            operator => $mapping->{ $phFieldInfo->{field_type} }{ $aConditions->[$i] },
            value    => $value,
            postfix  => $aSummary[$i+1] || undef
        };
    }

    $phData->{mode} = lc($phParams->{sMode});
    if ($self->hasResults()) {
        # $phData->{deals} = \@{decode_json($self->result)};
        $phData->{deals} = decode_json($self->result);
    }

    return $phData;
}
share|improve this answer
    
I can't tell if the #$aFields is a comment...so is it for my $i (0 .. $aFields) ? What version of perl is required? –  Sam Selikoff Jul 14 '13 at 23:20
    
any perl5 is fine, $aFields is array reference so $#$aFields is last index for that array (if you're more comfortable with brackets then $#{$aFields}) –  mpapec Jul 15 '13 at 7:05

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.