PATCH for RT-View-ConciseSpreadsheet

Today Jesse released an RT extension for spreadsheet output
that honors the search $Format. This patch handles link
fields better as well as proper quoting using Text::CSV_XS.

enjoy

-Todd

improved_tsv.patch (7.71 KB)

Wait. Why are you using an XS module for something so trivial?On Tue, Aug 15, 2006 at 06:41:26PM -0400, Todd Chapman wrote:

Today Jesse released an RT extension for spreadsheet output
that honors the search $Format. This patch handles link
fields better as well as proper quoting using Text::CSV_XS.

enjoy

-Todd

==== Patch <improved_tsv> level 1
Source: 6fc35107-3207-0410-b21e-9a2d7f624572:/local/bp/rt/extensions/RT-View-ConciseSpreadsheet:8473
Target: e417ac7c-1bcc-0310-8ffa-8f5827389a85:/RT-View-ConciseSpreadsheet:5773
(svn://svn.bestpractical.com)
Log:
r8472@slah001: root | 2006-08-15 14:25:27 -0400
Need to fix rendering of columns formatted as links.
r8473@slah001: root | 2006-08-15 18:26:09 -0400
Handles links much better, as well as properly formatting tsv
using Text::CSV_XS. Fields with carriage returns and tabs
are properly quoted.
TODO: properly strip out other non-printable characters.

=== html/ConciseSpreadsheet/Results.tsv

— html/ConciseSpreadsheet/Results.tsv (revision 5773)
+++ html/ConciseSpreadsheet/Results.tsv (patch improved_tsv level 1)
@@ -1,5 +1,7 @@
<%INIT>

+use Text::CSV_XS;
+
my $Tickets = RT::Tickets->new($session{‘CurrentUser’});
$Tickets->FromSQL($ARGS{‘Query’});

@@ -10,9 +12,7 @@

$r->content_type(‘application/vnd.ms-excel’);

-my @rows=();
my @header=();
-my @cols=();

used to store m->comp output - prevents the output from being

written to the output stream. That’s because we are not interested in the

@@ -22,14 +22,6 @@
foreach my $column (@Format) {
next if $column->{title} eq ‘NEWLINE’;

  • Extract the column names from the Format array

  • foreach my $subcol ( @{ $column->{output} } ) {
  •    if ( $subcol =~ /^__(.*?)__$/o ) {
    
  •        my $col = $1;
    
  •        push (@cols, $col);
    
  •    }
    
  • }
  • Determine the column titles

    my $title = $column->{title};
    $title =~ s/^(.*)$/$1/o;
    @@ -45,43 +37,45 @@
    push @header, $title;
    }

+my $csv = Text::CSV_XS->new( { sep_char => “\t”, binary => 1, eol => “\012” } );
+
+$csv->combine(@header);
+$m->out( $csv->string() );
+
while ( my $Ticket = $Tickets->Next()) {

  • my $row;
  • foreach my $column (@cols) {
  •    my $value = $m->comp({ store => \$mason_output }, 
    
  •                         '/Elements/RT__Ticket/ColumnMap', 
    
  •                         Name => $column, Attr => 'value');
    
  •    if ( $value && ref($value)) {
    
  •        my @x = &{ $value }( $Ticket, 0 );
    
  •        my $i=0;
    
  •        $row->{ $column } = "";
    
  •        foreach my $x (@x) {
    
  •            $row->{ $column } .= ", " if $i > 0; # separating multivalues
    
  •            if (ref ($x)) {
    
  •                $row->{ $column } .= $$x;
    
  •            } else {                        
    
  •                $row->{ $column } .= $x;
    
  • my @row;
  • foreach my $column (@Format) {
  •    next if $column->{title} eq 'NEWLINE';
    
  •    my $column_value = '';
    
  •    foreach my $subcol ( @{ $column->{output} } ) {
    
  •        if ( $subcol =~ /^__(.*?)__$/o ) {
    
  •            my $col = $1;
    
  •            my $value = $m->comp({ store => \$mason_output }, 
    
  •                                 '/Elements/RT__Ticket/ColumnMap', 
    
  •                                 Name => $col, Attr => 'value');
    
  •            if ( $value && ref($value)) {
    
  •                my @x = &{ $value }( $Ticket, 0 );
    
  •                $column_value .= join('', map { ref($_) ? $$_ : $_ } @x);
    
  •            } else {
    
  •                $column_value .=  $value;
               }
    
  •            $i++;
           }
    
  •    } else {
    
  •        $row->{ $column } =  $value ;
    
  •        else {
    
  •            $column_value .= $subcol;
    
  •        }
       }
    
  •    $row->{ $column } =~ s/, <br>//g;    # ColumnMap adds <br> tags, which we don't want
    
  • }
  • push @rows, $row;
    -}

-$m->out(join(“\t”, @header));
-$m->out(“\n”);

  •    $column_value =~ s{<br(\s+/)?>}{, }g;
    
  •    $column_value =  $scrubber->scrub( $column_value );
    
  •    $column_value =~ s{, $}{}g;    # ColumnMap is putting a trailing br
    

-foreach my $row (@rows) {

  •    my @row;
    
  •    foreach my $col(@cols) {
    
  •            push @row, $row->{"$col"};
    
  •    }
    
  •    $m->out(join("\t",@row));
    
  •    $m->out("\n");
    
  •    push @row, $column_value;
    
  • }
  • $csv->combine(@row);
  • $m->out( $csv->string() );
  • $m->flush_buffer();
    }

$m->abort();
@@ -95,3 +89,7 @@
$OrderBy => ‘id’
$Order => ‘ASC’
</%ARGS>
+<%once>
+my $scrubber = HTML::Scrubber->new();
+$scrubber->deny(qw[*]);
+</%once>
=== META.yml

— META.yml (revision 5773)
+++ META.yml (patch improved_tsv level 1)
@@ -1,13 +1,15 @@
-name: RT-View-ConciseSpreadsheet
-version: 0.001
-abstract: [One line description of module’s purpose here]
+abstract: “[One line description of module’s purpose here]”
author: Jesse Vincent jesse@bestpractical.com
+distribution_type: module
+generated_by: Module::Install version 0.63
license: perl
-distribution_type: module
-requires:

  • Test::More: 0
    -no_index:
  • directory:
    +name: RT-View-ConciseSpreadsheet
    +no_index:
  • directory:
    • html
    • inc
      -generated_by: Module::Install version 0.37
    • t
      +requires:
  • Test::More: 0
  • Text::CSV_XS: 0
    +version: 0.001
    === Makefile.PL
    ==================================================================
    — Makefile.PL (revision 5773)
    +++ Makefile.PL (patch improved_tsv level 1)
    @@ -6,5 +6,6 @@
    abstract_from(‘lib/RT/View/ConciseSpreadsheet.pm’);
    license(‘perl’);
    requires(‘Test::More’);
    +requires(‘Text::CSV_XS’);

&WriteAll;

==== BEGIN SVK PATCH BLOCK ====
Version: svk 1.07 (linux)

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
==== END SVK PATCH BLOCK ====


List info: The rt-devel Archives

Because the parameters I am giving to new are not
supported in the non-XS module, but they are important.On Thu, Aug 17, 2006 at 01:47:24PM -0400, Jesse Vincent wrote:

Wait. Why are you using an XS module for something so trivial?

On Tue, Aug 15, 2006 at 06:41:26PM -0400, Todd Chapman wrote:

Today Jesse released an RT extension for spreadsheet output
that honors the search $Format. This patch handles link
fields better as well as proper quoting using Text::CSV_XS.

enjoy

-Todd

==== Patch <improved_tsv> level 1
Source: 6fc35107-3207-0410-b21e-9a2d7f624572:/local/bp/rt/extensions/RT-View-ConciseSpreadsheet:8473
Target: e417ac7c-1bcc-0310-8ffa-8f5827389a85:/RT-View-ConciseSpreadsheet:5773
(svn://svn.bestpractical.com)
Log:
r8472@slah001: root | 2006-08-15 14:25:27 -0400
Need to fix rendering of columns formatted as links.
r8473@slah001: root | 2006-08-15 18:26:09 -0400
Handles links much better, as well as properly formatting tsv
using Text::CSV_XS. Fields with carriage returns and tabs
are properly quoted.
TODO: properly strip out other non-printable characters.

=== html/ConciseSpreadsheet/Results.tsv

— html/ConciseSpreadsheet/Results.tsv (revision 5773)
+++ html/ConciseSpreadsheet/Results.tsv (patch improved_tsv level 1)
@@ -1,5 +1,7 @@
<%INIT>

+use Text::CSV_XS;
+
my $Tickets = RT::Tickets->new($session{‘CurrentUser’});
$Tickets->FromSQL($ARGS{‘Query’});

@@ -10,9 +12,7 @@

$r->content_type(‘application/vnd.ms-excel’);

-my @rows=();
my @header=();
-my @cols=();

used to store m->comp output - prevents the output from being

written to the output stream. That’s because we are not interested in the

@@ -22,14 +22,6 @@
foreach my $column (@Format) {
next if $column->{title} eq ‘NEWLINE’;

  • Extract the column names from the Format array

  • foreach my $subcol ( @{ $column->{output} } ) {
  •    if ( $subcol =~ /^__(.*?)__$/o ) {
    
  •        my $col = $1;
    
  •        push (@cols, $col);
    
  •    }
    
  • }
  • Determine the column titles

    my $title = $column->{title};
    $title =~ s/^(.*)$/$1/o;
    @@ -45,43 +37,45 @@
    push @header, $title;
    }

+my $csv = Text::CSV_XS->new( { sep_char => “\t”, binary => 1, eol => “\012” } );
+
+$csv->combine(@header);
+$m->out( $csv->string() );
+
while ( my $Ticket = $Tickets->Next()) {

  • my $row;
  • foreach my $column (@cols) {
  •    my $value = $m->comp({ store => \$mason_output }, 
    
  •                         '/Elements/RT__Ticket/ColumnMap', 
    
  •                         Name => $column, Attr => 'value');
    
  •    if ( $value && ref($value)) {
    
  •        my @x = &{ $value }( $Ticket, 0 );
    
  •        my $i=0;
    
  •        $row->{ $column } = "";
    
  •        foreach my $x (@x) {
    
  •            $row->{ $column } .= ", " if $i > 0; # separating multivalues
    
  •            if (ref ($x)) {
    
  •                $row->{ $column } .= $$x;
    
  •            } else {                        
    
  •                $row->{ $column } .= $x;
    
  • my @row;
  • foreach my $column (@Format) {
  •    next if $column->{title} eq 'NEWLINE';
    
  •    my $column_value = '';
    
  •    foreach my $subcol ( @{ $column->{output} } ) {
    
  •        if ( $subcol =~ /^__(.*?)__$/o ) {
    
  •            my $col = $1;
    
  •            my $value = $m->comp({ store => \$mason_output }, 
    
  •                                 '/Elements/RT__Ticket/ColumnMap', 
    
  •                                 Name => $col, Attr => 'value');
    
  •            if ( $value && ref($value)) {
    
  •                my @x = &{ $value }( $Ticket, 0 );
    
  •                $column_value .= join('', map { ref($_) ? $$_ : $_ } @x);
    
  •            } else {
    
  •                $column_value .=  $value;
               }
    
  •            $i++;
           }
    
  •    } else {
    
  •        $row->{ $column } =  $value ;
    
  •        else {
    
  •            $column_value .= $subcol;
    
  •        }
       }
    
  •    $row->{ $column } =~ s/, <br>//g;    # ColumnMap adds <br> tags, which we don't want
    
  • }
  • push @rows, $row;
    -}

-$m->out(join(“\t”, @header));
-$m->out(“\n”);

  •    $column_value =~ s{<br(\s+/)?>}{, }g;
    
  •    $column_value =  $scrubber->scrub( $column_value );
    
  •    $column_value =~ s{, $}{}g;    # ColumnMap is putting a trailing br
    

-foreach my $row (@rows) {

  •    my @row;
    
  •    foreach my $col(@cols) {
    
  •            push @row, $row->{"$col"};
    
  •    }
    
  •    $m->out(join("\t",@row));
    
  •    $m->out("\n");
    
  •    push @row, $column_value;
    
  • }
  • $csv->combine(@row);
  • $m->out( $csv->string() );
  • $m->flush_buffer();
    }

$m->abort();
@@ -95,3 +89,7 @@
$OrderBy => ‘id’
$Order => ‘ASC’
</%ARGS>
+<%once>
+my $scrubber = HTML::Scrubber->new();
+$scrubber->deny(qw[*]);
+</%once>
=== META.yml

— META.yml (revision 5773)
+++ META.yml (patch improved_tsv level 1)
@@ -1,13 +1,15 @@
-name: RT-View-ConciseSpreadsheet
-version: 0.001
-abstract: [One line description of module’s purpose here]
+abstract: “[One line description of module’s purpose here]”
author: Jesse Vincent jesse@bestpractical.com
+distribution_type: module
+generated_by: Module::Install version 0.63
license: perl
-distribution_type: module
-requires:

  • Test::More: 0
    -no_index:
  • directory:
    +name: RT-View-ConciseSpreadsheet
    +no_index:
  • directory:
    • html
    • inc
      -generated_by: Module::Install version 0.37
    • t
      +requires:
  • Test::More: 0
  • Text::CSV_XS: 0
    +version: 0.001
    === Makefile.PL
    ==================================================================
    — Makefile.PL (revision 5773)
    +++ Makefile.PL (patch improved_tsv level 1)
    @@ -6,5 +6,6 @@
    abstract_from(‘lib/RT/View/ConciseSpreadsheet.pm’);
    license(‘perl’);
    requires(‘Test::More’);
    +requires(‘Text::CSV_XS’);

&WriteAll;

==== BEGIN SVK PATCH BLOCK ====
Version: svk 1.07 (linux)

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
==== END SVK PATCH BLOCK ====


List info: The rt-devel Archives

Because the parameters I am giving to new are not
supported in the non-XS module, but they are important.

I’m absolutely shocked that there isn’t a pure-perl TSV module around.
(Which was my real hesitation about taking this).

I’ve released 0.002 with your patch. Thanks for the constant quest to
improve the state of the RT-World.

Jesse