home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / perl_ste.zip / Data / Flow.pm < prev   
Text File  |  1997-08-20  |  7KB  |  242 lines

  1. package Data::Flow;
  2.  
  3. use strict;
  4. use vars qw($VERSION @ISA @EXPORT);
  5.  
  6. require Exporter;
  7. require AutoLoader;
  8.  
  9. @ISA = qw(Exporter AutoLoader);
  10. # Items to export into callers namespace by default. Note: do not export
  11. # names by default without a very good reason. Use EXPORT_OK instead.
  12. # Do not simply export all your public functions/methods/constants.
  13. @EXPORT = qw(
  14. );
  15. $VERSION = '0.05';
  16.  
  17.  
  18. # Preloaded methods go here.
  19.  
  20. sub new {
  21.   die "Usage: new Data::Flow \$recipes" unless @_ == 2;
  22.   my $class = shift;
  23.   my $recipes = shift;
  24.   $recipes = bless [$recipes, {}], $class;
  25.   # $recipes->set(@_);
  26.   $recipes;
  27. }
  28.  
  29. sub set {
  30.   my $self = shift;
  31.   die "Odd number of data given to Data::Flow::set" if @_ % 2;
  32.   my %data = @_;
  33.   @{$self->[1]}{keys %data} = values %data;
  34. }
  35.  
  36. sub get {
  37.   my $self = shift;
  38.   my $request = shift;
  39.   $self->request($request);
  40.   $self->[1]->{$request};
  41. }
  42.  
  43. sub request {
  44.   my $self = shift;
  45.   my ($recipes, $data) = @$self;
  46.   my ($recipe, $request);
  47.   for $request (@_) {
  48.     # Bail out if present
  49.     next if exists $data->{$request};
  50.     $recipe = $recipes->{$request};
  51.     # Get prerequisites
  52.     $self->request(@{$recipe->{prerequisites}})
  53.       if exists $recipe->{prerequisites};
  54.     # Check for default value
  55.     if (exists $recipe->{default}) {
  56.       $data->{$request} = $recipe->{default};
  57.       next;
  58.     } elsif (exists $recipe->{process}) { # Let it do the work itself.
  59.       &{$recipe->{process}}($data, $request);
  60.       die "The recipe for processing the request `$request' did not acquire it" 
  61.     unless exists $data->{$request};
  62.     } elsif (exists $recipe->{output}) { # Keep return value.
  63.       $data->{$request} = &{$recipe->{output}}($data, $request);
  64.     } elsif (exists $recipe->{filter}) { # Input comes from $data
  65.       my @arr = @{ $recipe->{filter} };
  66.       my $sub = shift @arr;
  67.       foreach (@arr) { $self->request($_) }
  68.       @arr = map $data->{$_}, @arr;
  69.       $data->{$request} = &$sub( @arr );
  70.     } elsif (exists $recipe->{method_filter}) { # Input comes from $data
  71.       my @arr = @{ $recipe->{method_filter} };
  72.       my $method = shift @arr;
  73.       foreach (@arr) { $self->request($_) }
  74.       @arr = map $data->{$_}, @arr;
  75.       my $obj = shift @arr;
  76.       $data->{$request} = $obj->$method( @arr );
  77.     } elsif (exists $recipe->{class_filter}) { # Input comes from $data
  78.       my @arr = @{ $recipe->{class_filter} };
  79.       my $method = shift @arr;
  80.       my $class = shift @arr;
  81.       foreach (@arr) { $self->request($_) }
  82.       @arr = map $data->{$_}, @arr;
  83.       $data->{$request} = $class->$method( @arr );
  84.     } else {
  85.       die "Do not know how to satisfy the request `$request'";
  86.     }
  87.   }
  88. }
  89.  
  90. *TIEHASH  = \&new;
  91. *STORE      = \&set;
  92. *FETCH      = \&get;
  93.  
  94. # Autoload methods go after =cut, and are processed by the autosplit program.
  95.  
  96. 1;
  97. __END__
  98.  
  99. =head1 NAME
  100.  
  101. Data::Flow - Perl extension for simple-minded recipe-controlled build of data.
  102.  
  103. =head1 SYNOPSIS
  104.  
  105.   use Data::Flow;
  106.   $recipes = { path  => { default => './MANIFEST'},
  107.            contents => { prerequisites => ['path', 'x'] ,
  108.                  process => 
  109.                  sub {
  110.                    my $data = shift; 
  111.                    $data->{ shift() } = `cat $data->get('path')`
  112.                  x $data->get('x');
  113.                  }
  114.                },
  115.          };
  116.  
  117.   $request = new Data::Flow $recipes;
  118.   $request->set( x => 1);
  119.   print $request->get('contents');
  120.  
  121.   tie %request, Data::Flow, $recipes;
  122.   $request{x} = 1;
  123.   print $request{contents};
  124.  
  125.  
  126. =head1 DESCRIPTION
  127.  
  128. The module Data::Flow provides its services via objects. The objects may
  129. be obtained by the usual
  130.  
  131.   $request = new Data::Flow $recipes;
  132.  
  133. paradigm. The argument $recipes is a hash reference, which provides
  134. the rules for request processing. The objects support two methods,
  135. set() and get(). The first one is used to provide input data for
  136. processing, the second one to obtain the output.
  137.  
  138. The unit of requested information is a I<field>. The method set()
  139. takes a pair C<field =E<gt> value>, the method get() takes one
  140. argument: the C<field>.
  141.  
  142. Every object is created without any fields filled, but it knows how to
  143. I<construct> fields basing on other fields or some global into. This
  144. knowledge is provided in the argument $recipe of the new()
  145. function. This is a reference to a hash, keyed by I<fields>. The
  146. values of this hash are hash references themselves, which describe how
  147. to acquire the I<field> which is the corresponding key of the initial
  148. hash.
  149.  
  150. The internal hashes may have the following keys:
  151.  
  152. =over 8
  153.  
  154. =item C<default>
  155.  
  156. describes the default value for the key, if none is provided by
  157. set(). The value becomes the value of the field of the object. No
  158. additional processing is performed. Example:
  159.  
  160.   default => $Config{installdir}
  161.  
  162. =item C<prerequisites>
  163.  
  164. gives the fields which are needed for the construction of the given
  165. field. The corresponding value is an array references. The array
  166. contains the I<required> fields.
  167.  
  168. If C<defaults> did not satisfy the request for a field, but
  169. C<$recipe-E<gt>{field}{prerequisites}> exists, the I<required>
  170. fields are build before any further processing is done. Example:
  171.  
  172.   prerequisites => [ qw(prefix arch) ]
  173.  
  174. =item C<process>
  175.  
  176. contains the rule to build the field. The value is a reference to a
  177. subroutine taking 2 arguments: the object $request, and the name of
  178. the required field. It is up to the subroutine to actually fill the
  179. corresponding field of $data, an error condition is raised if it did
  180. not. Example:
  181.  
  182.   process => sub { my $data = shift;
  183.            $data->set( time => localtime(time) ) }
  184.  
  185. =item C<output>
  186.  
  187. the corresponing value has the same meaning as for C<process>, but the
  188. return value of the subroutine is used as the value of the
  189. I<field>. Example:
  190.  
  191.   output => sub { localtime(time) }
  192.  
  193.  
  194. =item C<filter>
  195.  
  196. contains the rule to build the field basing on other fields. The value
  197. is a reference to an array. The first element of the array is a
  198. reference to a subroutine, the rest contains names of the fields. When
  199. the subroutine is called, the arguments are the values of I<fields> of
  200. the object $request which appear in the array (in the same order). The
  201. return value of the subroutine is used as the value of the
  202. I<field>. Example:
  203.  
  204.   filter => [ sub { shift + shift }, 
  205.           'first_half', 'second_half' ]
  206.  
  207. Note that the mentioned field will be automatically marked as
  208. prerequisites.
  209.  
  210. =item C<class_filter>
  211.  
  212. is similar to C<filter>, but the first argument is the name of the
  213. method to call, second one is the name of the package to use for the
  214. method invocation. The rest contains names of field to provide as
  215. method arguments. Example:
  216.  
  217.   class_filter => [ 'new', 'FileHandle', 'filename' ]
  218.  
  219. =item C<method_filter>
  220.  
  221. is similar to C<class_filter>, but the second argument is the name of the
  222. field which is used to call the method upon. Example:
  223.  
  224.   method_filter => [ 'show', 'widget_name', 'current_display' ]
  225.  
  226. =back
  227.  
  228. =head2 Tied interface
  229.  
  230. The access to the same functionality is available via tied hash
  231. interface.
  232.  
  233. =head1 AUTHOR
  234.  
  235. Ilya Zakharevich, ilya@math.ohio-state.edu
  236.  
  237. =head1 SEE ALSO
  238.  
  239. perl(1), make(1).
  240.  
  241. =cut
  242.