Extend any classes

作者:   發佈於:  

It may or may not be a good practice / group culture to do this, but it's easy to extend any classes by manipulating the symbol table.

I found myself in love with iterating over things with each method. Therefore I extend Jifty::DBI::Collection to add each on it, I say:

*Jifty::DBI::Collection::each = sub {
    my $self = shift;
    my $cb = shift;
  
    my $idx = 0;
    $self->goto_first_item();
    while(my $record = $self->next) {
        my $ret = $cb->($record, $idx++, $self);
        last if (defined($ret) && !$ret);
    }
};

Notice that this needs to be done after use Jifty::DBI. Then I can do something like this in my Jifty application view code:

PostCollection->each(
    sub {
        my ($post, $index, $post_collection) = @_;
        div { $post->body };
    }
);

With the helper function defined in my JiftyX::ModelHelpers

This sometimes gets really handy, and it feels like I'm doing some prototype-based OO in Javascript.

Actually the least scary way to do this is to just use package twice to switch current package:

package Jifty::DBI::Collection;
sub each { ... };
package main; # Or to wherever you can from.

If you want to avoid two package calls for some reason, you may use eval:

eval 'package Jifty::DBI::Collection;
sub each { ... };';

(But then you need to be aware of the quotes.)

I personally found these two approaches are less readable then the symbol table assignment statement above, since I write javascript and ruby code too.

Again, it might not be a good practice. Don't try it at home. Or, try it only if you're at home. ykwim.