Open the lid like a pen in Perl

So, I had this crazy idea. Right now, I am creating a table in Word using Text :: CSV_XS, for example:

use Win32::OLE;
use Win32::OLE::Const 'Microsoft Word';
use Text::CSV_XS;

# instantiation of word and Text::CSV_XS omitted for clarity
my $select = $word->Selection;
foreach my $row (@rows) { # @rows is an array of arrayrefs
    $csv->combine(@{$row});
    $select->InsertAfter($csv->string);
    $select->InsertParagraphAfter;
}
$select->convertToTable(({'Separator' => wdSeparateByCommas});

      

But it would be cooler if I could do something like this:

use Win32::OLE;
use Win32::OLE::Const 'Microsoft Word';
use Text::CSV_XS;

# instantiation of word and Text::CSV_XS omitted for clarity
my $select = $word->Selection;
foreach my $row (@rows) { # @rows is an array of arrayrefs
    $csv->bind_columns($row);
    $csv->print( 
        sub {
            my $something; # Should be the combine()'d string
            $select->InsertAfter($something);
            $select->InsertParagraphAfter;
        },
        undef
    ); 
}
$select->convertToTable(({'Separator' => wdSeparateByCommas});

      

So my questions are, how do I get $something

from my second code example, and what do I need to do to make the closure look like a handle?

+3


source to share


2 answers


Text::CSV::print

a descriptor is not required. The documentation just says it needs something with a method print

.

{
    package Print::After::Selection;
    sub new {
        my ($pkg, $selection) = @_;
        my $self = { selection => $selection };
        return bless $self, $pkg;
    }
    sub print {
        my ($self, $string) = @_;
        my $selection = $self->{selection};
        $selection->InsertAfter($string);
        $selection->InsertParagraphAfter;
        return 1;  # return true or Text::CSV will think print failed
    }
}

...
$csv->print( Print::After::Selection->new( $word->Selection ), undef );
...

      



(not verified)

+2


source


I believe you are really asking how to render data in Word with the following interface:

my $fh = SelectionHandle->new($selection);
my $csv = Text::CSV_XS->new({ binary => 1 });
$csv->print($fh, $_) for @rows;

      

(I think this is a bad idea, internally. Create an object that formats using an encapsulated CSV object.)

If you want to give an object a variable interface (scalar, array, hash, file descriptor) you want tie

. When you do, you will receive



use SelectionHandle qw( );
use Text::CSV_XS    qw( );

my $selection = ...;
my @rows      = ...;

my $fh = SelectionHandle->new($selection);
my $csv = Text::CSV_XS->new({ binary => 1 });
$csv->print($fh, $_) for @rows;

      

And the module looks like this:

package SelectionHandle;

use strict;
use warnings;

use Symbol      qw( gensym );
use Tie::Handle qw( );

our @ISA = qw( Tie::Handle );

sub new {
   my ($class, $selection) = @_;
   my $fh = gensym();
   tie(*$fh, $class, $selection);
   return $fh;
}

sub TIEHANDLE {
   my ($class, $selection) = @_;
   return bless({
      selection => $selection,
   }, $class);
}

sub PRINT {
   my ($self, $str) = @_;
   my $selection = $self->{selection};
   $selection->InsertAfter($str);
   $selection->InsertParagraphAfter();
   return 1;
}

1;

      

+2


source







All Articles