#!/usr/bin/perl

use strict;
use warnings;

use Carp qw/croak/;
use List::MoreUtils qw/firstidx firstval/;

use Yandex::YT;
use Yandex::ListUtils;
use Yandex::HashUtils;

sub yield($);
sub yields($;$$);
sub iter(&);

my %args_idx = map {$ARGV[$_] => $_} 0..$#ARGV;
if (grep {/^(--help|-help|-h)$/} @ARGV) {
    print 
q#Write perl one-liners for YT! (like perl -nae '')

mapreduce-pyt -map '$r->{uid} *= 100; yield $r' -src 'tmp/1{uid}' -dst tmp/2
mapreduce-pyt -map '$S{$r->{id}}++; }{ yields \%S' -src 'tmp/1{uid}' -dst tmp/2
mapreduce-pyt -map '$cnt++; }{ yield {cnt => $cnt}' -src 'tmp/1{uid}' -dst tmp/2
mapreduce-pyt -reduce 'while(my $r = $s->get_all) {$g->{cnt}++} yield $g' -reduceby uid -src 'tmp/1{uid}' -dst tmp/2
mapreduce-pyt -reduce 'iter {$g->{cnt}+=$r->{cnt}}; yield $g if $g->{cnt} > 100' -reduceby uid -src 'tmp/1{uid}' -dst tmp/2
mapreduce-pyt -read tmp/2

mapreduce-pyt -src 'logs/logcmd{logtime}["20130801":"20130801z"]' -map 'yield {h => substr($r->{logtime},8,2)}' -reduce 'iter {$g->{cnt}++}' -dst 'tmp/5'

What you can use in onliner:
  $s - Yandex::YT::Streaming object (supports yield(), get(), get_all())
  yield($) ~ $s->yield
  yelds({a=>1, b=>2}) ~ yield {key => 'a', value => 1}; yield {key => 'b', value => 2};
  yelds({ip1 => 1, ip2=>2}, ip => 'cnt') ~ yield {ip => 'ip1', cnt => 1}; yield {ip => 'ip2', cnt => 2};
  iter {CODE}; - full analogue of "while(my $r = $s->get) {CODE;}"
  $r - current record (in map or iter only)
  $g - current reduce group (in reduce only)
  $_ - current line
#;
    exit 0;
}

my $format = 'dsv';
if (defined (my $format_idx = $args_idx{'-format'}) ) {
    $format = $ARGV[$format_idx+1];
} elsif (!defined $args_idx{'-dsv'}) {
    push @ARGV, '-dsv';
}
if ($format !~ /^(dsv|json)$/) {
    croak "unsupported format: $format";
}

my @cleanup_files;
if (exists $args_idx{"-read"}) {
    Yandex::YT::_read_and_format(['mapreduce-yt', @ARGV]);
} else {
    for my $cmd_type (qw/map reduce/) {
        my $cmd_idx = $args_idx{"-$cmd_type"};
        next if !defined $cmd_idx;
        croak "-$cmd_type argument is not defined" if $cmd_idx == $#ARGV;
        my $cmd = $ARGV[$cmd_idx+1];

        my $streaming_params = "format => '$format'";
        my $main;
        if ($cmd_type eq 'map') {
            $main = "while(my \$r = \$s->get) {local \$_ = \$s->{_line}; $cmd}";
        } else {
            my @reduceby = map {$ARGV[$_] eq '-reduceby' ? $ARGV[$_+1] : ()} 0..$#ARGV-1;
            croak "Incorrect -reduceby" if !@reduceby || grep {!/^\w+$/} @reduceby;
            $streaming_params .= ', reduceby => '.Data::Dumper->new([\@reduceby])->Terse(1)->Indent(0)->Dump();
            $main = "while(my \$g = \$s->get_group) {local \$_ = \$s->{_line}; $cmd}";
        }

        { no strict; eval "sub ___test_$cmd_type {my (\$s,\$r,\$g); $main; }"; }
        croak $@ if $@;

        $main = "my \$s = Yandex::YT::Streaming->new($streaming_params);
my \$r;
my \$g;
sub yield (\$) {
    \$s->yield(\$_[0]);
}
sub yields (\$;\$\$) {
    my \$h = shift;
    my \$kn = \$_[0] || 'key';
    my \$vn = \$_[1] || 'value';
    while(my (\$k, \$v) = each \%\$h) {
        \$s->yield(+{\$kn => \$k, \$vn => \$v});
    }
}
sub iter (&) {
    while(\$r = \$s->get) {
        local \$_ = \$s->{_line};
        \$_[0]->();
    }
}

$main
";

    my $prog = "#!/usr/bin/perl

use List::Util qw/sum/;

use FindBin qw/\$Bin/;
use lib \$Bin;

use Yandex::YT;
use Yandex::ListUtils;
use Yandex::HashUtils;

$main
";
        my ($tar, $yt_cmd) = Yandex::YT::_yt_prog_tar(prog => $prog);
        $ARGV[$cmd_idx+1] = $yt_cmd;
        push @ARGV, "-file", $tar;
        push @cleanup_files, $tar;
    }
    system('mapreduce-yt', @ARGV) and croak "$!";
}



END {
    unlink @cleanup_files;
}
