Acme-RunDoc

 view release on metacpan or  search on metacpan

lib/Acme/RunDoc.pm  view on Meta::CPAN

package Acme::RunDoc;

use strict;
use autodie;

BEGIN {
	$Acme::RunDoc::AUTHORITY = 'cpan:TOBYINK';
	$Acme::RunDoc::VERSION   = '0.002';
}

# 'undef' is Text::Extract::Word's default filter, and probably the only
# one that makes sense.
use constant FILTER => undef;

use Carp qw//;
use Data::Dumper qw//;
use File::Spec;
use IO::File;
use Text::Extract::Word;
use Module::Runtime qw//;

sub do
{
	my ($class, $file) = _args(@_);
	my $text = Text::Extract::Word->new($file)->get_body(FILTER)
		or CORE::do { $! = 'cannot read file'; return undef };
	return CORE::eval($text);
}

sub require_file
{
	my ($class, $file) = _args(@_);
	my $fh = IO::File->new($file, 'r')
		or Carp::croak("Could not require file $file: $!");
	$class->do($fh) or Carp::croak("Could not require file $file: $@");
}

sub require
{
	my ($class, $module) = _args(@_);
	(my $filename = Module::Runtime::module_notional_filename($module))
		=~ s{ \.pm $ }{ '.docm' }ex;
	my ($file) = 
		grep { -e $_ }
		map { File::Spec->catfile($_, $filename) }
		@INC;
	Carp::croak("Could not find $filename in \@INC: ".join q{ }, @INC)
		unless defined $file;
	$class->require_file($file);
}

sub use
{
	my ($class, $module, @args) = _args(@_);
	$class->require($module);
	
	{
		my $import = $module->can('import');
		@_ = ($module, @args);
		goto $import if $import;
	}
}

sub import
{
	my ($class, @args) = _args(@_);
	my $caller = scalar caller;
	local $Data::Dumper::Indent = 0;
	while (@args)
	{
		my $module = shift @args;
		my $args   = ref $args[0] ? shift @args : undef;
		my $eval = sprintf(
			"{ package %s; my \@args = %s; Acme::RunDoc->use('%s', \@args); }",
			$caller,
			ref $args eq 'HASH'
				? sprintf('do { my %s; %%$VAR1 }', Data::Dumper::Dumper($args))
				: ref $args
				? sprintf('do { my %s; @$VAR1 }',  Data::Dumper::Dumper($args))
				: '()',
			$module,
			);
		eval "$eval; 1" or Carp::croak($@);
	}
}

sub _args
{
	my (@args) = @_;
	return @args if $args[0] eq __PACKAGE__;
	return @args if UNIVERSAL::can($args[0] => 'isa')
	             && $args[0]->isa(__PACKAGE__);
	unshift @args, __PACKAGE__;
	return @args;
}

__FILE__
__END__

=head1 NAME

Acme::RunDoc - executes a Microsoft Word document as if it were Perl code

=head1 SYNOPSIS

 Acme::RunDoc->do("helloworld.doc"); 

=head1 DESCRIPTION

It is recieved wisdom that word processors are better than text editors.
After all, you can style your documents with different fonts and colours;
you can take advantage of the built-in spell check; and your ugly single
and double quote characters get auto-replaced with "smart" curly versions.

This module allows you to run Perl documents edited in Microsoft Word
(and other word processors capable of saving in the ".doc" format) as
normal Perl code. You can write scripts and run them like this:

  perl -Microsoft::Word helloworld.doc

or call them from other files using:

  Acme::RunDoc->do("helloworld.doc");

You can write Perl modules using Microsoft Word too. (Just take care to
rename ".doc" to ".docm".) To "require" them:

  Acme::RunDoc->require_file("Hello/World.docm");
  Acme::RunDoc->require("Hello::World");

Acme::RunDoc searches C<< @INC >> just like you'd expect.

You can even "use" modules written in Microsoft Word:

  BEGIN {
    require Acme::RunDoc;
    Acme::RunDoc->use("Hello::World", "greet");
  }

 view all matches for this distribution
 view release on metacpan -  search on metacpan

( run in 0.609 second using v1.00-cache-2.02-grep-82fe00e-cpan-2c419f77a38b )