tags:

views:

189

answers:

4

I have the following mostly ok code:

my $results = { data => [
   map {
      my $f = $_->TO_JSON;
      $f->{display_field} = $_->display_field($q);
      $f;
   } $rs->all
]};

Only I'd rather it were more like the following:

my $results = { data => [
   map {
      %{$_->TO_JSON},
      display_field => $_->display_field($q),
   }, $rs->all
]};

But that gives a syntax error. How can I do what I want, or is my current version the best it gets?

update: sorry about the extra semicolon from before. It's late here. Not sure how I missed it. Thanks guys!

+5  A: 

It only gives a syntax error because you Perl thinks you need to omit the comma after map { ... }, because it is parsing that map as being a block, not an expression. Putting + in front will fix that. Also, you can't have a semicolon in an anonymous hash:

my $results = { data => [
   map +{
#      ^----------------- plus sign added
      %{$_->TO_JSON},
      display_field => $_->display_field($q);
#                                           ^---- should be comma or nothing
   }, $rs->all
]};
derobert
He doesn't need to omit the comma. He needs it to be an anonymous hash reference, not a code block, and in this case the comma is necessary. It's Perl that's guessing wrong.
Chris Lutz
Ah, that looks like a good probable cause. I don't know how I missed a semicolon in a hash reference. +1
Chris Lutz
+2  A: 

The problem is that Perl doesn't look ahead far enough to figure out whether { means "start an anonymous hash reference" or "start a code block". It should (ideally) look to the corresponding } and see if there is or isn't a comma, and act accordingly, but it doesn't. It only looks a little bit ahead and tries to guess. And this time it's wrong, and you get a syntax error about a comma that shouldn't be there, except that it should so don't move it.

perldoc -f map will tell you all about this. Basically, it says that if you put +{, Perl will understand that this means "not a code block" and guess that it's a hash reference. This is probably the cause of your syntax error. As another suggestion, it might work to say map({ HASH STUFF }, $rs->all) - I bet money Perl won't guess it's a code reference here.

I couldn't get it to work, but not having $rs or a ->TO_JSON or a variable named $q I couldn't get any of this to work anyway. I hope this helps. If not, post a little more code. Don't worry, we don't bite.

Also, while we're at it, why not write it this way:

my $results;
$results->{data} = [ map MAGIC MAP STUFF, $rs->all ];

Might arguably be more readable, especially if you're adding a lot of stuff to $results all at once.

Chris Lutz
+{ isn't working at all in this case for some weird reason. Trying to figure out why.
derobert
Me too. You might try using parenthesis: `map({ HASH STUFF }, $rs->all)`
Chris Lutz
Found out why; see my answer. Oddly enough, $hashref = { foo => 1, bar => 2 **;** } is an error.
derobert
I just saw. I don't know how I missed it, and I almost think Perl shouldn't whine about this given some of the other things it accepts, but that is most likely the culprit here.
Chris Lutz
+1  A: 

I'm not completely sure what kind of structure you're looking for. The map in your first example already returns a list of hashrefs (every version of $f).

If you just want syntax similar to your second example, then you were almost right; you need to get rid of the extraneous semicolon in your map block, and use a pair of curlies to make an anonymous hash ref.

Something like:

my $results = { data => [
    map { { %{$_->TO_JSON},
            display_field => $_->display_field($q)
          }
    } $rs->all
]};
friedo
I believe it can be done without double brackets, but +1.
Chris Lutz
You're right, it can also be done with a unary + compiler hint. I like this way better though because it's more clear (IMHO).
friedo
It's arguable. I would prefer parenthesis around the arguments to `map()` here as "more readable", but I definitely agree the double brackets make it more obvious than `+{` however ugly the double parenthesis may look.
Chris Lutz
A: 

I just always use map in the block form, and structure the code so it's easy to pick apart. Although you can put a + in front of the opening curly to use the expression form, does it really matter to you that much?

Aside from everything else going on, your first example looks fine. Move on and solve real problems. :)

brian d foy